/*! 
  Ripple Mobile Environment Emulator v0.9.8 :: Built On Fri Dec 14 2012 17:24:10 GMT+0800 (CST)

                                Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

-------------------------------------------------------
Copyright 2011 Research In Motion Limited.

Contributors:
        Brent Lintner (blintner@rim.com)
        Dan Silivestru (dsilivestru@rim.com)
        Gord Tanner (gtanner@rim.com)
        Nino D'Aversa (ndaversa@rim.com)
        Nukul Bhasin (nbhasin@rim.com)

-------------------------------------------------------
--> Kudos to third party awesomeness:

* browser-require *

https://github.com/rsms/browser-require

The MIT License
http://www.opensource.org/licenses/mit-license.php
Copyright (c) 2010 Rasmus Andersson http://hunch.se/

-------------------------------------------------------
* jWorkflow *

http://github.com/tinyhippos/jWorkflow/

The MIT License
http://www.opensource.org/licenses/mit-license.php
Copyright (c) 2010 all contributors:
Gord Tanner

-------------------------------------------------------
* jXHR.js (JSON-P XHR) *
 v0.1 (c) Kyle Simpson 
 MIT License

-------------------------------------------------------
* UI.Acceleromter Control (panel plugin) *

Licensed under the MIT license:
  Copyright Train Hack 2010
  Contributors: Wolfram Kriesing, Dan Silivestru, Brent Lintner
  http://www.opensource.org/licenses/mit-license.php

-------------------------------------------------------
* jQuery JavaScript Library *

http://jquery.com/

Copyright 2010, John Resig
Licensed under MIT
http://jquery.org/license

Includes Sizzle.js
http://sizzlejs.com/
Copyright 2010, The Dojo Foundation
Released under the MIT, BSD, and GPL Licenses.

-------------------------------------------------------
* jQuery UI *

Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
licensed under the MIT (MIT-LICENSE.txt)

http://docs.jquery.com/UI

-------------------------------------------------------
* jQuery Tooltip plugin *

http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/
http://docs.jquery.com/Plugins/Tooltip

Copyright (c) 2006 - 2008 Jörn Zaefferer

Dual licensed under the MIT and GPL licenses:
  http://www.opensource.org/licenses/mit-license.php
  http://www.gnu.org/licenses/gpl.html

-------------------------------------------------------
* Math.uuid.js (v1.4) *

http://www.broofa.com
mailto:robert@broofa.com

Copyright (c) 2010 Robert Kieffer
Dual licensed under the MIT and GPL licenses.

-------------------------------------------------------
* Wii Opera SDK - 3D Math Class v2.7.22 2008-12-14 *
(c) 2007-2008 Daniel Gump. All Rights Reserved.                          
 http://wiioperasdk.com, http://hullbreachonline.com                      
 hullbreach@hullbreachonline.com                                          
                                                                          
* Wii Opera SDK - Drawing Class v2.6.16 2008-12-14 * 
(c) 2007-2008 Daniel Gump. All Rights Reserved
http://wiioperasdk.com, http://hullbreachonline.com
hullbreach@hullbreachonline.com

  Wii is a trademark of Nintendo Co., Ltd.                                
  Opera is a trademark of Opera, ASA.                                     
  This software package is not associated with either company             
  but was created to support users of both.  Its alternative name         
  when supporting other products is the HULLBREACH SDK.                   
                                                                          
  Redistribution and use in source and binary forms, with or without      
  modification, are permitted provided that the following conditions      
  are met:                                                                
    * Redistributions of source code must retain the above copyright      
      notice, this list of conditions and the following disclaimer.       
    * Redistributions in binary form must reproduce the above copyright   
      notice, this list of conditions and the following disclaimer in     
      the documentation and/or other materials provided with the          
      distribution.                                                       
    * Neither the names HULLBREACH ONLINE nor WII OPERA SDK nor the names 
      of its contributors may be used to endorse or promote products      
      derived from this software without specific prior written           
      permission.                                                         
    * If the explicit purpose of the software is not to support the       
      Nintendo Wii or the Opera Web browser, then the names of such must  
      not be used in any derived product. The name shall be the           
      HULLBREACH SDK with a reference link to http://hullbreachonline.    
                                                                          
  THIS SOFTWARE IS PROVIDED BY Daniel Gump ''AS IS'' AND ANY EXPRESS OR   
  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED          
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
  DISCLAIMED. IN NO EVENT SHALL Daniel Gump BE LIABLE FOR ANY DIRECT,     
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES      
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR      
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,     
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING   
  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      
  POSSIBILITY OF SUCH DAMAGE.                                             

-------------------------------------------------------
  OpenLayers.js -- OpenLayers Map Viewer Library

  Copyright 2005-2010 OpenLayers Contributors, released under the Clear BSD
  license. Full license text below taken from http://svn.openlayers.org/trunk/openlayers/license.txt

        Copyright 2005-2011 OpenLayers Contributors. All rights reserved. See
        authors.txt for full list.
         
        Redistribution and use in source and binary forms, with or without modification,
        are permitted provided that the following conditions are met:
         
        1. Redistributions of source code must retain the above copyright notice, this
        list of conditions and the following disclaimer.
         
        2. Redistributions in binary form must reproduce the above copyright notice,
        this list of conditions and the following disclaimer in the documentation and/or
        other materials provided with the distribution.
         
        THIS SOFTWARE IS PROVIDED BY OPENLAYERS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
        OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
        MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
        SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
        LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
        OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
        ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         
        The views and conclusions contained in the software and documentation are those
        of the authors and should not be interpreted as representing official policies,
        either expressed or implied, of OpenLayers Contributors.

  Includes compressed code under the following licenses:

  (For uncompressed versions of the code used please see the
  OpenLayers SVN repository: <http://openlayers.org/>)

-------------------------------------------------------
  Contains portions of Rico <http://openrico.org/>
 
  Copyright 2005 Sabre Airline Solutions  
  
  Licensed under the Apache License, Version 2.0 (the "License"); you
  may not use this file except in compliance with the License. You
  may obtain a copy of the License at the top of this file or a the following
  link:
  
         http://www.apache.org/licenses/LICENSE-2.0  
  
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  implied. See the License for the specific language governing
  permissions and limitations under the License. 

-------------------------------------------------------
  Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
  Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
 
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0

-------------------------------------------------------
  Contains portions of Gears <http://code.google.com/apis/gears/>

  Copyright 2007, Google Inc.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. Neither the name of Google Inc. nor the names of its contributors may be
      used to endorse or promote products derived from this software without
      specific prior written permission.
 
  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  Sets up google.gears.*, which is *the only* supported way to access Gears.

  Circumvent this file at your own risk!
 
  In the future, Gears may automatically define google.gears.* without this
  file. Gears may use these objects to transparently fix bugs and compatibility
  issues. Applications that use the code below will continue to work seamlessly
  when that happens.
*/
window.require = null;window.define = null;/**
 * almond 0.0.3 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
 * Available via the MIT or new BSD license.
 * see: http://github.com/jrburke/almond for details
 */
/*jslint strict: false, plusplus: false */
/*global setTimeout: false */

var requirejs, require, define;
(function (undef) {

    var defined = {},
        waiting = {},
        aps = [].slice,
        main, req;

    if (typeof define === "function") {
        //If a define is already in play via another AMD loader,
        //do not overwrite.
        return;
    }

    /**
     * Given a relative module name, like ./something, normalize it to
     * a real name that can be mapped to a path.
     * @param {String} name the relative name
     * @param {String} baseName a real name that the name arg is relative
     * to.
     * @returns {String} normalized name
     */
    function normalize(name, baseName) {
        //Adjust any relative paths.
        if (name && name.charAt(0) === ".") {
            //If have a base name, try to normalize against it,
            //otherwise, assume it is a top-level require that will
            //be relative to baseUrl in the end.
            if (baseName) {
                //Convert baseName to array, and lop off the last part,
                //so that . matches that "directory" and not name of the baseName's
                //module. For instance, baseName of "one/two/three", maps to
                //"one/two/three.js", but we want the directory, "one/two" for
                //this normalization.
                baseName = baseName.split("/");
                baseName = baseName.slice(0, baseName.length - 1);

                name = baseName.concat(name.split("/"));

                //start trimDots
                var i, part;
                for (i = 0; (part = name[i]); i++) {
                    if (part === ".") {
                        name.splice(i, 1);
                        i -= 1;
                    } else if (part === "..") {
                        if (i === 1 && (name[2] === '..' || name[0] === '..')) {
                            //End of the line. Keep at least one non-dot
                            //path segment at the front so it can be mapped
                            //correctly to disk. Otherwise, there is likely
                            //no path mapping for a path starting with '..'.
                            //This can still fail, but catches the most reasonable
                            //uses of ..
                            break;
                        } else if (i > 0) {
                            name.splice(i - 1, 2);
                            i -= 2;
                        }
                    }
                }
                //end trimDots

                name = name.join("/");
            }
        }
        return name;
    }

    function makeRequire(relName, forceSync) {
        return function () {
            //A version of a require function that passes a moduleName
            //value for items that may need to
            //look up paths relative to the moduleName
            return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
        };
    }

    function makeNormalize(relName) {
        return function (name) {
            return normalize(name, relName);
        };
    }

    function makeLoad(depName) {
        return function (value) {
            defined[depName] = value;
        };
    }

    function callDep(name) {
        if (waiting.hasOwnProperty(name)) {
            var args = waiting[name];
            delete waiting[name];
            main.apply(undef, args);
        }
        return defined[name];
    }

    /**
     * Makes a name map, normalizing the name, and using a plugin
     * for normalization if necessary. Grabs a ref to plugin
     * too, as an optimization.
     */
    function makeMap(name, relName) {
        var prefix, plugin,
            index = name.indexOf('!');

        if (index !== -1) {
            prefix = normalize(name.slice(0, index), relName);
            name = name.slice(index + 1);
            plugin = callDep(prefix);

            //Normalize according
            if (plugin && plugin.normalize) {
                name = plugin.normalize(name, makeNormalize(relName));
            } else {
                name = normalize(name, relName);
            }
        } else {
            name = normalize(name, relName);
        }

        //Using ridiculous property names for space reasons
        return {
            f: prefix ? prefix + '!' + name : name, //fullName
            n: name,
            p: plugin
        };
    }

    main = function (name, deps, callback, relName) {
        var args = [],
            usingExports,
            cjsModule, depName, i, ret, map;

        //Use name if no relName
        if (!relName) {
            relName = name;
        }

        //Call the callback to define the module, if necessary.
        if (typeof callback === 'function') {

            //Default to require, exports, module if no deps if
            //the factory arg has any arguments specified.
            if (!deps.length && callback.length) {
                deps = ['require', 'exports', 'module'];
            }

            //Pull out the defined dependencies and pass the ordered
            //values to the callback.
            for (i = 0; i < deps.length; i++) {
                map = makeMap(deps[i], relName);
                depName = map.f;

                //Fast path CommonJS standard dependencies.
                if (depName === "require") {
                    args[i] = makeRequire(name);
                } else if (depName === "exports") {
                    //CommonJS module spec 1.1
                    args[i] = defined[name] = {};
                    usingExports = true;
                } else if (depName === "module") {
                    //CommonJS module spec 1.1
                    cjsModule = args[i] = {
                        id: name,
                        uri: '',
                        exports: defined[name]
                    };
                } else if (defined.hasOwnProperty(depName) || waiting.hasOwnProperty(depName)) {
                    args[i] = callDep(depName);
                } else if (map.p) {
                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
                    args[i] = defined[depName];
                } else {
                    throw name + ' missing ' + depName;
                }
            }

            ret = callback.apply(defined[name], args);

            if (name) {
                //If setting exports via "module" is in play,
                //favor that over return value and exports. After that,
                //favor a non-undefined return value over exports use.
                if (cjsModule && cjsModule.exports !== undef) {
                    defined[name] = cjsModule.exports;
                } else if (!usingExports) {
                    //Use the return value from the function.
                    defined[name] = ret;
                }
            }
        } else if (name) {
            //May just be an object definition for the module. Only
            //worry about defining if have a module name.
            defined[name] = callback;
        }
    };

    requirejs = req = function (deps, callback, relName, forceSync) {
        if (typeof deps === "string") {

            //Just return the module wanted. In this scenario, the
            //deps arg is the module name, and second arg (if passed)
            //is just the relName.
            //Normalize module name, if it contains . or ..
            return callDep(makeMap(deps, callback).f);
        } else if (!deps.splice) {
            //deps is a config object, not an array.
            //Drop the config stuff on the ground.
            if (callback.splice) {
                //callback is an array, which means it is a dependency list.
                //Adjust args if there are dependencies
                deps = callback;
                callback = arguments[2];
            } else {
                deps = [];
            }
        }

        //Simulate async callback;
        if (forceSync) {
            main(undef, deps, callback, relName);
        } else {
            setTimeout(function () {
                main(undef, deps, callback, relName);
            }, 15);
        }

        return req;
    };

    /**
     * Just drops the config on the floor, but returns req in case
     * the config return value is used.
     */
    req.config = function () {
        return req;
    };

    /**
     * Export require as a global, but only if it does not already exist.
     */
    if (!require) {
        require = req;
    }

    define = function (name, deps, callback) {

        //This module may not have dependencies
        if (!deps.splice) {
            //deps is not an array, so probably means
            //an object literal or factory function for
            //the value. Adjust args.
            callback = deps;
            deps = [];
        }

        if (define.unordered) {
            waiting[name] = [name, deps, callback];
        } else {
            main(name, deps, callback);
        }
    };

    define.amd = {
        jQuery: true
    };
}());
/*!
 * jQuery JavaScript Library v1.6
 * http://jquery.com/
 *
 * Copyright 2011, John Resig
 * licensed under the MIT 
 * http://jquery.org/license
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 * Copyright 2011, The Dojo Foundation
 * Released under the MIT, BSD, and GPL Licenses.
 *
 * Date: Mon May 2 13:50:00 2011 -0400
 */
(function( window, undefined ) {

// Use the correct document accordingly with window argument (sandbox)
var document = window.document,
	navigator = window.navigator,
	location = window.location;
var jQuery = (function() {

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
		// The jQuery object is actually just the init constructor 'enhanced'
		return new jQuery.fn.init( selector, context, rootjQuery );
	},

	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$,

	// A central reference to the root jQuery(document)
	rootjQuery,

	// A simple way to check for HTML strings or ID strings
	// (both of which we optimize for)
	quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,

	// Check if a string has a non-whitespace character in it
	rnotwhite = /\S/,

	// Used for trimming whitespace
	trimLeft = /^\s+/,
	trimRight = /\s+$/,

	// Check for digits
	rdigit = /\d/,

	// Match a standalone tag
	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,

	// JSON RegExp
	rvalidchars = /^[\],:{}\s]*$/,
	rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
	rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,

	// Useragent RegExp
	rwebkit = /(webkit)[ \/]([\w.]+)/,
	ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
	rmsie = /(msie) ([\w.]+)/,
	rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,

	// Keep a UserAgent string for use with jQuery.browser
	userAgent = navigator.userAgent,

	// For matching the engine and version of the browser
	browserMatch,

	// The deferred used on DOM ready
	readyList,

	// The ready event handler
	DOMContentLoaded,

	// Save a reference to some core methods
	toString = Object.prototype.toString,
	hasOwn = Object.prototype.hasOwnProperty,
	push = Array.prototype.push,
	slice = Array.prototype.slice,
	trim = String.prototype.trim,
	indexOf = Array.prototype.indexOf,

	// [[Class]] -> type pairs
	class2type = {};

jQuery.fn = jQuery.prototype = {
	constructor: jQuery,
	init: function( selector, context, rootjQuery ) {
		var match, elem, ret, doc;

		// Handle $(""), $(null), or $(undefined)
		if ( !selector ) {
			return this;
		}

		// Handle $(DOMElement)
		if ( selector.nodeType ) {
			this.context = this[0] = selector;
			this.length = 1;
			return this;
		}

		// The body element only exists once, optimize finding it
		if ( selector === "body" && !context && document.body ) {
			this.context = document;
			this[0] = document.body;
			this.selector = selector;
			this.length = 1;
			return this;
		}

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			// Are we dealing with HTML string or an ID?
			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
				// Assume that strings that start and end with <> are HTML and skip the regex check
				match = [ null, selector, null ];

			} else {
				match = quickExpr.exec( selector );
			}

			// Verify a match, and that no context was specified for #id
			if ( match && (match[1] || !context) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[1] ) {
					context = context instanceof jQuery ? context[0] : context;
					doc = (context ? context.ownerDocument || context : document);

					// If a single string is passed in and it's a single tag
					// just do a createElement and skip the rest
					ret = rsingleTag.exec( selector );

					if ( ret ) {
						if ( jQuery.isPlainObject( context ) ) {
							selector = [ document.createElement( ret[1] ) ];
							jQuery.fn.attr.call( selector, context, true );

						} else {
							selector = [ doc.createElement( ret[1] ) ];
						}

					} else {
						ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
						selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
					}

					return jQuery.merge( this, selector );

				// HANDLE: $("#id")
				} else {
					elem = document.getElementById( match[2] );

					// Check parentNode to catch when Blackberry 4.6 returns
					// nodes that are no longer in the document #6963
					if ( elem && elem.parentNode ) {
						// Handle the case where IE and Opera return items
						// by name instead of ID
						if ( elem.id !== match[2] ) {
							return rootjQuery.find( selector );
						}

						// Otherwise, we inject the element directly into the jQuery object
						this.length = 1;
						this[0] = elem;
					}

					this.context = document;
					this.selector = selector;
					return this;
				}

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
				return (context || rootjQuery).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return this.constructor( context ).find( selector );
			}

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) ) {
			return rootjQuery.ready( selector );
		}

		if (selector.selector !== undefined) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

		return jQuery.makeArray( selector, this );
	},

	// Start with an empty selector
	selector: "",

	// The current version of jQuery being used
	jquery: "1.6",

	// The default length of a jQuery object is 0
	length: 0,

	// The number of elements contained in the matched element set
	size: function() {
		return this.length;
	},

	toArray: function() {
		return slice.call( this, 0 );
	},

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {
		return num == null ?

			// Return a 'clean' array
			this.toArray() :

			// Return just the object
			( num < 0 ? this[ this.length + num ] : this[ num ] );
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems, name, selector ) {
		// Build a new jQuery matched element set
		var ret = this.constructor();

		if ( jQuery.isArray( elems ) ) {
			push.apply( ret, elems );

		} else {
			jQuery.merge( ret, elems );
		}

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;

		ret.context = this.context;

		if ( name === "find" ) {
			ret.selector = this.selector + (this.selector ? " " : "") + selector;
		} else if ( name ) {
			ret.selector = this.selector + "." + name + "(" + selector + ")";
		}

		// Return the newly-formed element set
		return ret;
	},

	// Execute a callback for every element in the matched set.
	// (You can seed the arguments with an array of args, but this is
	// only used internally.)
	each: function( callback, args ) {
		return jQuery.each( this, callback, args );
	},

	ready: function( fn ) {
		// Attach the listeners
		jQuery.bindReady();

		// Add the callback
		readyList.done( fn );

		return this;
	},

	eq: function( i ) {
		return i === -1 ?
			this.slice( i ) :
			this.slice( i, +i + 1 );
	},

	first: function() {
		return this.eq( 0 );
	},

	last: function() {
		return this.eq( -1 );
	},

	slice: function() {
		return this.pushStack( slice.apply( this, arguments ),
			"slice", slice.call(arguments).join(",") );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map(this, function( elem, i ) {
			return callback.call( elem, i, elem );
		}));
	},

	end: function() {
		return this.prevObject || this.constructor(null);
	},

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: push,
	sort: [].sort,
	splice: [].splice
};

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

jQuery.extend = jQuery.fn.extend = function() {
	var options, name, src, copy, copyIsArray, clone,
		target = arguments[0] || {},
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
		target = {};
	}

	// extend jQuery itself if only one argument is passed
	if ( length === i ) {
		target = this;
		--i;
	}

	for ( ; i < length; i++ ) {
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null ) {
			// Extend the base object
			for ( name in options ) {
				src = target[ name ];
				copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy ) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
					if ( copyIsArray ) {
						copyIsArray = false;
						clone = src && jQuery.isArray(src) ? src : [];

					} else {
						clone = src && jQuery.isPlainObject(src) ? src : {};
					}

					// Never move original objects, clone them
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don't bring in undefined values
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

jQuery.extend({
	noConflict: function( deep ) {
		if ( window.$ === jQuery ) {
			window.$ = _$;
		}

		if ( deep && window.jQuery === jQuery ) {
			window.jQuery = _jQuery;
		}

		return jQuery;
	},

	// Is the DOM ready to be used? Set to true once it occurs.
	isReady: false,

	// A counter to track how many items to wait for before
	// the ready event fires. See #6781
	readyWait: 1,

	// Hold (or release) the ready event
	holdReady: function( hold ) {
		if ( hold ) {
			jQuery.readyWait++;
		} else {
			jQuery.ready( true );
		}
	},

	// Handle when the DOM is ready
	ready: function( wait ) {
		// Either a released hold or an DOMready/load event and not yet ready
		if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
			if ( !document.body ) {
				return setTimeout( jQuery.ready, 1 );
			}

			// Remember that the DOM is ready
			jQuery.isReady = true;

			// If a normal DOM Ready event fired, decrement, and wait if need be
			if ( wait !== true && --jQuery.readyWait > 0 ) {
				return;
			}

			// If there are functions bound, to execute
			readyList.resolveWith( document, [ jQuery ] );

			// Trigger any bound ready events
			if ( jQuery.fn.trigger ) {
				jQuery( document ).trigger( "ready" ).unbind( "ready" );
			}
		}
	},

	bindReady: function() {
		if ( readyList ) {
			return;
		}

		readyList = jQuery._Deferred();

		// Catch cases where $(document).ready() is called after the
		// browser event has already occurred.
		if ( document.readyState === "complete" ) {
			// Handle it asynchronously to allow scripts the opportunity to delay ready
			return setTimeout( jQuery.ready, 1 );
		}

		// Mozilla, Opera and webkit nightlies currently support this event
		if ( document.addEventListener ) {
			// Use the handy event callback
			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

			// A fallback to window.onload, that will always work
			window.addEventListener( "load", jQuery.ready, false );

		// If IE event model is used
		} else if ( document.attachEvent ) {
			// ensure firing before onload,
			// maybe late but safe also for iframes
			document.attachEvent( "onreadystatechange", DOMContentLoaded );

			// A fallback to window.onload, that will always work
			window.attachEvent( "onload", jQuery.ready );

			// If IE and not a frame
			// continually check to see if the document is ready
			var toplevel = false;

			try {
				toplevel = window.frameElement == null;
			} catch(e) {}

			if ( document.documentElement.doScroll && toplevel ) {
				doScrollCheck();
			}
		}
	},

	// See test/unit/core.js for details concerning isFunction.
	// Since version 1.3, DOM methods and functions like alert
	// aren't supported. They return false on IE (#2968).
	isFunction: function( obj ) {
		return jQuery.type(obj) === "function";
	},

	isArray: Array.isArray || function( obj ) {
		return jQuery.type(obj) === "array";
	},

	// A crude way of determining if an object is a window
	isWindow: function( obj ) {
		return obj && typeof obj === "object" && "setInterval" in obj;
	},

	isNaN: function( obj ) {
		return obj == null || !rdigit.test( obj ) || isNaN( obj );
	},

	type: function( obj ) {
		return obj == null ?
			String( obj ) :
			class2type[ toString.call(obj) ] || "object";
	},

	isPlainObject: function( obj ) {
		// Must be an Object.
		// Because of IE, we also have to check the presence of the constructor property.
		// Make sure that DOM nodes and window objects don't pass through, as well
		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
			return false;
		}

		// Not own constructor property must be Object
		if ( obj.constructor &&
			!hasOwn.call(obj, "constructor") &&
			!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
			return false;
		}

		// Own properties are enumerated firstly, so to speed up,
		// if last one is own, then all properties are own.

		var key;
		for ( key in obj ) {}

		return key === undefined || hasOwn.call( obj, key );
	},

	isEmptyObject: function( obj ) {
		for ( var name in obj ) {
			return false;
		}
		return true;
	},

	error: function( msg ) {
		throw msg;
	},

	parseJSON: function( data ) {
		if ( typeof data !== "string" || !data ) {
			return null;
		}

		// Make sure leading/trailing whitespace is removed (IE can't handle it)
		data = jQuery.trim( data );

		// Attempt to parse using the native JSON parser first
		if ( window.JSON && window.JSON.parse ) {
			return window.JSON.parse( data );
		}

		// Make sure the incoming data is actual JSON
		// Logic borrowed from http://json.org/json2.js
		if ( rvalidchars.test( data.replace( rvalidescape, "@" )
			.replace( rvalidtokens, "]" )
			.replace( rvalidbraces, "")) ) {

			return (new Function( "return " + data ))();

		}
		jQuery.error( "Invalid JSON: " + data );
	},

	// Cross-browser xml parsing
	// (xml & tmp used internally)
	parseXML: function( data , xml , tmp ) {

		if ( window.DOMParser ) { // Standard
			tmp = new DOMParser();
			xml = tmp.parseFromString( data , "text/xml" );
		} else { // IE
			xml = new ActiveXObject( "Microsoft.XMLDOM" );
			xml.async = "false";
			xml.loadXML( data );
		}

		tmp = xml.documentElement;

		if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
			jQuery.error( "Invalid XML: " + data );
		}

		return xml;
	},

	noop: function() {},

	// Evaluates a script in a global context
	// Workarounds based on findings by Jim Driscoll
	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
	globalEval: function( data ) {
		if ( data && rnotwhite.test( data ) ) {
			// We use execScript on Internet Explorer
			// We use an anonymous function so that context is window
			// rather than jQuery in Firefox
			( window.execScript || function( data ) {
				window[ "eval" ].call( window, data );
			} )( data );
		}
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
	},

	// args is for internal usage only
	each: function( object, callback, args ) {
		var name, i = 0,
			length = object.length,
			isObj = length === undefined || jQuery.isFunction( object );

		if ( args ) {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.apply( object[ name ], args ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.apply( object[ i++ ], args ) === false ) {
						break;
					}
				}
			}

		// A special, fast, case for the most common use of each
		} else {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
						break;
					}
				}
			}
		}

		return object;
	},

	// Use native String.trim function wherever possible
	trim: trim ?
		function( text ) {
			return text == null ?
				"" :
				trim.call( text );
		} :

		// Otherwise use our own trimming functionality
		function( text ) {
			return text == null ?
				"" :
				text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
		},

	// results is for internal usage only
	makeArray: function( array, results ) {
		var ret = results || [];

		if ( array != null ) {
			// The window, strings (and functions) also have 'length'
			// The extra typeof function check is to prevent crashes
			// in Safari 2 (See: #3039)
			// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
			var type = jQuery.type( array );

			if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
				push.call( ret, array );
			} else {
				jQuery.merge( ret, array );
			}
		}

		return ret;
	},

	inArray: function( elem, array ) {

		if ( indexOf ) {
			return indexOf.call( array, elem );
		}

		for ( var i = 0, length = array.length; i < length; i++ ) {
			if ( array[ i ] === elem ) {
				return i;
			}
		}

		return -1;
	},

	merge: function( first, second ) {
		var i = first.length,
			j = 0;

		if ( typeof second.length === "number" ) {
			for ( var l = second.length; j < l; j++ ) {
				first[ i++ ] = second[ j ];
			}

		} else {
			while ( second[j] !== undefined ) {
				first[ i++ ] = second[ j++ ];
			}
		}

		first.length = i;

		return first;
	},

	grep: function( elems, callback, inv ) {
		var ret = [], retVal;
		inv = !!inv;

		// Go through the array, only saving the items
		// that pass the validator function
		for ( var i = 0, length = elems.length; i < length; i++ ) {
			retVal = !!callback( elems[ i ], i );
			if ( inv !== retVal ) {
				ret.push( elems[ i ] );
			}
		}

		return ret;
	},

	// arg is for internal usage only
	map: function( elems, callback, arg ) {
		var value, key, ret = [],
			i = 0,
			length = elems.length,
			// jquery objects are treated as arrays
			isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;

		// Go through the array, translating each of the items to their
		if ( isArray ) {
			for ( ; i < length; i++ ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret[ ret.length ] = value;
				}
			}

		// Go through every key on the object,
		} else {
			for ( key in elems ) {
				value = callback( elems[ key ], key, arg );

				if ( value != null ) {
					ret[ ret.length ] = value;
				}
			}
		}

		// Flatten any nested arrays
		return ret.concat.apply( [], ret );
	},

	// A global GUID counter for objects
	guid: 1,

	// Bind a function to a context, optionally partially applying any
	// arguments.
	proxy: function( fn, context ) {
		if ( typeof context === "string" ) {
			var tmp = fn[ context ];
			context = fn;
			fn = tmp;
		}

		// Quick check to determine if target is callable, in the spec
		// this throws a TypeError, but we will just return undefined.
		if ( !jQuery.isFunction( fn ) ) {
			return undefined;
		}

		// Simulated bind
		var args = slice.call( arguments, 2 ),
			proxy = function() {
				return fn.apply( context, args.concat( slice.call( arguments ) ) );
			};

		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;

		return proxy;
	},

	// Mutifunctional method to get and set values to a collection
	// The value/s can be optionally by executed if its a function
	access: function( elems, key, value, exec, fn, pass ) {
		var length = elems.length;

		// Setting many attributes
		if ( typeof key === "object" ) {
			for ( var k in key ) {
				jQuery.access( elems, k, key[k], exec, fn, value );
			}
			return elems;
		}

		// Setting one attribute
		if ( value !== undefined ) {
			// Optionally, function values get executed if exec is true
			exec = !pass && exec && jQuery.isFunction(value);

			for ( var i = 0; i < length; i++ ) {
				fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
			}

			return elems;
		}

		// Getting an attribute
		return length ? fn( elems[0], key ) : undefined;
	},

	now: function() {
		return (new Date()).getTime();
	},

	// Use of jQuery.browser is frowned upon.
	// More details: http://docs.jquery.com/Utilities/jQuery.browser
	uaMatch: function( ua ) {
		ua = ua.toLowerCase();

		var match = rwebkit.exec( ua ) ||
			ropera.exec( ua ) ||
			rmsie.exec( ua ) ||
			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
			[];

		return { browser: match[1] || "", version: match[2] || "0" };
	},

	sub: function() {
		function jQuerySub( selector, context ) {
			return new jQuerySub.fn.init( selector, context );
		}
		jQuery.extend( true, jQuerySub, this );
		jQuerySub.superclass = this;
		jQuerySub.fn = jQuerySub.prototype = this();
		jQuerySub.fn.constructor = jQuerySub;
		jQuerySub.sub = this.sub;
		jQuerySub.fn.init = function init( selector, context ) {
			if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
				context = jQuerySub( context );
			}

			return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
		};
		jQuerySub.fn.init.prototype = jQuerySub.fn;
		var rootjQuerySub = jQuerySub(document);
		return jQuerySub;
	},

	browser: {}
});

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
	class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

browserMatch = jQuery.uaMatch( userAgent );
if ( browserMatch.browser ) {
	jQuery.browser[ browserMatch.browser ] = true;
	jQuery.browser.version = browserMatch.version;
}

// Deprecated, use jQuery.browser.webkit instead
if ( jQuery.browser.webkit ) {
	jQuery.browser.safari = true;
}

// IE doesn't match non-breaking spaces with \s
if ( rnotwhite.test( "\xA0" ) ) {
	trimLeft = /^[\s\xA0]+/;
	trimRight = /[\s\xA0]+$/;
}

// All jQuery objects should point back to these
rootjQuery = jQuery(document);

// Cleanup functions for the document ready method
if ( document.addEventListener ) {
	DOMContentLoaded = function() {
		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
		jQuery.ready();
	};

} else if ( document.attachEvent ) {
	DOMContentLoaded = function() {
		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
		if ( document.readyState === "complete" ) {
			document.detachEvent( "onreadystatechange", DOMContentLoaded );
			jQuery.ready();
		}
	};
}

// The DOM ready check for Internet Explorer
function doScrollCheck() {
	if ( jQuery.isReady ) {
		return;
	}

	try {
		// If IE is used, use the trick by Diego Perini
		// http://javascript.nwbox.com/IEContentLoaded/
		document.documentElement.doScroll("left");
	} catch(e) {
		setTimeout( doScrollCheck, 1 );
		return;
	}

	// and execute any waiting functions
	jQuery.ready();
}

// Expose jQuery to the global object
return jQuery;

})();


var // Promise methods
	promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
	// Static reference to slice
	sliceDeferred = [].slice;

jQuery.extend({
	// Create a simple deferred (one callbacks list)
	_Deferred: function() {
		var // callbacks list
			callbacks = [],
			// stored [ context , args ]
			fired,
			// to avoid firing when already doing so
			firing,
			// flag to know if the deferred has been cancelled
			cancelled,
			// the deferred itself
			deferred  = {

				// done( f1, f2, ...)
				done: function() {
					if ( !cancelled ) {
						var args = arguments,
							i,
							length,
							elem,
							type,
							_fired;
						if ( fired ) {
							_fired = fired;
							fired = 0;
						}
						for ( i = 0, length = args.length; i < length; i++ ) {
							elem = args[ i ];
							type = jQuery.type( elem );
							if ( type === "array" ) {
								deferred.done.apply( deferred, elem );
							} else if ( type === "function" ) {
								callbacks.push( elem );
							}
						}
						if ( _fired ) {
							deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
						}
					}
					return this;
				},

				// resolve with given context and args
				resolveWith: function( context, args ) {
					if ( !cancelled && !fired && !firing ) {
						// make sure args are available (#8421)
						args = args || [];
						firing = 1;
						try {
							while( callbacks[ 0 ] ) {
								callbacks.shift().apply( context, args );
							}
						}
						finally {
							fired = [ context, args ];
							firing = 0;
						}
					}
					return this;
				},

				// resolve with this as context and given arguments
				resolve: function() {
					deferred.resolveWith( this, arguments );
					return this;
				},

				// Has this deferred been resolved?
				isResolved: function() {
					return !!( firing || fired );
				},

				// Cancel
				cancel: function() {
					cancelled = 1;
					callbacks = [];
					return this;
				}
			};

		return deferred;
	},

	// Full fledged deferred (two callbacks list)
	Deferred: function( func ) {
		var deferred = jQuery._Deferred(),
			failDeferred = jQuery._Deferred(),
			promise;
		// Add errorDeferred methods, then and promise
		jQuery.extend( deferred, {
			then: function( doneCallbacks, failCallbacks ) {
				deferred.done( doneCallbacks ).fail( failCallbacks );
				return this;
			},
			always: function() {
				return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
			},
			fail: failDeferred.done,
			rejectWith: failDeferred.resolveWith,
			reject: failDeferred.resolve,
			isRejected: failDeferred.isResolved,
			pipe: function( fnDone, fnFail ) {
				return jQuery.Deferred(function( newDefer ) {
					jQuery.each( {
						done: [ fnDone, "resolve" ],
						fail: [ fnFail, "reject" ]
					}, function( handler, data ) {
						var fn = data[ 0 ],
							action = data[ 1 ],
							returned;
						if ( jQuery.isFunction( fn ) ) {
							deferred[ handler ](function() {
								returned = fn.apply( this, arguments );
								if ( jQuery.isFunction( returned.promise ) ) {
									returned.promise().then( newDefer.resolve, newDefer.reject );
								} else {
									newDefer[ action ]( returned );
								}
							});
						} else {
							deferred[ handler ]( newDefer[ action ] );
						}
					});
				}).promise();
			},
			// Get a promise for this deferred
			// If obj is provided, the promise aspect is added to the object
			promise: function( obj ) {
				if ( obj == null ) {
					if ( promise ) {
						return promise;
					}
					promise = obj = {};
				}
				var i = promiseMethods.length;
				while( i-- ) {
					obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
				}
				return obj;
			}
		});
		// Make sure only one callback list will be used
		deferred.done( failDeferred.cancel ).fail( deferred.cancel );
		// Unexpose cancel
		delete deferred.cancel;
		// Call given func if any
		if ( func ) {
			func.call( deferred, deferred );
		}
		return deferred;
	},

	// Deferred helper
	when: function( firstParam ) {
		var args = arguments,
			i = 0,
			length = args.length,
			count = length,
			deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
				firstParam :
				jQuery.Deferred();
		function resolveFunc( i ) {
			return function( value ) {
				args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
				if ( !( --count ) ) {
					// Strange bug in FF4:
					// Values changed onto the arguments object sometimes end up as undefined values
					// outside the $.when method. Cloning the object into a fresh array solves the issue
					deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
				}
			};
		}
		if ( length > 1 ) {
			for( ; i < length; i++ ) {
				if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
					args[ i ].promise().then( resolveFunc(i), deferred.reject );
				} else {
					--count;
				}
			}
			if ( !count ) {
				deferred.resolveWith( deferred, args );
			}
		} else if ( deferred !== firstParam ) {
			deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
		}
		return deferred.promise();
	}
});



jQuery.support = (function() {

	var div = document.createElement( "div" ),
		all,
		a,
		select,
		opt,
		input,
		marginDiv,
		support,
		fragment,
		body,
		bodyStyle,
		tds,
		events,
		eventName,
		i,
		isSupported;

	// Preliminary tests
	div.setAttribute("className", "t");
	div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

	all = div.getElementsByTagName( "*" );
	a = div.getElementsByTagName( "a" )[ 0 ];

	// Can't get basic test support
	if ( !all || !all.length || !a ) {
		return {};
	}

	// First batch of supports tests
	select = document.createElement( "select" );
	opt = select.appendChild( document.createElement("option") );
	input = div.getElementsByTagName( "input" )[ 0 ];

	support = {
		// IE strips leading whitespace when .innerHTML is used
		leadingWhitespace: ( div.firstChild.nodeType === 3 ),

		// Make sure that tbody elements aren't automatically inserted
		// IE will insert them into empty tables
		tbody: !div.getElementsByTagName( "tbody" ).length,

		// Make sure that link elements get serialized correctly by innerHTML
		// This requires a wrapper element in IE
		htmlSerialize: !!div.getElementsByTagName( "link" ).length,

		// Get the style information from getAttribute
		// (IE uses .cssText instead)
		style: /top/.test( a.getAttribute("style") ),

		// Make sure that URLs aren't manipulated
		// (IE normalizes it by default)
		hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),

		// Make sure that element opacity exists
		// (IE uses filter instead)
		// Use a regex to work around a WebKit issue. See #5145
		opacity: /^0.55$/.test( a.style.opacity ),

		// Verify style float existence
		// (IE uses styleFloat instead of cssFloat)
		cssFloat: !!a.style.cssFloat,

		// Make sure that if no value is specified for a checkbox
		// that it defaults to "on".
		// (WebKit defaults to "" instead)
		checkOn: ( input.value === "on" ),

		// Make sure that a selected-by-default option has a working selected property.
		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
		optSelected: opt.selected,

		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
		getSetAttribute: div.className !== "t",

		// Will be defined later
		submitBubbles: true,
		changeBubbles: true,
		focusinBubbles: false,
		deleteExpando: true,
		noCloneEvent: true,
		inlineBlockNeedsLayout: false,
		shrinkWrapBlocks: false,
		reliableMarginRight: true
	};

	// Make sure checked status is properly cloned
	input.checked = true;
	support.noCloneChecked = input.cloneNode( true ).checked;

	// Make sure that the options inside disabled selects aren't marked as disabled
	// (WebKit marks them as disabled)
	select.disabled = true;
	support.optDisabled = !opt.disabled;

	// Test to see if it's possible to delete an expando from an element
	// Fails in Internet Explorer
	try {
		delete div.test;
	} catch( e ) {
		support.deleteExpando = false;
	}

	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
		div.attachEvent( "onclick", function click() {
			// Cloning a node shouldn't copy over any
			// bound event handlers (IE does this)
			support.noCloneEvent = false;
			div.detachEvent( "onclick", click );
		});
		div.cloneNode( true ).fireEvent( "onclick" );
	}

	// Check if a radio maintains it's value
	// after being appended to the DOM
	input = document.createElement("input");
	input.value = "t";
	input.setAttribute("type", "radio");
	support.radioValue = input.value === "t";

	input.setAttribute("checked", "checked");
	div.appendChild( input );
	fragment = document.createDocumentFragment();
	fragment.appendChild( div.firstChild );

	// WebKit doesn't clone checked state correctly in fragments
	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;

	div.innerHTML = "";

	// Figure out if the W3C box model works as expected
	div.style.width = div.style.paddingLeft = "1px";

	// We use our own, invisible, body
	body = document.createElement( "body" );
	bodyStyle = {
		visibility: "hidden",
		width: 0,
		height: 0,
		border: 0,
		margin: 0,
		// Set background to avoid IE crashes when removing (#9028)
		background: "none"
	};
	for ( i in bodyStyle ) {
		body.style[ i ] = bodyStyle[ i ];
	}
	body.appendChild( div );
	document.documentElement.appendChild( body );

	// Check if a disconnected checkbox will retain its checked
	// value of true after appended to the DOM (IE6/7)
	support.appendChecked = input.checked;

	support.boxModel = div.offsetWidth === 2;

	if ( "zoom" in div.style ) {
		// Check if natively block-level elements act like inline-block
		// elements when setting their display to 'inline' and giving
		// them layout
		// (IE < 8 does this)
		div.style.display = "inline";
		div.style.zoom = 1;
		support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );

		// Check if elements with layout shrink-wrap their children
		// (IE 6 does this)
		div.style.display = "";
		div.innerHTML = "<div style='width:4px;'></div>";
		support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
	}

	div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
	tds = div.getElementsByTagName( "td" );

	// Check if table cells still have offsetWidth/Height when they are set
	// to display:none and there are still other visible table cells in a
	// table row; if so, offsetWidth/Height are not reliable for use when
	// determining if an element has been hidden directly using
	// display:none (it is still safe to use offsets if a parent element is
	// hidden; don safety goggles and see bug #4512 for more information).
	// (only IE 8 fails this test)
	isSupported = ( tds[ 0 ].offsetHeight === 0 );

	tds[ 0 ].style.display = "";
	tds[ 1 ].style.display = "none";

	// Check if empty table cells still have offsetWidth/Height
	// (IE < 8 fail this test)
	support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
	div.innerHTML = "";

	// Check if div with explicit width and no margin-right incorrectly
	// gets computed margin-right based on width of container. For more
	// info see bug #3333
	// Fails in WebKit before Feb 2011 nightlies
	// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
	if ( document.defaultView && document.defaultView.getComputedStyle ) {
		marginDiv = document.createElement( "div" );
		marginDiv.style.width = "0";
		marginDiv.style.marginRight = "0";
		div.appendChild( marginDiv );
		support.reliableMarginRight =
			( parseInt( document.defaultView.getComputedStyle( marginDiv, null ).marginRight, 10 ) || 0 ) === 0;
	}

	// Remove the body element we added
	body.innerHTML = "";
	document.documentElement.removeChild( body );

	// Technique from Juriy Zaytsev
	// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
	// We only care about the case where non-standard event systems
	// are used, namely in IE. Short-circuiting here helps us to
	// avoid an eval call (in setAttribute) which can cause CSP
	// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
	if ( div.attachEvent ) {
		for( i in {
			submit: 1,
			change: 1,
			focusin: 1
		} ) {
			eventName = "on" + i;
			isSupported = ( eventName in div );
			if ( !isSupported ) {
				div.setAttribute( eventName, "return;" );
				isSupported = ( typeof div[ eventName ] === "function" );
			}
			support[ i + "Bubbles" ] = isSupported;
		}
	}

	return support;
})();

// Keep track of boxModel
jQuery.boxModel = jQuery.support.boxModel;




var rbrace = /^(?:\{.*\}|\[.*\])$/,
	rmultiDash = /([a-z])([A-Z])/g;

jQuery.extend({
	cache: {},

	// Please use with caution
	uuid: 0,

	// Unique for each copy of jQuery on the page
	// Non-digits removed to match rinlinejQuery
	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),

	// The following elements throw uncatchable exceptions if you
	// attempt to add expando properties to them.
	noData: {
		"embed": true,
		// Ban all objects except for Flash (which handle expandos)
		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
		"applet": true
	},

	hasData: function( elem ) {
		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

		return !!elem && !isEmptyDataObject( elem );
	},

	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,

			// We have to handle DOM nodes and JS objects differently because IE6-7
			// can't GC object references properly across the DOM-JS boundary
			isNode = elem.nodeType,

			// Only DOM nodes need the global jQuery cache; JS object data is
			// attached directly to the object so GC can occur automatically
			cache = isNode ? jQuery.cache : elem,

			// Only defining an ID for JS objects if its cache already exists allows
			// the code to shortcut on the same path as a DOM node with no cache
			id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;

		// Avoid doing any more work than we need to when trying to get data on an
		// object that has no data at all
		if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
			return;
		}

		if ( !id ) {
			// Only DOM nodes need a new unique ID for each element since their data
			// ends up in the global cache
			if ( isNode ) {
				elem[ jQuery.expando ] = id = ++jQuery.uuid;
			} else {
				id = jQuery.expando;
			}
		}

		if ( !cache[ id ] ) {
			cache[ id ] = {};

			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}
		}

		// An object can be passed to jQuery.data instead of a key/value pair; this gets
		// shallow copied over onto the existing cache
		if ( typeof name === "object" || typeof name === "function" ) {
			if ( pvt ) {
				cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
			} else {
				cache[ id ] = jQuery.extend(cache[ id ], name);
			}
		}

		thisCache = cache[ id ];

		// Internal jQuery data is stored in a separate object inside the object's data
		// cache in order to avoid key collisions between internal data and user-defined
		// data
		if ( pvt ) {
			if ( !thisCache[ internalKey ] ) {
				thisCache[ internalKey ] = {};
			}

			thisCache = thisCache[ internalKey ];
		}

		if ( data !== undefined ) {
			thisCache[ name ] = data;
		}

		// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
		// not attempt to inspect the internal events object using jQuery.data, as this
		// internal data object is undocumented and subject to change.
		if ( name === "events" && !thisCache[name] ) {
			return thisCache[ internalKey ] && thisCache[ internalKey ].events;
		}

		return getByName ? thisCache[ name ] : thisCache;
	},

	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
		if ( !jQuery.acceptData( elem ) ) {
			return;
		}

		var internalKey = jQuery.expando, isNode = elem.nodeType,

			// See jQuery.data for more information
			cache = isNode ? jQuery.cache : elem,

			// See jQuery.data for more information
			id = isNode ? elem[ jQuery.expando ] : jQuery.expando;

		// If there is already no cache entry for this object, there is no
		// purpose in continuing
		if ( !cache[ id ] ) {
			return;
		}

		if ( name ) {
			var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];

			if ( thisCache ) {
				delete thisCache[ name ];

				// If there is no data left in the cache, we want to continue
				// and let the cache object itself get destroyed
				if ( !isEmptyDataObject(thisCache) ) {
					return;
				}
			}
		}

		// See jQuery.data for more information
		if ( pvt ) {
			delete cache[ id ][ internalKey ];

			// Don't destroy the parent cache unless the internal data object
			// had been the only thing left in it
			if ( !isEmptyDataObject(cache[ id ]) ) {
				return;
			}
		}

		var internalCache = cache[ id ][ internalKey ];

		// Browsers that fail expando deletion also refuse to delete expandos on
		// the window, but it will allow it on all other JS objects; other browsers
		// don't care
		if ( jQuery.support.deleteExpando || cache != window ) {
			delete cache[ id ];
		} else {
			cache[ id ] = null;
		}

		// We destroyed the entire user cache at once because it's faster than
		// iterating through each key, but we need to continue to persist internal
		// data if it existed
		if ( internalCache ) {
			cache[ id ] = {};
			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
			// metadata on plain JS objects when the object is serialized using
			// JSON.stringify
			if ( !isNode ) {
				cache[ id ].toJSON = jQuery.noop;
			}

			cache[ id ][ internalKey ] = internalCache;

		// Otherwise, we need to eliminate the expando on the node to avoid
		// false lookups in the cache for entries that no longer exist
		} else if ( isNode ) {
			// IE does not allow us to delete expando properties from nodes,
			// nor does it have a removeAttribute function on Document nodes;
			// we must handle all of these cases
			if ( jQuery.support.deleteExpando ) {
				delete elem[ jQuery.expando ];
			} else if ( elem.removeAttribute ) {
				elem.removeAttribute( jQuery.expando );
			} else {
				elem[ jQuery.expando ] = null;
			}
		}
	},

	// For internal use only.
	_data: function( elem, name, data ) {
		return jQuery.data( elem, name, data, true );
	},

	// A method for determining if a DOM node can handle the data expando
	acceptData: function( elem ) {
		if ( elem.nodeName ) {
			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];

			if ( match ) {
				return !(match === true || elem.getAttribute("classid") !== match);
			}
		}

		return true;
	}
});

jQuery.fn.extend({
	data: function( key, value ) {
		var data = null;

		if ( typeof key === "undefined" ) {
			if ( this.length ) {
				data = jQuery.data( this[0] );

				if ( this[0].nodeType === 1 ) {
			    var attr = this[0].attributes, name;
					for ( var i = 0, l = attr.length; i < l; i++ ) {
						name = attr[i].name;

						if ( name.indexOf( "data-" ) === 0 ) {
							name = jQuery.camelCase( name.substring(5) );

							dataAttr( this[0], name, data[ name ] );
						}
					}
				}
			}

			return data;

		} else if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );
			});
		}

		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";

		if ( value === undefined ) {
			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			// Try to fetch any internally stored data first
			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
				data = dataAttr( this[0], key, data );
			}

			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;

		} else {
			return this.each(function() {
				var $this = jQuery( this ),
					args = [ parts[0], value ];

				$this.triggerHandler( "setData" + parts[1] + "!", args );
				jQuery.data( this, key, value );
				$this.triggerHandler( "changeData" + parts[1] + "!", args );
			});
		}
	},

	removeData: function( key ) {
		return this.each(function() {
			jQuery.removeData( this, key );
		});
	}
});

function dataAttr( elem, key, data ) {
	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {
		name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();

		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = data === "true" ? true :
				data === "false" ? false :
				data === "null" ? null :
				!jQuery.isNaN( data ) ? parseFloat( data ) :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch( e ) {}

			// Make sure we set the data so it isn't changed later
			jQuery.data( elem, key, data );

		} else {
			data = undefined;
		}
	}

	return data;
}

// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
// property to be considered empty objects; this property always exists in
// order to make sure JSON.stringify does not expose internal metadata
function isEmptyDataObject( obj ) {
	for ( var name in obj ) {
		if ( name !== "toJSON" ) {
			return false;
		}
	}

	return true;
}




function handleQueueMarkDefer( elem, type, src ) {
	var deferDataKey = type + "defer",
		queueDataKey = type + "queue",
		markDataKey = type + "mark",
		defer = jQuery.data( elem, deferDataKey, undefined, true );
	if ( defer &&
		( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
		( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
		// Give room for hard-coded callbacks to fire first
		// and eventually mark/queue something else on the element
		setTimeout( function() {
			if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
				!jQuery.data( elem, markDataKey, undefined, true ) ) {
				jQuery.removeData( elem, deferDataKey, true );
				defer.resolve();
			}
		}, 0 );
	}
}

jQuery.extend({

	_mark: function( elem, type ) {
		if ( elem ) {
			type = (type || "fx") + "mark";
			jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
		}
	},

	_unmark: function( force, elem, type ) {
		if ( force !== true ) {
			type = elem;
			elem = force;
			force = false;
		}
		if ( elem ) {
			type = type || "fx";
			var key = type + "mark",
				count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
			if ( count ) {
				jQuery.data( elem, key, count, true );
			} else {
				jQuery.removeData( elem, key, true );
				handleQueueMarkDefer( elem, type, "mark" );
			}
		}
	},

	queue: function( elem, type, data ) {
		if ( elem ) {
			type = (type || "fx") + "queue";
			var q = jQuery.data( elem, type, undefined, true );
			// Speed up dequeue by getting out quickly if this is just a lookup
			if ( data ) {
				if ( !q || jQuery.isArray(data) ) {
					q = jQuery.data( elem, type, jQuery.makeArray(data), true );
				} else {
					q.push( data );
				}
			}
			return q || [];
		}
	},

	dequeue: function( elem, type ) {
		type = type || "fx";

		var queue = jQuery.queue( elem, type ),
			fn = queue.shift(),
			defer;

		// If the fx queue is dequeued, always remove the progress sentinel
		if ( fn === "inprogress" ) {
			fn = queue.shift();
		}

		if ( fn ) {
			// Add a progress sentinel to prevent the fx queue from being
			// automatically dequeued
			if ( type === "fx" ) {
				queue.unshift("inprogress");
			}

			fn.call(elem, function() {
				jQuery.dequeue(elem, type);
			});
		}

		if ( !queue.length ) {
			jQuery.removeData( elem, type + "queue", true );
			handleQueueMarkDefer( elem, type, "queue" );
		}
	}
});

jQuery.fn.extend({
	queue: function( type, data ) {
		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
		}

		if ( data === undefined ) {
			return jQuery.queue( this[0], type );
		}
		return this.each(function() {
			var queue = jQuery.queue( this, type, data );

			if ( type === "fx" && queue[0] !== "inprogress" ) {
				jQuery.dequeue( this, type );
			}
		});
	},
	dequeue: function( type ) {
		return this.each(function() {
			jQuery.dequeue( this, type );
		});
	},
	// Based off of the plugin by Clint Helfers, with permission.
	// http://blindsignals.com/index.php/2009/07/jquery-delay/
	delay: function( time, type ) {
		time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
		type = type || "fx";

		return this.queue( type, function() {
			var elem = this;
			setTimeout(function() {
				jQuery.dequeue( elem, type );
			}, time );
		});
	},
	clearQueue: function( type ) {
		return this.queue( type || "fx", [] );
	},
	// Get a promise resolved when queues of a certain type
	// are emptied (fx is the type by default)
	promise: function( type, object ) {
		if ( typeof type !== "string" ) {
			object = type;
			type = undefined;
		}
		type = type || "fx";
		var defer = jQuery.Deferred(),
			elements = this,
			i = elements.length,
			count = 1,
			deferDataKey = type + "defer",
			queueDataKey = type + "queue",
			markDataKey = type + "mark";
		function resolve() {
			if ( !( --count ) ) {
				defer.resolveWith( elements, [ elements ] );
			}
		}
		while( i-- ) {
			if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
					( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
						jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
					jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
				count++;
				tmp.done( resolve );
			}
		}
		resolve();
		return defer.promise();
	}
});




var rclass = /[\n\t\r]/g,
	rspace = /\s+/,
	rreturn = /\r/g,
	rtype = /^(?:button|input)$/i,
	rfocusable = /^(?:button|input|object|select|textarea)$/i,
	rclickable = /^a(?:rea)?$/i,
	rspecial = /^(?:data-|aria-)/,
	rinvalidChar = /\:/,
	formHook;

jQuery.fn.extend({
	attr: function( name, value ) {
		return jQuery.access( this, name, value, true, jQuery.attr );
	},

	removeAttr: function( name ) {
		return this.each(function() {
			jQuery.removeAttr( this, name );
		});
	},
	
	prop: function( name, value ) {
		return jQuery.access( this, name, value, true, jQuery.prop );
	},
	
	removeProp: function( name ) {
		return this.each(function() {
			// try/catch handles cases where IE balks (such as removing a property on window)
			try {
				this[ name ] = undefined;
				delete this[ name ];
			} catch( e ) {}
		});
	},

	addClass: function( value ) {
		if ( jQuery.isFunction( value ) ) {
			return this.each(function(i) {
				var self = jQuery(this);
				self.addClass( value.call(this, i, self.attr("class") || "") );
			});
		}

		if ( value && typeof value === "string" ) {
			var classNames = (value || "").split( rspace );

			for ( var i = 0, l = this.length; i < l; i++ ) {
				var elem = this[i];

				if ( elem.nodeType === 1 ) {
					if ( !elem.className ) {
						elem.className = value;

					} else {
						var className = " " + elem.className + " ",
							setClass = elem.className;

						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
							if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
								setClass += " " + classNames[c];
							}
						}
						elem.className = jQuery.trim( setClass );
					}
				}
			}
		}

		return this;
	},

	removeClass: function( value ) {
		if ( jQuery.isFunction(value) ) {
			return this.each(function(i) {
				var self = jQuery(this);
				self.removeClass( value.call(this, i, self.attr("class")) );
			});
		}

		if ( (value && typeof value === "string") || value === undefined ) {
			var classNames = (value || "").split( rspace );

			for ( var i = 0, l = this.length; i < l; i++ ) {
				var elem = this[i];

				if ( elem.nodeType === 1 && elem.className ) {
					if ( value ) {
						var className = (" " + elem.className + " ").replace(rclass, " ");
						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
							className = className.replace(" " + classNames[c] + " ", " ");
						}
						elem.className = jQuery.trim( className );

					} else {
						elem.className = "";
					}
				}
			}
		}

		return this;
	},

	toggleClass: function( value, stateVal ) {
		var type = typeof value,
			isBool = typeof stateVal === "boolean";

		if ( jQuery.isFunction( value ) ) {
			return this.each(function(i) {
				var self = jQuery(this);
				self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
			});
		}

		return this.each(function() {
			if ( type === "string" ) {
				// toggle individual class names
				var className,
					i = 0,
					self = jQuery( this ),
					state = stateVal,
					classNames = value.split( rspace );

				while ( (className = classNames[ i++ ]) ) {
					// check each className given, space seperated list
					state = isBool ? state : !self.hasClass( className );
					self[ state ? "addClass" : "removeClass" ]( className );
				}

			} else if ( type === "undefined" || type === "boolean" ) {
				if ( this.className ) {
					// store className if set
					jQuery._data( this, "__className__", this.className );
				}

				// toggle whole className
				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
			}
		});
	},

	hasClass: function( selector ) {
		var className = " " + selector + " ";
		for ( var i = 0, l = this.length; i < l; i++ ) {
			if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
				return true;
			}
		}

		return false;
	},

	val: function( value ) {
		var hooks, ret,
			elem = this[0];
		
		if ( !arguments.length ) {
			if ( elem ) {
				hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];

				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
					return ret;
				}

				return (elem.value || "").replace(rreturn, "");
			}

			return undefined;
		}

		var isFunction = jQuery.isFunction( value );

		return this.each(function( i ) {
			var self = jQuery(this), val;

			if ( this.nodeType !== 1 ) {
				return;
			}

			if ( isFunction ) {
				val = value.call( this, i, self.val() );
			} else {
				val = value;
			}

			// Treat null/undefined as ""; convert numbers to string
			if ( val == null ) {
				val = "";
			} else if ( typeof val === "number" ) {
				val += "";
			} else if ( jQuery.isArray( val ) ) {
				val = jQuery.map(val, function ( value ) {
					return value == null ? "" : value + "";
				});
			}

			hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];

			// If set returns undefined, fall back to normal setting
			if ( !hooks || ("set" in hooks && hooks.set( this, val, "value" ) === undefined) ) {
				this.value = val;
			}
		});
	}
});

jQuery.extend({
	valHooks: {
		option: {
			get: function( elem ) {
				// attributes.value is undefined in Blackberry 4.7 but
				// uses .value. See #6932
				var val = elem.attributes.value;
				return !val || val.specified ? elem.value : elem.text;
			}
		},
		select: {
			get: function( elem ) {
				var index = elem.selectedIndex,
					values = [],
					options = elem.options,
					one = elem.type === "select-one";

				// Nothing was selected
				if ( index < 0 ) {
					return null;
				}

				// Loop through all the selected options
				for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
					var option = options[ i ];

					// Don't return options that are disabled or in a disabled optgroup
					if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
							(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {

						// Get the specific value for the option
						value = jQuery( option ).val();

						// We don't need an array for one selects
						if ( one ) {
							return value;
						}

						// Multi-Selects return an array
						values.push( value );
					}
				}

				// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
				if ( one && !values.length && options.length ) {
					return jQuery( options[ index ] ).val();
				}

				return values;
			},

			set: function( elem, value ) {
				var values = jQuery.makeArray( value );

				jQuery(elem).find("option").each(function() {
					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
				});

				if ( !values.length ) {
					elem.selectedIndex = -1;
				}
				return values;
			}
		}
	},

	attrFn: {
		val: true,
		css: true,
		html: true,
		text: true,
		data: true,
		width: true,
		height: true,
		offset: true
	},
	
	attrFix: {
		// Always normalize to ensure hook usage
		tabindex: "tabIndex",
		readonly: "readOnly"
	},
	
	attr: function( elem, name, value, pass ) {
		var nType = elem.nodeType;
		
		// don't get/set attributes on text, comment and attribute nodes
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return undefined;
		}

		if ( pass && name in jQuery.attrFn ) {
			return jQuery( elem )[ name ]( value );
		}
		
		var ret, hooks,
			notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
		
		// Normalize the name if needed
		name = notxml && jQuery.attrFix[ name ] || name;

		// Get the appropriate hook, or the formHook
		// if getSetAttribute is not supported and we have form objects in IE6/7
		hooks = jQuery.attrHooks[ name ] ||
			( formHook && (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ?
				formHook :
				undefined );

		if ( value !== undefined ) {

			if ( value === null || (value === false && !rspecial.test( name )) ) {
				jQuery.removeAttr( elem, name );
				return undefined;

			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
				return ret;

			} else {

				// Set boolean attributes to the same name
				if ( value === true && !rspecial.test( name ) ) {
					value = name;
				}

				elem.setAttribute( name, "" + value );
				return value;
			}

		} else {

			if ( hooks && "get" in hooks && notxml ) {
				return hooks.get( elem, name );

			} else {

				ret = elem.getAttribute( name );

				// Non-existent attributes return null, we normalize to undefined
				return ret === null ?
					undefined :
					ret;
			}
		}
	},
	
	removeAttr: function( elem, name ) {
		if ( elem.nodeType === 1 ) {
			name = jQuery.attrFix[ name ] || name;
		
			if ( jQuery.support.getSetAttribute ) {
				// Use removeAttribute in browsers that support it
				elem.removeAttribute( name );
			} else {
				jQuery.attr( elem, name, "" );
				elem.removeAttributeNode( elem.getAttributeNode( name ) );
			}
		}
	},

	attrHooks: {
		type: {
			set: function( elem, value ) {
				// We can't allow the type property to be changed (since it causes problems in IE)
				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
					jQuery.error( "type property can't be changed" );
				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
					// Setting the type on a radio button after the value resets the value in IE6-9
					// Reset value to it's default in case type is set after value
					// This is for element creation
					var val = elem.getAttribute("value");
					elem.setAttribute( "type", value );
					if ( val ) {
						elem.value = val;
					}
					return value;
				}
			}
		},
		tabIndex: {
			get: function( elem ) {
				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				var attributeNode = elem.getAttributeNode("tabIndex");

				return attributeNode && attributeNode.specified ?
					parseInt( attributeNode.value, 10 ) :
					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
						0 :
						undefined;
			}
		}
	},
	
	propFix: {},
	
	prop: function( elem, name, value ) {
		var nType = elem.nodeType;
		
		// don't get/set properties on text, comment and attribute nodes
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return undefined;
		}
		
		var ret, hooks,
			notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
		
		// Try to normalize/fix the name
		name = notxml && jQuery.propFix[ name ] || name;
		
		hooks = jQuery.propHooks[ name ];
		
		if ( value !== undefined ) {
			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
				return ret;
			
			} else {
				return (elem[ name ] = value);
			}
		
		} else {
			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {
				return ret;
				
			} else {
				return elem[ name ];
			}
		}
	},
	
	propHooks: {}
});

// IE6/7 do not support getting/setting some attributes with get/setAttribute
if ( !jQuery.support.getSetAttribute ) {
	jQuery.attrFix = jQuery.extend( jQuery.attrFix, {
		"for": "htmlFor",
		"class": "className",
		maxlength: "maxLength",
		cellspacing: "cellSpacing",
		cellpadding: "cellPadding",
		rowspan: "rowSpan",
		colspan: "colSpan",
		usemap: "useMap",
		frameborder: "frameBorder"
	});
	
	// Use this for any attribute on a form in IE6/7
	formHook = jQuery.attrHooks.name = jQuery.attrHooks.value = jQuery.valHooks.button = {
		get: function( elem, name ) {
			var ret;
			if ( name === "value" && !jQuery.nodeName( elem, "button" ) ) {
				return elem.getAttribute( name );
			}
			ret = elem.getAttributeNode( name );
			// Return undefined if not specified instead of empty string
			return ret && ret.specified ?
				ret.nodeValue :
				undefined;
		},
		set: function( elem, value, name ) {
			// Check form objects in IE (multiple bugs related)
			// Only use nodeValue if the attribute node exists on the form
			var ret = elem.getAttributeNode( name );
			if ( ret ) {
				ret.nodeValue = value;
				return value;
			}
		}
	};

	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
	// This is for removals
	jQuery.each([ "width", "height" ], function( i, name ) {
		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
			set: function( elem, value ) {
				if ( value === "" ) {
					elem.setAttribute( name, "auto" );
					return value;
				}
			}
		});
	});
}


// Some attributes require a special call on IE
if ( !jQuery.support.hrefNormalized ) {
	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
			get: function( elem ) {
				var ret = elem.getAttribute( name, 2 );
				return ret === null ? undefined : ret;
			}
		});
	});
}

if ( !jQuery.support.style ) {
	jQuery.attrHooks.style = {
		get: function( elem ) {
			// Return undefined in the case of empty string
			// Normalize to lowercase since IE uppercases css property names
			return elem.style.cssText.toLowerCase() || undefined;
		},
		set: function( elem, value ) {
			return (elem.style.cssText = "" + value);
		}
	};
}

// Safari mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
if ( !jQuery.support.optSelected ) {
	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
		get: function( elem ) {
			var parent = elem.parentNode;

			if ( parent ) {
				parent.selectedIndex;

				// Make sure that it also works with optgroups, see #5701
				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
		}
	});
}

// Radios and checkboxes getter/setter
if ( !jQuery.support.checkOn ) {
	jQuery.each([ "radio", "checkbox" ], function() {
		jQuery.valHooks[ this ] = {
			get: function( elem ) {
				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
				return elem.getAttribute("value") === null ? "on" : elem.value;
			}
		};
	});
}
jQuery.each([ "radio", "checkbox" ], function() {
	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
		set: function( elem, value ) {
			if ( jQuery.isArray( value ) ) {
				return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
			}
		}
	});
});




var hasOwn = Object.prototype.hasOwnProperty,
	rnamespaces = /\.(.*)$/,
	rformElems = /^(?:textarea|input|select)$/i,
	rperiod = /\./g,
	rspaces = / /g,
	rescape = /[^\w\s.|`]/g,
	fcleanup = function( nm ) {
		return nm.replace(rescape, "\\$&");
	};

/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code originated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {

	// Bind an event to an element
	// Original by Dean Edwards
	add: function( elem, types, handler, data ) {
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		if ( handler === false ) {
			handler = returnFalse;
		} else if ( !handler ) {
			// Fixes bug #7229. Fix recommended by jdalton
			return;
		}

		var handleObjIn, handleObj;

		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
		}

		// Make sure that the function being executed has a unique ID
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Init the element's event structure
		var elemData = jQuery._data( elem );

		// If no elemData is found then we must be trying to bind to one of the
		// banned noData elements
		if ( !elemData ) {
			return;
		}

		var events = elemData.events,
			eventHandle = elemData.handle;

		if ( !events ) {
			elemData.events = events = {};
		}

		if ( !eventHandle ) {
			elemData.handle = eventHandle = function( e ) {
				// Discard the second event of a jQuery.event.trigger() and
				// when an event is called after a page has unloaded
				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
					jQuery.event.handle.apply( eventHandle.elem, arguments ) :
					undefined;
			};
		}

		// Add elem as a property of the handle function
		// This is to prevent a memory leak with non-native events in IE.
		eventHandle.elem = elem;

		// Handle multiple events separated by a space
		// jQuery(...).bind("mouseover mouseout", fn);
		types = types.split(" ");

		var type, i = 0, namespaces;

		while ( (type = types[ i++ ]) ) {
			handleObj = handleObjIn ?
				jQuery.extend({}, handleObjIn) :
				{ handler: handler, data: data };

			// Namespaced event handlers
			if ( type.indexOf(".") > -1 ) {
				namespaces = type.split(".");
				type = namespaces.shift();
				handleObj.namespace = namespaces.slice(0).sort().join(".");

			} else {
				namespaces = [];
				handleObj.namespace = "";
			}

			handleObj.type = type;
			if ( !handleObj.guid ) {
				handleObj.guid = handler.guid;
			}

			// Get the current list of functions bound to this event
			var handlers = events[ type ],
				special = jQuery.event.special[ type ] || {};

			// Init the event handler queue
			if ( !handlers ) {
				handlers = events[ type ] = [];

				// Check for a special event handler
				// Only use addEventListener/attachEvent if the special
				// events handler returns false
				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
					// Bind the global event handler to the element
					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle, false );

					} else if ( elem.attachEvent ) {
						elem.attachEvent( "on" + type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Add the function to the element's handler list
			handlers.push( handleObj );

			// Keep track of which events have been used, for event optimization
			jQuery.event.global[ type ] = true;
		}

		// Nullify elem to prevent memory leaks in IE
		elem = null;
	},

	global: {},

	// Detach an event or set of events from an element
	remove: function( elem, types, handler, pos ) {
		// don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		if ( handler === false ) {
			handler = returnFalse;
		}

		var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
			elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
			events = elemData && elemData.events;

		if ( !elemData || !events ) {
			return;
		}

		// types is actually an event object here
		if ( types && types.type ) {
			handler = types.handler;
			types = types.type;
		}

		// Unbind all events for the element
		if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
			types = types || "";

			for ( type in events ) {
				jQuery.event.remove( elem, type + types );
			}

			return;
		}

		// Handle multiple events separated by a space
		// jQuery(...).unbind("mouseover mouseout", fn);
		types = types.split(" ");

		while ( (type = types[ i++ ]) ) {
			origType = type;
			handleObj = null;
			all = type.indexOf(".") < 0;
			namespaces = [];

			if ( !all ) {
				// Namespaced event handlers
				namespaces = type.split(".");
				type = namespaces.shift();

				namespace = new RegExp("(^|\\.)" +
					jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
			}

			eventType = events[ type ];

			if ( !eventType ) {
				continue;
			}

			if ( !handler ) {
				for ( j = 0; j < eventType.length; j++ ) {
					handleObj = eventType[ j ];

					if ( all || namespace.test( handleObj.namespace ) ) {
						jQuery.event.remove( elem, origType, handleObj.handler, j );
						eventType.splice( j--, 1 );
					}
				}

				continue;
			}

			special = jQuery.event.special[ type ] || {};

			for ( j = pos || 0; j < eventType.length; j++ ) {
				handleObj = eventType[ j ];

				if ( handler.guid === handleObj.guid ) {
					// remove the given handler for the given type
					if ( all || namespace.test( handleObj.namespace ) ) {
						if ( pos == null ) {
							eventType.splice( j--, 1 );
						}

						if ( special.remove ) {
							special.remove.call( elem, handleObj );
						}
					}

					if ( pos != null ) {
						break;
					}
				}
			}

			// remove generic event handler if no more handlers exist
			if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
					jQuery.removeEvent( elem, type, elemData.handle );
				}

				ret = null;
				delete events[ type ];
			}
		}

		// Remove the expando if it's no longer used
		if ( jQuery.isEmptyObject( events ) ) {
			var handle = elemData.handle;
			if ( handle ) {
				handle.elem = null;
			}

			delete elemData.events;
			delete elemData.handle;

			if ( jQuery.isEmptyObject( elemData ) ) {
				jQuery.removeData( elem, undefined, true );
			}
		}
	},
	
	// Events that are safe to short-circuit if no handlers are attached.
	// Native DOM events should not be added, they may have inline handlers.
	customEvent: {
		"getData": true,
		"setData": true,
		"changeData": true
	},

	trigger: function( event, data, elem, onlyHandlers ) {
		// Event object or event type
		var type = event.type || event,
			namespaces = [],
			exclusive;

		if ( type.indexOf("!") >= 0 ) {
			// Exclusive events trigger only for the exact event (no namespaces)
			type = type.slice(0, -1);
			exclusive = true;
		}

		if ( type.indexOf(".") >= 0 ) {
			// Namespaced trigger; create a regexp to match event type in handle()
			namespaces = type.split(".");
			type = namespaces.shift();
			namespaces.sort();
		}

		if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
			// No jQuery handlers for this event type, and it can't have inline handlers
			return;
		}

		// Caller can pass in an Event, Object, or just an event type string
		event = typeof event === "object" ?
			// jQuery.Event object
			event[ jQuery.expando ] ? event :
			// Object literal
			new jQuery.Event( type, event ) :
			// Just the event type (string)
			new jQuery.Event( type );

		event.type = type;
		event.exclusive = exclusive;
		event.namespace = namespaces.join(".");
		event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
		
		// triggerHandler() and global events don't bubble or run the default action
		if ( onlyHandlers || !elem ) {
			event.preventDefault();
			event.stopPropagation();
		}

		// Handle a global trigger
		if ( !elem ) {
			// TODO: Stop taunting the data cache; remove global events and always attach to document
			jQuery.each( jQuery.cache, function() {
				// internalKey variable is just used to make it easier to find
				// and potentially change this stuff later; currently it just
				// points to jQuery.expando
				var internalKey = jQuery.expando,
					internalCache = this[ internalKey ];
				if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
					jQuery.event.trigger( event, data, internalCache.handle.elem );
				}
			});
			return;
		}

		// Don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		// Clean up the event in case it is being reused
		event.result = undefined;
		event.target = elem;

		// Clone any incoming data and prepend the event, creating the handler arg list
		data = data ? jQuery.makeArray( data ) : [];
		data.unshift( event );

		var cur = elem,
			// IE doesn't like method names with a colon (#3533, #8272)
			ontype = type.indexOf(":") < 0 ? "on" + type : "";

		// Fire event on the current element, then bubble up the DOM tree
		do {
			var handle = jQuery._data( cur, "handle" );

			event.currentTarget = cur;
			if ( handle ) {
				handle.apply( cur, data );
			}

			// Trigger an inline bound script
			if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
				event.result = false;
				event.preventDefault();
			}

			// Bubble up to document, then to window
			cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
		} while ( cur && !event.isPropagationStopped() );

		// If nobody prevented the default action, do it now
		if ( !event.isDefaultPrevented() ) {
			var old,
				special = jQuery.event.special[ type ] || {};

			if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {

				// Call a native DOM method on the target with the same name name as the event.
				// Can't use an .isFunction)() check here because IE6/7 fails that test.
				// IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
				try {
					if ( ontype && elem[ type ] ) {
						// Don't re-trigger an onFOO event when we call its FOO() method
						old = elem[ ontype ];

						if ( old ) {
							elem[ ontype ] = null;
						}

						jQuery.event.triggered = type;
						elem[ type ]();
					}
				} catch ( ieError ) {}

				if ( old ) {
					elem[ ontype ] = old;
				}

				jQuery.event.triggered = undefined;
			}
		}
		
		return event.result;
	},

	handle: function( event ) {
		event = jQuery.event.fix( event || window.event );
		// Snapshot the handlers list since a called handler may add/remove events.
		var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
			run_all = !event.exclusive && !event.namespace,
			args = Array.prototype.slice.call( arguments, 0 );

		// Use the fix-ed Event rather than the (read-only) native event
		args[0] = event;
		event.currentTarget = this;

		for ( var j = 0, l = handlers.length; j < l; j++ ) {
			var handleObj = handlers[ j ];

			// Triggered event must 1) be non-exclusive and have no namespace, or
			// 2) have namespace(s) a subset or equal to those in the bound event.
			if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
				// Pass in a reference to the handler function itself
				// So that we can later remove it
				event.handler = handleObj.handler;
				event.data = handleObj.data;
				event.handleObj = handleObj;

				var ret = handleObj.handler.apply( this, args );

				if ( ret !== undefined ) {
					event.result = ret;
					if ( ret === false ) {
						event.preventDefault();
						event.stopPropagation();
					}
				}

				if ( event.isImmediatePropagationStopped() ) {
					break;
				}
			}
		}
		return event.result;
	},

	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),

	fix: function( event ) {
		if ( event[ jQuery.expando ] ) {
			return event;
		}

		// store a copy of the original event object
		// and "clone" to set read-only properties
		var originalEvent = event;
		event = jQuery.Event( originalEvent );

		for ( var i = this.props.length, prop; i; ) {
			prop = this.props[ --i ];
			event[ prop ] = originalEvent[ prop ];
		}

		// Fix target property, if necessary
		if ( !event.target ) {
			// Fixes #1925 where srcElement might not be defined either
			event.target = event.srcElement || document;
		}

		// check if target is a textnode (safari)
		if ( event.target.nodeType === 3 ) {
			event.target = event.target.parentNode;
		}

		// Add relatedTarget, if necessary
		if ( !event.relatedTarget && event.fromElement ) {
			event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
		}

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == null && event.clientX != null ) {
			var eventDocument = event.target.ownerDocument || document,
				doc = eventDocument.documentElement,
				body = eventDocument.body;

			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
		}

		// Add which for key events
		if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
			event.which = event.charCode != null ? event.charCode : event.keyCode;
		}

		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !event.metaKey && event.ctrlKey ) {
			event.metaKey = event.ctrlKey;
		}

		// Add which for click: 1 === left; 2 === middle; 3 === right
		// Note: button is not normalized, so don't use it
		if ( !event.which && event.button !== undefined ) {
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
		}

		return event;
	},

	// Deprecated, use jQuery.guid instead
	guid: 1E8,

	// Deprecated, use jQuery.proxy instead
	proxy: jQuery.proxy,

	special: {
		ready: {
			// Make sure the ready event is setup
			setup: jQuery.bindReady,
			teardown: jQuery.noop
		},

		live: {
			add: function( handleObj ) {
				jQuery.event.add( this,
					liveConvert( handleObj.origType, handleObj.selector ),
					jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
			},

			remove: function( handleObj ) {
				jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
			}
		},

		beforeunload: {
			setup: function( data, namespaces, eventHandle ) {
				// We only want to do this special case on windows
				if ( jQuery.isWindow( this ) ) {
					this.onbeforeunload = eventHandle;
				}
			},

			teardown: function( namespaces, eventHandle ) {
				if ( this.onbeforeunload === eventHandle ) {
					this.onbeforeunload = null;
				}
			}
		}
	}
};

jQuery.removeEvent = document.removeEventListener ?
	function( elem, type, handle ) {
		if ( elem.removeEventListener ) {
			elem.removeEventListener( type, handle, false );
		}
	} :
	function( elem, type, handle ) {
		if ( elem.detachEvent ) {
			elem.detachEvent( "on" + type, handle );
		}
	};

jQuery.Event = function( src, props ) {
	// Allow instantiation without the 'new' keyword
	if ( !this.preventDefault ) {
		return new jQuery.Event( src, props );
	}

	// Event object
	if ( src && src.type ) {
		this.originalEvent = src;
		this.type = src.type;

		// Events bubbling up the document may have been marked as prevented
		// by a handler lower down the tree; reflect the correct value.
		this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
			src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;

	// Event type
	} else {
		this.type = src;
	}

	// Put explicitly provided properties onto the event object
	if ( props ) {
		jQuery.extend( this, props );
	}

	// timeStamp is buggy for some events on Firefox(#3843)
	// So we won't rely on the native value
	this.timeStamp = jQuery.now();

	// Mark it as fixed
	this[ jQuery.expando ] = true;
};

function returnFalse() {
	return false;
}
function returnTrue() {
	return true;
}

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	preventDefault: function() {
		this.isDefaultPrevented = returnTrue;

		var e = this.originalEvent;
		if ( !e ) {
			return;
		}

		// if preventDefault exists run it on the original event
		if ( e.preventDefault ) {
			e.preventDefault();

		// otherwise set the returnValue property of the original event to false (IE)
		} else {
			e.returnValue = false;
		}
	},
	stopPropagation: function() {
		this.isPropagationStopped = returnTrue;

		var e = this.originalEvent;
		if ( !e ) {
			return;
		}
		// if stopPropagation exists run it on the original event
		if ( e.stopPropagation ) {
			e.stopPropagation();
		}
		// otherwise set the cancelBubble property of the original event to true (IE)
		e.cancelBubble = true;
	},
	stopImmediatePropagation: function() {
		this.isImmediatePropagationStopped = returnTrue;
		this.stopPropagation();
	},
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse
};

// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function( event ) {
	// Check if mouse(over|out) are still within the same parent element
	var parent = event.relatedTarget;

	// Firefox sometimes assigns relatedTarget a XUL element
	// which we cannot access the parentNode property of
	try {

		// Chrome does something similar, the parentNode property
		// can be accessed but is null.
		if ( parent && parent !== document && !parent.parentNode ) {
			return;
		}
		// Traverse up the tree
		while ( parent && parent !== this ) {
			parent = parent.parentNode;
		}

		if ( parent !== this ) {
			// set the correct event type
			event.type = event.data;

			// handle event if we actually just moused on to a non sub-element
			jQuery.event.handle.apply( this, arguments );
		}

	// assuming we've left the element since we most likely mousedover a xul element
	} catch(e) { }
},

// In case of event delegation, we only need to rename the event.type,
// liveHandler will take care of the rest.
delegate = function( event ) {
	event.type = event.data;
	jQuery.event.handle.apply( this, arguments );
};

// Create mouseenter and mouseleave events
jQuery.each({
	mouseenter: "mouseover",
	mouseleave: "mouseout"
}, function( orig, fix ) {
	jQuery.event.special[ orig ] = {
		setup: function( data ) {
			jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
		},
		teardown: function( data ) {
			jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
		}
	};
});

// submit delegation
if ( !jQuery.support.submitBubbles ) {

	jQuery.event.special.submit = {
		setup: function( data, namespaces ) {
			if ( !jQuery.nodeName( this, "form" ) ) {
				jQuery.event.add(this, "click.specialSubmit", function( e ) {
					var elem = e.target,
						type = elem.type;

					if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
						trigger( "submit", this, arguments );
					}
				});

				jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
					var elem = e.target,
						type = elem.type;

					if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
						trigger( "submit", this, arguments );
					}
				});

			} else {
				return false;
			}
		},

		teardown: function( namespaces ) {
			jQuery.event.remove( this, ".specialSubmit" );
		}
	};

}

// change delegation, happens here so we have bind.
if ( !jQuery.support.changeBubbles ) {

	var changeFilters,

	getVal = function( elem ) {
		var type = elem.type, val = elem.value;

		if ( type === "radio" || type === "checkbox" ) {
			val = elem.checked;

		} else if ( type === "select-multiple" ) {
			val = elem.selectedIndex > -1 ?
				jQuery.map( elem.options, function( elem ) {
					return elem.selected;
				}).join("-") :
				"";

		} else if ( jQuery.nodeName( elem, "select" ) ) {
			val = elem.selectedIndex;
		}

		return val;
	},

	testChange = function testChange( e ) {
		var elem = e.target, data, val;

		if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
			return;
		}

		data = jQuery._data( elem, "_change_data" );
		val = getVal(elem);

		// the current data will be also retrieved by beforeactivate
		if ( e.type !== "focusout" || elem.type !== "radio" ) {
			jQuery._data( elem, "_change_data", val );
		}

		if ( data === undefined || val === data ) {
			return;
		}

		if ( data != null || val ) {
			e.type = "change";
			e.liveFired = undefined;
			jQuery.event.trigger( e, arguments[1], elem );
		}
	};

	jQuery.event.special.change = {
		filters: {
			focusout: testChange,

			beforedeactivate: testChange,

			click: function( e ) {
				var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";

				if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
					testChange.call( this, e );
				}
			},

			// Change has to be called before submit
			// Keydown will be called before keypress, which is used in submit-event delegation
			keydown: function( e ) {
				var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";

				if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
					(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
					type === "select-multiple" ) {
					testChange.call( this, e );
				}
			},

			// Beforeactivate happens also before the previous element is blurred
			// with this event you can't trigger a change event, but you can store
			// information
			beforeactivate: function( e ) {
				var elem = e.target;
				jQuery._data( elem, "_change_data", getVal(elem) );
			}
		},

		setup: function( data, namespaces ) {
			if ( this.type === "file" ) {
				return false;
			}

			for ( var type in changeFilters ) {
				jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
			}

			return rformElems.test( this.nodeName );
		},

		teardown: function( namespaces ) {
			jQuery.event.remove( this, ".specialChange" );

			return rformElems.test( this.nodeName );
		}
	};

	changeFilters = jQuery.event.special.change.filters;

	// Handle when the input is .focus()'d
	changeFilters.focus = changeFilters.beforeactivate;
}

function trigger( type, elem, args ) {
	// Piggyback on a donor event to simulate a different one.
	// Fake originalEvent to avoid donor's stopPropagation, but if the
	// simulated event prevents default then we do the same on the donor.
	// Don't pass args or remember liveFired; they apply to the donor event.
	var event = jQuery.extend( {}, args[ 0 ] );
	event.type = type;
	event.originalEvent = {};
	event.liveFired = undefined;
	jQuery.event.handle.call( elem, event );
	if ( event.isDefaultPrevented() ) {
		args[ 0 ].preventDefault();
	}
}

// Create "bubbling" focus and blur events
if ( !jQuery.support.focusinBubbles ) {
	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {

		// Attach a single capturing handler while someone wants focusin/focusout
		var attaches = 0;

		jQuery.event.special[ fix ] = {
			setup: function() {
				if ( attaches++ === 0 ) {
					document.addEventListener( orig, handler, true );
				}
			},
			teardown: function() {
				if ( --attaches === 0 ) {
					document.removeEventListener( orig, handler, true );
				}
			}
		};

		function handler( donor ) {
			// Donor event is always a native one; fix it and switch its type.
			// Let focusin/out handler cancel the donor focus/blur event.
			var e = jQuery.event.fix( donor );
			e.type = fix;
			e.originalEvent = {};
			jQuery.event.trigger( e, null, e.target );
			if ( e.isDefaultPrevented() ) {
				donor.preventDefault();
			}
		}
	});
}

jQuery.each(["bind", "one"], function( i, name ) {
	jQuery.fn[ name ] = function( type, data, fn ) {
		var handler;

		// Handle object literals
		if ( typeof type === "object" ) {
			for ( var key in type ) {
				this[ name ](key, data, type[key], fn);
			}
			return this;
		}

		if ( arguments.length === 2 || data === false ) {
			fn = data;
			data = undefined;
		}

		if ( name === "one" ) {
			handler = function( event ) {
				jQuery( this ).unbind( event, handler );
				return fn.apply( this, arguments );
			};
			handler.guid = fn.guid || jQuery.guid++;
		} else {
			handler = fn;
		}

		if ( type === "unload" && name !== "one" ) {
			this.one( type, data, fn );

		} else {
			for ( var i = 0, l = this.length; i < l; i++ ) {
				jQuery.event.add( this[i], type, handler, data );
			}
		}

		return this;
	};
});

jQuery.fn.extend({
	unbind: function( type, fn ) {
		// Handle object literals
		if ( typeof type === "object" && !type.preventDefault ) {
			for ( var key in type ) {
				this.unbind(key, type[key]);
			}

		} else {
			for ( var i = 0, l = this.length; i < l; i++ ) {
				jQuery.event.remove( this[i], type, fn );
			}
		}

		return this;
	},

	delegate: function( selector, types, data, fn ) {
		return this.live( types, data, fn, selector );
	},

	undelegate: function( selector, types, fn ) {
		if ( arguments.length === 0 ) {
			return this.unbind( "live" );

		} else {
			return this.die( types, null, fn, selector );
		}
	},

	trigger: function( type, data ) {
		return this.each(function() {
			jQuery.event.trigger( type, data, this );
		});
	},

	triggerHandler: function( type, data ) {
		if ( this[0] ) {
			return jQuery.event.trigger( type, data, this[0], true );
		}
	},

	toggle: function( fn ) {
		// Save reference to arguments for access in closure
		var args = arguments,
			guid = fn.guid || jQuery.guid++,
			i = 0,
			toggler = function( event ) {
				// Figure out which function to execute
				var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
				jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );

				// Make sure that clicks stop
				event.preventDefault();

				// and execute the function
				return args[ lastToggle ].apply( this, arguments ) || false;
			};

		// link all the functions, so any of them can unbind this click handler
		toggler.guid = guid;
		while ( i < args.length ) {
			args[ i++ ].guid = guid;
		}

		return this.click( toggler );
	},

	hover: function( fnOver, fnOut ) {
		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
	}
});

var liveMap = {
	focus: "focusin",
	blur: "focusout",
	mouseenter: "mouseover",
	mouseleave: "mouseout"
};

jQuery.each(["live", "die"], function( i, name ) {
	jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
		var type, i = 0, match, namespaces, preType,
			selector = origSelector || this.selector,
			context = origSelector ? this : jQuery( this.context );

		if ( typeof types === "object" && !types.preventDefault ) {
			for ( var key in types ) {
				context[ name ]( key, data, types[key], selector );
			}

			return this;
		}

		if ( name === "die" && !types &&
					origSelector && origSelector.charAt(0) === "." ) {

			context.unbind( origSelector );

			return this;
		}

		if ( data === false || jQuery.isFunction( data ) ) {
			fn = data || returnFalse;
			data = undefined;
		}

		types = (types || "").split(" ");

		while ( (type = types[ i++ ]) != null ) {
			match = rnamespaces.exec( type );
			namespaces = "";

			if ( match )  {
				namespaces = match[0];
				type = type.replace( rnamespaces, "" );
			}

			if ( type === "hover" ) {
				types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
				continue;
			}

			preType = type;

			if ( liveMap[ type ] ) {
				types.push( liveMap[ type ] + namespaces );
				type = type + namespaces;

			} else {
				type = (liveMap[ type ] || type) + namespaces;
			}

			if ( name === "live" ) {
				// bind live handler
				for ( var j = 0, l = context.length; j < l; j++ ) {
					jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
						{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
				}

			} else {
				// unbind live handler
				context.unbind( "live." + liveConvert( type, selector ), fn );
			}
		}

		return this;
	};
});

function liveHandler( event ) {
	var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
		elems = [],
		selectors = [],
		events = jQuery._data( this, "events" );

	// Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
	if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
		return;
	}

	if ( event.namespace ) {
		namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
	}

	event.liveFired = this;

	var live = events.live.slice(0);

	for ( j = 0; j < live.length; j++ ) {
		handleObj = live[j];

		if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
			selectors.push( handleObj.selector );

		} else {
			live.splice( j--, 1 );
		}
	}

	match = jQuery( event.target ).closest( selectors, event.currentTarget );

	for ( i = 0, l = match.length; i < l; i++ ) {
		close = match[i];

		for ( j = 0; j < live.length; j++ ) {
			handleObj = live[j];

			if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
				elem = close.elem;
				related = null;

				// Those two events require additional checking
				if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
					event.type = handleObj.preType;
					related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];

					// Make sure not to accidentally match a child element with the same selector
					if ( related && jQuery.contains( elem, related ) ) {
						related = elem;
					}
				}

				if ( !related || related !== elem ) {
					elems.push({ elem: elem, handleObj: handleObj, level: close.level });
				}
			}
		}
	}

	for ( i = 0, l = elems.length; i < l; i++ ) {
		match = elems[i];

		if ( maxLevel && match.level > maxLevel ) {
			break;
		}

		event.currentTarget = match.elem;
		event.data = match.handleObj.data;
		event.handleObj = match.handleObj;

		ret = match.handleObj.origHandler.apply( match.elem, arguments );

		if ( ret === false || event.isPropagationStopped() ) {
			maxLevel = match.level;

			if ( ret === false ) {
				stop = false;
			}
			if ( event.isImmediatePropagationStopped() ) {
				break;
			}
		}
	}

	return stop;
}

function liveConvert( type, selector ) {
	return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
}

jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
	"change select submit keydown keypress keyup error").split(" "), function( i, name ) {

	// Handle event binding
	jQuery.fn[ name ] = function( data, fn ) {
		if ( fn == null ) {
			fn = data;
			data = null;
		}

		return arguments.length > 0 ?
			this.bind( name, data, fn ) :
			this.trigger( name );
	};

	if ( jQuery.attrFn ) {
		jQuery.attrFn[ name ] = true;
	}
});



/*!
 * Sizzle CSS Selector Engine
 *  Copyright 2011, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){

var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
	done = 0,
	toString = Object.prototype.toString,
	hasDuplicate = false,
	baseHasDuplicate = true,
	rBackslash = /\\/g,
	rNonWord = /\W/;

// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
//   Thus far that includes Google Chrome.
[0, 0].sort(function() {
	baseHasDuplicate = false;
	return 0;
});

var Sizzle = function( selector, context, results, seed ) {
	results = results || [];
	context = context || document;

	var origContext = context;

	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
		return [];
	}
	
	if ( !selector || typeof selector !== "string" ) {
		return results;
	}

	var m, set, checkSet, extra, ret, cur, pop, i,
		prune = true,
		contextXML = Sizzle.isXML( context ),
		parts = [],
		soFar = selector;
	
	// Reset the position of the chunker regexp (start from head)
	do {
		chunker.exec( "" );
		m = chunker.exec( soFar );

		if ( m ) {
			soFar = m[3];
		
			parts.push( m[1] );
		
			if ( m[2] ) {
				extra = m[3];
				break;
			}
		}
	} while ( m );

	if ( parts.length > 1 && origPOS.exec( selector ) ) {

		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
			set = posProcess( parts[0] + parts[1], context );

		} else {
			set = Expr.relative[ parts[0] ] ?
				[ context ] :
				Sizzle( parts.shift(), context );

			while ( parts.length ) {
				selector = parts.shift();

				if ( Expr.relative[ selector ] ) {
					selector += parts.shift();
				}
				
				set = posProcess( selector, set );
			}
		}

	} else {
		// Take a shortcut and set the context if the root selector is an ID
		// (but not if it'll be faster if the inner selector is an ID)
		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {

			ret = Sizzle.find( parts.shift(), context, contextXML );
			context = ret.expr ?
				Sizzle.filter( ret.expr, ret.set )[0] :
				ret.set[0];
		}

		if ( context ) {
			ret = seed ?
				{ expr: parts.pop(), set: makeArray(seed) } :
				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );

			set = ret.expr ?
				Sizzle.filter( ret.expr, ret.set ) :
				ret.set;

			if ( parts.length > 0 ) {
				checkSet = makeArray( set );

			} else {
				prune = false;
			}

			while ( parts.length ) {
				cur = parts.pop();
				pop = cur;

				if ( !Expr.relative[ cur ] ) {
					cur = "";
				} else {
					pop = parts.pop();
				}

				if ( pop == null ) {
					pop = context;
				}

				Expr.relative[ cur ]( checkSet, pop, contextXML );
			}

		} else {
			checkSet = parts = [];
		}
	}

	if ( !checkSet ) {
		checkSet = set;
	}

	if ( !checkSet ) {
		Sizzle.error( cur || selector );
	}

	if ( toString.call(checkSet) === "[object Array]" ) {
		if ( !prune ) {
			results.push.apply( results, checkSet );

		} else if ( context && context.nodeType === 1 ) {
			for ( i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
					results.push( set[i] );
				}
			}

		} else {
			for ( i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
					results.push( set[i] );
				}
			}
		}

	} else {
		makeArray( checkSet, results );
	}

	if ( extra ) {
		Sizzle( extra, origContext, results, seed );
		Sizzle.uniqueSort( results );
	}

	return results;
};

Sizzle.uniqueSort = function( results ) {
	if ( sortOrder ) {
		hasDuplicate = baseHasDuplicate;
		results.sort( sortOrder );

		if ( hasDuplicate ) {
			for ( var i = 1; i < results.length; i++ ) {
				if ( results[i] === results[ i - 1 ] ) {
					results.splice( i--, 1 );
				}
			}
		}
	}

	return results;
};

Sizzle.matches = function( expr, set ) {
	return Sizzle( expr, null, null, set );
};

Sizzle.matchesSelector = function( node, expr ) {
	return Sizzle( expr, null, null, [node] ).length > 0;
};

Sizzle.find = function( expr, context, isXML ) {
	var set;

	if ( !expr ) {
		return [];
	}

	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
		var match,
			type = Expr.order[i];
		
		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
			var left = match[1];
			match.splice( 1, 1 );

			if ( left.substr( left.length - 1 ) !== "\\" ) {
				match[1] = (match[1] || "").replace( rBackslash, "" );
				set = Expr.find[ type ]( match, context, isXML );

				if ( set != null ) {
					expr = expr.replace( Expr.match[ type ], "" );
					break;
				}
			}
		}
	}

	if ( !set ) {
		set = typeof context.getElementsByTagName !== "undefined" ?
			context.getElementsByTagName( "*" ) :
			[];
	}

	return { set: set, expr: expr };
};

Sizzle.filter = function( expr, set, inplace, not ) {
	var match, anyFound,
		old = expr,
		result = [],
		curLoop = set,
		isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );

	while ( expr && set.length ) {
		for ( var type in Expr.filter ) {
			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
				var found, item,
					filter = Expr.filter[ type ],
					left = match[1];

				anyFound = false;

				match.splice(1,1);

				if ( left.substr( left.length - 1 ) === "\\" ) {
					continue;
				}

				if ( curLoop === result ) {
					result = [];
				}

				if ( Expr.preFilter[ type ] ) {
					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

					if ( !match ) {
						anyFound = found = true;

					} else if ( match === true ) {
						continue;
					}
				}

				if ( match ) {
					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
						if ( item ) {
							found = filter( item, match, i, curLoop );
							var pass = not ^ !!found;

							if ( inplace && found != null ) {
								if ( pass ) {
									anyFound = true;

								} else {
									curLoop[i] = false;
								}

							} else if ( pass ) {
								result.push( item );
								anyFound = true;
							}
						}
					}
				}

				if ( found !== undefined ) {
					if ( !inplace ) {
						curLoop = result;
					}

					expr = expr.replace( Expr.match[ type ], "" );

					if ( !anyFound ) {
						return [];
					}

					break;
				}
			}
		}

		// Improper expression
		if ( expr === old ) {
			if ( anyFound == null ) {
				Sizzle.error( expr );

			} else {
				break;
			}
		}

		old = expr;
	}

	return curLoop;
};

Sizzle.error = function( msg ) {
	throw "Syntax error, unrecognized expression: " + msg;
};

var Expr = Sizzle.selectors = {
	order: [ "ID", "NAME", "TAG" ],

	match: {
		ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
		CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
		TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
		CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
		PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
	},

	leftMatch: {},

	attrMap: {
		"class": "className",
		"for": "htmlFor"
	},

	attrHandle: {
		href: function( elem ) {
			return elem.getAttribute( "href" );
		},
		type: function( elem ) {
			return elem.getAttribute( "type" );
		}
	},

	relative: {
		"+": function(checkSet, part){
			var isPartStr = typeof part === "string",
				isTag = isPartStr && !rNonWord.test( part ),
				isPartStrNotTag = isPartStr && !isTag;

			if ( isTag ) {
				part = part.toLowerCase();
			}

			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
				if ( (elem = checkSet[i]) ) {
					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}

					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
						elem || false :
						elem === part;
				}
			}

			if ( isPartStrNotTag ) {
				Sizzle.filter( part, checkSet, true );
			}
		},

		">": function( checkSet, part ) {
			var elem,
				isPartStr = typeof part === "string",
				i = 0,
				l = checkSet.length;

			if ( isPartStr && !rNonWord.test( part ) ) {
				part = part.toLowerCase();

				for ( ; i < l; i++ ) {
					elem = checkSet[i];

					if ( elem ) {
						var parent = elem.parentNode;
						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
					}
				}

			} else {
				for ( ; i < l; i++ ) {
					elem = checkSet[i];

					if ( elem ) {
						checkSet[i] = isPartStr ?
							elem.parentNode :
							elem.parentNode === part;
					}
				}

				if ( isPartStr ) {
					Sizzle.filter( part, checkSet, true );
				}
			}
		},

		"": function(checkSet, part, isXML){
			var nodeCheck,
				doneName = done++,
				checkFn = dirCheck;

			if ( typeof part === "string" && !rNonWord.test( part ) ) {
				part = part.toLowerCase();
				nodeCheck = part;
				checkFn = dirNodeCheck;
			}

			checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
		},

		"~": function( checkSet, part, isXML ) {
			var nodeCheck,
				doneName = done++,
				checkFn = dirCheck;

			if ( typeof part === "string" && !rNonWord.test( part ) ) {
				part = part.toLowerCase();
				nodeCheck = part;
				checkFn = dirNodeCheck;
			}

			checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
		}
	},

	find: {
		ID: function( match, context, isXML ) {
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				// Check parentNode to catch when Blackberry 4.6 returns
				// nodes that are no longer in the document #6963
				return m && m.parentNode ? [m] : [];
			}
		},

		NAME: function( match, context ) {
			if ( typeof context.getElementsByName !== "undefined" ) {
				var ret = [],
					results = context.getElementsByName( match[1] );

				for ( var i = 0, l = results.length; i < l; i++ ) {
					if ( results[i].getAttribute("name") === match[1] ) {
						ret.push( results[i] );
					}
				}

				return ret.length === 0 ? null : ret;
			}
		},

		TAG: function( match, context ) {
			if ( typeof context.getElementsByTagName !== "undefined" ) {
				return context.getElementsByTagName( match[1] );
			}
		}
	},
	preFilter: {
		CLASS: function( match, curLoop, inplace, result, not, isXML ) {
			match = " " + match[1].replace( rBackslash, "" ) + " ";

			if ( isXML ) {
				return match;
			}

			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
				if ( elem ) {
					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
						if ( !inplace ) {
							result.push( elem );
						}

					} else if ( inplace ) {
						curLoop[i] = false;
					}
				}
			}

			return false;
		},

		ID: function( match ) {
			return match[1].replace( rBackslash, "" );
		},

		TAG: function( match, curLoop ) {
			return match[1].replace( rBackslash, "" ).toLowerCase();
		},

		CHILD: function( match ) {
			if ( match[1] === "nth" ) {
				if ( !match[2] ) {
					Sizzle.error( match[0] );
				}

				match[2] = match[2].replace(/^\+|\s*/g, '');

				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
				var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);

				// calculate the numbers (first)n+(last) including if they are negative
				match[2] = (test[1] + (test[2] || 1)) - 0;
				match[3] = test[3] - 0;
			}
			else if ( match[2] ) {
				Sizzle.error( match[0] );
			}

			// TODO: Move to normal caching system
			match[0] = done++;

			return match;
		},

		ATTR: function( match, curLoop, inplace, result, not, isXML ) {
			var name = match[1] = match[1].replace( rBackslash, "" );
			
			if ( !isXML && Expr.attrMap[name] ) {
				match[1] = Expr.attrMap[name];
			}

			// Handle if an un-quoted value was used
			match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );

			if ( match[2] === "~=" ) {
				match[4] = " " + match[4] + " ";
			}

			return match;
		},

		PSEUDO: function( match, curLoop, inplace, result, not ) {
			if ( match[1] === "not" ) {
				// If we're dealing with a complex expression, or a simple one
				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
					match[3] = Sizzle(match[3], null, null, curLoop);

				} else {
					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);

					if ( !inplace ) {
						result.push.apply( result, ret );
					}

					return false;
				}

			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
				return true;
			}
			
			return match;
		},

		POS: function( match ) {
			match.unshift( true );

			return match;
		}
	},
	
	filters: {
		enabled: function( elem ) {
			return elem.disabled === false && elem.type !== "hidden";
		},

		disabled: function( elem ) {
			return elem.disabled === true;
		},

		checked: function( elem ) {
			return elem.checked === true;
		},
		
		selected: function( elem ) {
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			if ( elem.parentNode ) {
				elem.parentNode.selectedIndex;
			}
			
			return elem.selected === true;
		},

		parent: function( elem ) {
			return !!elem.firstChild;
		},

		empty: function( elem ) {
			return !elem.firstChild;
		},

		has: function( elem, i, match ) {
			return !!Sizzle( match[3], elem ).length;
		},

		header: function( elem ) {
			return (/h\d/i).test( elem.nodeName );
		},

		text: function( elem ) {
			var attr = elem.getAttribute( "type" ), type = elem.type;
			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
			// use getAttribute instead to test this case
			return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
		},

		radio: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
		},

		checkbox: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
		},

		file: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
		},

		password: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
		},

		submit: function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return (name === "input" || name === "button") && "submit" === elem.type;
		},

		image: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
		},

		reset: function( elem ) {
			return elem.nodeName.toLowerCase() === "input" && "reset" === elem.type;
		},

		button: function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return name === "input" && "button" === elem.type || name === "button";
		},

		input: function( elem ) {
			return (/input|select|textarea|button/i).test( elem.nodeName );
		},

		focus: function( elem ) {
			return elem === elem.ownerDocument.activeElement;
		}
	},
	setFilters: {
		first: function( elem, i ) {
			return i === 0;
		},

		last: function( elem, i, match, array ) {
			return i === array.length - 1;
		},

		even: function( elem, i ) {
			return i % 2 === 0;
		},

		odd: function( elem, i ) {
			return i % 2 === 1;
		},

		lt: function( elem, i, match ) {
			return i < match[3] - 0;
		},

		gt: function( elem, i, match ) {
			return i > match[3] - 0;
		},

		nth: function( elem, i, match ) {
			return match[3] - 0 === i;
		},

		eq: function( elem, i, match ) {
			return match[3] - 0 === i;
		}
	},
	filter: {
		PSEUDO: function( elem, match, i, array ) {
			var name = match[1],
				filter = Expr.filters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );

			} else if ( name === "contains" ) {
				return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;

			} else if ( name === "not" ) {
				var not = match[3];

				for ( var j = 0, l = not.length; j < l; j++ ) {
					if ( not[j] === elem ) {
						return false;
					}
				}

				return true;

			} else {
				Sizzle.error( name );
			}
		},

		CHILD: function( elem, match ) {
			var type = match[1],
				node = elem;

			switch ( type ) {
				case "only":
				case "first":
					while ( (node = node.previousSibling) )	 {
						if ( node.nodeType === 1 ) { 
							return false; 
						}
					}

					if ( type === "first" ) { 
						return true; 
					}

					node = elem;

				case "last":
					while ( (node = node.nextSibling) )	 {
						if ( node.nodeType === 1 ) { 
							return false; 
						}
					}

					return true;

				case "nth":
					var first = match[2],
						last = match[3];

					if ( first === 1 && last === 0 ) {
						return true;
					}
					
					var doneName = match[0],
						parent = elem.parentNode;
	
					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
						var count = 0;
						
						for ( node = parent.firstChild; node; node = node.nextSibling ) {
							if ( node.nodeType === 1 ) {
								node.nodeIndex = ++count;
							}
						} 

						parent.sizcache = doneName;
					}
					
					var diff = elem.nodeIndex - last;

					if ( first === 0 ) {
						return diff === 0;

					} else {
						return ( diff % first === 0 && diff / first >= 0 );
					}
			}
		},

		ID: function( elem, match ) {
			return elem.nodeType === 1 && elem.getAttribute("id") === match;
		},

		TAG: function( elem, match ) {
			return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
		},
		
		CLASS: function( elem, match ) {
			return (" " + (elem.className || elem.getAttribute("class")) + " ")
				.indexOf( match ) > -1;
		},

		ATTR: function( elem, match ) {
			var name = match[1],
				result = Expr.attrHandle[ name ] ?
					Expr.attrHandle[ name ]( elem ) :
					elem[ name ] != null ?
						elem[ name ] :
						elem.getAttribute( name ),
				value = result + "",
				type = match[2],
				check = match[4];

			return result == null ?
				type === "!=" :
				type === "=" ?
				value === check :
				type === "*=" ?
				value.indexOf(check) >= 0 :
				type === "~=" ?
				(" " + value + " ").indexOf(check) >= 0 :
				!check ?
				value && result !== false :
				type === "!=" ?
				value !== check :
				type === "^=" ?
				value.indexOf(check) === 0 :
				type === "$=" ?
				value.substr(value.length - check.length) === check :
				type === "|=" ?
				value === check || value.substr(0, check.length + 1) === check + "-" :
				false;
		},

		POS: function( elem, match, i, array ) {
			var name = match[2],
				filter = Expr.setFilters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			}
		}
	}
};

var origPOS = Expr.match.POS,
	fescape = function(all, num){
		return "\\" + (num - 0 + 1);
	};

for ( var type in Expr.match ) {
	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
}

var makeArray = function( array, results ) {
	array = Array.prototype.slice.call( array, 0 );

	if ( results ) {
		results.push.apply( results, array );
		return results;
	}
	
	return array;
};

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
// Also verifies that the returned array holds DOM nodes
// (which is not the case in the Blackberry browser)
try {
	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;

// Provide a fallback method if it does not work
} catch( e ) {
	makeArray = function( array, results ) {
		var i = 0,
			ret = results || [];

		if ( toString.call(array) === "[object Array]" ) {
			Array.prototype.push.apply( ret, array );

		} else {
			if ( typeof array.length === "number" ) {
				for ( var l = array.length; i < l; i++ ) {
					ret.push( array[i] );
				}

			} else {
				for ( ; array[i]; i++ ) {
					ret.push( array[i] );
				}
			}
		}

		return ret;
	};
}

var sortOrder, siblingCheck;

if ( document.documentElement.compareDocumentPosition ) {
	sortOrder = function( a, b ) {
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
			return a.compareDocumentPosition ? -1 : 1;
		}

		return a.compareDocumentPosition(b) & 4 ? -1 : 1;
	};

} else {
	sortOrder = function( a, b ) {
		var al, bl,
			ap = [],
			bp = [],
			aup = a.parentNode,
			bup = b.parentNode,
			cur = aup;

		// The nodes are identical, we can exit early
		if ( a === b ) {
			hasDuplicate = true;
			return 0;

		// If the nodes are siblings (or identical) we can do a quick check
		} else if ( aup === bup ) {
			return siblingCheck( a, b );

		// If no parents were found then the nodes are disconnected
		} else if ( !aup ) {
			return -1;

		} else if ( !bup ) {
			return 1;
		}

		// Otherwise they're somewhere else in the tree so we need
		// to build up a full list of the parentNodes for comparison
		while ( cur ) {
			ap.unshift( cur );
			cur = cur.parentNode;
		}

		cur = bup;

		while ( cur ) {
			bp.unshift( cur );
			cur = cur.parentNode;
		}

		al = ap.length;
		bl = bp.length;

		// Start walking down the tree looking for a discrepancy
		for ( var i = 0; i < al && i < bl; i++ ) {
			if ( ap[i] !== bp[i] ) {
				return siblingCheck( ap[i], bp[i] );
			}
		}

		// We ended someplace up the tree so do a sibling check
		return i === al ?
			siblingCheck( a, bp[i], -1 ) :
			siblingCheck( ap[i], b, 1 );
	};

	siblingCheck = function( a, b, ret ) {
		if ( a === b ) {
			return ret;
		}

		var cur = a.nextSibling;

		while ( cur ) {
			if ( cur === b ) {
				return -1;
			}

			cur = cur.nextSibling;
		}

		return 1;
	};
}

// Utility function for retreiving the text value of an array of DOM nodes
Sizzle.getText = function( elems ) {
	var ret = "", elem;

	for ( var i = 0; elems[i]; i++ ) {
		elem = elems[i];

		// Get the text from text nodes and CDATA nodes
		if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
			ret += elem.nodeValue;

		// Traverse everything else, except comment nodes
		} else if ( elem.nodeType !== 8 ) {
			ret += Sizzle.getText( elem.childNodes );
		}
	}

	return ret;
};

// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
	// We're going to inject a fake input element with a specified name
	var form = document.createElement("div"),
		id = "script" + (new Date()).getTime(),
		root = document.documentElement;

	form.innerHTML = "<a name='" + id + "'/>";

	// Inject it into the root element, check its status, and remove it quickly
	root.insertBefore( form, root.firstChild );

	// The workaround has to do additional checks after a getElementById
	// Which slows things down for other browsers (hence the branching)
	if ( document.getElementById( id ) ) {
		Expr.find.ID = function( match, context, isXML ) {
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);

				return m ?
					m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
						[m] :
						undefined :
					[];
			}
		};

		Expr.filter.ID = function( elem, match ) {
			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");

			return elem.nodeType === 1 && node && node.nodeValue === match;
		};
	}

	root.removeChild( form );

	// release memory in IE
	root = form = null;
})();

(function(){
	// Check to see if the browser returns only elements
	// when doing getElementsByTagName("*")

	// Create a fake element
	var div = document.createElement("div");
	div.appendChild( document.createComment("") );

	// Make sure no comments are found
	if ( div.getElementsByTagName("*").length > 0 ) {
		Expr.find.TAG = function( match, context ) {
			var results = context.getElementsByTagName( match[1] );

			// Filter out possible comments
			if ( match[1] === "*" ) {
				var tmp = [];

				for ( var i = 0; results[i]; i++ ) {
					if ( results[i].nodeType === 1 ) {
						tmp.push( results[i] );
					}
				}

				results = tmp;
			}

			return results;
		};
	}

	// Check to see if an attribute returns normalized href attributes
	div.innerHTML = "<a href='#'></a>";

	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
			div.firstChild.getAttribute("href") !== "#" ) {

		Expr.attrHandle.href = function( elem ) {
			return elem.getAttribute( "href", 2 );
		};
	}

	// release memory in IE
	div = null;
})();

if ( document.querySelectorAll ) {
	(function(){
		var oldSizzle = Sizzle,
			div = document.createElement("div"),
			id = "__sizzle__";

		div.innerHTML = "<p class='TEST'></p>";

		// Safari can't handle uppercase or unicode characters when
		// in quirks mode.
		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
			return;
		}
	
		Sizzle = function( query, context, extra, seed ) {
			context = context || document;

			// Only use querySelectorAll on non-XML documents
			// (ID selectors don't work in non-HTML documents)
			if ( !seed && !Sizzle.isXML(context) ) {
				// See if we find a selector to speed up
				var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
				
				if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
					// Speed-up: Sizzle("TAG")
					if ( match[1] ) {
						return makeArray( context.getElementsByTagName( query ), extra );
					
					// Speed-up: Sizzle(".CLASS")
					} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
						return makeArray( context.getElementsByClassName( match[2] ), extra );
					}
				}
				
				if ( context.nodeType === 9 ) {
					// Speed-up: Sizzle("body")
					// The body element only exists once, optimize finding it
					if ( query === "body" && context.body ) {
						return makeArray( [ context.body ], extra );
						
					// Speed-up: Sizzle("#ID")
					} else if ( match && match[3] ) {
						var elem = context.getElementById( match[3] );

						// Check parentNode to catch when Blackberry 4.6 returns
						// nodes that are no longer in the document #6963
						if ( elem && elem.parentNode ) {
							// Handle the case where IE and Opera return items
							// by name instead of ID
							if ( elem.id === match[3] ) {
								return makeArray( [ elem ], extra );
							}
							
						} else {
							return makeArray( [], extra );
						}
					}
					
					try {
						return makeArray( context.querySelectorAll(query), extra );
					} catch(qsaError) {}

				// qSA works strangely on Element-rooted queries
				// We can work around this by specifying an extra ID on the root
				// and working up from there (Thanks to Andrew Dupont for the technique)
				// IE 8 doesn't work on object elements
				} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
					var oldContext = context,
						old = context.getAttribute( "id" ),
						nid = old || id,
						hasParent = context.parentNode,
						relativeHierarchySelector = /^\s*[+~]/.test( query );

					if ( !old ) {
						context.setAttribute( "id", nid );
					} else {
						nid = nid.replace( /'/g, "\\$&" );
					}
					if ( relativeHierarchySelector && hasParent ) {
						context = context.parentNode;
					}

					try {
						if ( !relativeHierarchySelector || hasParent ) {
							return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
						}

					} catch(pseudoError) {
					} finally {
						if ( !old ) {
							oldContext.removeAttribute( "id" );
						}
					}
				}
			}
		
			return oldSizzle(query, context, extra, seed);
		};

		for ( var prop in oldSizzle ) {
			Sizzle[ prop ] = oldSizzle[ prop ];
		}

		// release memory in IE
		div = null;
	})();
}

(function(){
	var html = document.documentElement,
		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;

	if ( matches ) {
		// Check to see if it's possible to do matchesSelector
		// on a disconnected node (IE 9 fails this)
		var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
			pseudoWorks = false;

		try {
			// This should fail with an exception
			// Gecko does not error, returns false instead
			matches.call( document.documentElement, "[test!='']:sizzle" );
	
		} catch( pseudoError ) {
			pseudoWorks = true;
		}

		Sizzle.matchesSelector = function( node, expr ) {
			// Make sure that attribute selectors are quoted
			expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");

			if ( !Sizzle.isXML( node ) ) {
				try { 
					if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
						var ret = matches.call( node, expr );

						// IE 9's matchesSelector returns false on disconnected nodes
						if ( ret || !disconnectedMatch ||
								// As well, disconnected nodes are said to be in a document
								// fragment in IE 9, so check for that
								node.document && node.document.nodeType !== 11 ) {
							return ret;
						}
					}
				} catch(e) {}
			}

			return Sizzle(expr, null, null, [node]).length > 0;
		};
	}
})();

(function(){
	var div = document.createElement("div");

	div.innerHTML = "<div class='test e'></div><div class='test'></div>";

	// Opera can't find a second classname (in 9.6)
	// Also, make sure that getElementsByClassName actually exists
	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
		return;
	}

	// Safari caches class attributes, doesn't catch changes (in 3.2)
	div.lastChild.className = "e";

	if ( div.getElementsByClassName("e").length === 1 ) {
		return;
	}
	
	Expr.order.splice(1, 0, "CLASS");
	Expr.find.CLASS = function( match, context, isXML ) {
		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
			return context.getElementsByClassName(match[1]);
		}
	};

	// release memory in IE
	div = null;
})();

function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];

		if ( elem ) {
			var match = false;

			elem = elem[dir];

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 && !isXML ){
					elem.sizcache = doneName;
					elem.sizset = i;
				}

				if ( elem.nodeName.toLowerCase() === cur ) {
					match = elem;
					break;
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];

		if ( elem ) {
			var match = false;
			
			elem = elem[dir];

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 ) {
					if ( !isXML ) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}

					if ( typeof cur !== "string" ) {
						if ( elem === cur ) {
							match = true;
							break;
						}

					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
						match = elem;
						break;
					}
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

if ( document.documentElement.contains ) {
	Sizzle.contains = function( a, b ) {
		return a !== b && (a.contains ? a.contains(b) : true);
	};

} else if ( document.documentElement.compareDocumentPosition ) {
	Sizzle.contains = function( a, b ) {
		return !!(a.compareDocumentPosition(b) & 16);
	};

} else {
	Sizzle.contains = function() {
		return false;
	};
}

Sizzle.isXML = function( elem ) {
	// documentElement is verified for cases where it doesn't yet exist
	// (such as loading iframes in IE - #4833) 
	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;

	return documentElement ? documentElement.nodeName !== "HTML" : false;
};

var posProcess = function( selector, context ) {
	var match,
		tmpSet = [],
		later = "",
		root = context.nodeType ? [context] : context;

	// Position selectors must be done after the filter
	// And so must :not(positional) so we move all PSEUDOs to the end
	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
		later += match[0];
		selector = selector.replace( Expr.match.PSEUDO, "" );
	}

	selector = Expr.relative[selector] ? selector + "*" : selector;

	for ( var i = 0, l = root.length; i < l; i++ ) {
		Sizzle( selector, root[i], tmpSet );
	}

	return Sizzle.filter( later, tmpSet );
};

// EXPOSE
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;


})();


var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	isSimple = /^.[^:#\[\.,]*$/,
	slice = Array.prototype.slice,
	POS = jQuery.expr.match.POS,
	// methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend({
	find: function( selector ) {
		var self = this,
			i, l;

		if ( typeof selector !== "string" ) {
			return jQuery( selector ).filter(function() {
				for ( i = 0, l = self.length; i < l; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			});
		}

		var ret = this.pushStack( "", "find", selector ),
			length, n, r;

		for ( i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( n = length; n < ret.length; n++ ) {
					for ( r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	has: function( target ) {
		var targets = jQuery( target );
		return this.filter(function() {
			for ( var i = 0, l = targets.length; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	is: function( selector ) {
		return !!selector && ( typeof selector === "string" ?
			jQuery.filter( selector, this ).length > 0 :
			this.filter( selector ).length > 0 );
	},

	closest: function( selectors, context ) {
		var ret = [], i, l, cur = this[0];
		
		// Array
		if ( jQuery.isArray( selectors ) ) {
			var match, selector,
				matches = {},
				level = 1;

			if ( cur && selectors.length ) {
				for ( i = 0, l = selectors.length; i < l; i++ ) {
					selector = selectors[i];

					if ( !matches[ selector ] ) {
						matches[ selector ] = POS.test( selector ) ?
							jQuery( selector, context || this.context ) :
							selector;
					}
				}

				while ( cur && cur.ownerDocument && cur !== context ) {
					for ( selector in matches ) {
						match = matches[ selector ];

						if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
							ret.push({ selector: selector, elem: cur, level: level });
						}
					}

					cur = cur.parentNode;
					level++;
				}
			}

			return ret;
		}

		// String
		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( i = 0, l = this.length; i < l; i++ ) {
			cur = this[i];

			while ( cur ) {
				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
					ret.push( cur );
					break;

				} else {
					cur = cur.parentNode;
					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
						break;
					}
				}
			}
		}

		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;

		return this.pushStack( ret, "closest", selectors );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {
		if ( !elem || typeof elem === "string" ) {
			return jQuery.inArray( this[0],
				// If it receives a string, the selector is used
				// If it receives nothing, the siblings are used
				elem ? jQuery( elem ) : this.parent().children() );
		}
		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context ) :
				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
			all :
			jQuery.unique( all ) );
	},

	andSelf: function() {
		return this.add( this.prevObject );
	}
});

// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
	return !node || !node.parentNode || node.parentNode.nodeType === 11;
}

jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return jQuery.nth( elem, 2, "nextSibling" );
	},
	prev: function( elem ) {
		return jQuery.nth( elem, 2, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( elem.parentNode.firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.makeArray( elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until ),
			// The variable 'args' was introduced in
			// https://github.com/jquery/jquery/commit/52a0238
			// to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
			// http://code.google.com/p/v8/issues/detail?id=1050
			args = slice.call(arguments);

		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, args.join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return elems.length === 1 ?
			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
			jQuery.find.matches(expr, elems);
	},

	dir: function( elem, dir, until ) {
		var matched = [],
			cur = elem[ dir ];

		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, result, dir, elem ) {
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && ++num === result ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {

	// Can't pass null or undefined to indexOf in Firefox 4
	// Set to 0 to skip string check
	qualifier = qualifier || 0;

	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function( elem, i ) {
			var retVal = !!qualifier.call( elem, i, elem );
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) {
			return (elem === qualifier) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) {
		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
	});
}




var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
	rleadingWhitespace = /^\s+/,
	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
	rtagName = /<([\w:]+)/,
	rtbody = /<tbody/i,
	rhtml = /<|&#?\w+;/,
	rnocache = /<(?:script|object|embed|option|style)/i,
	// checked="checked" or checked
	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
	rscriptType = /\/(java|ecma)script/i,
	wrapMap = {
		option: [ 1, "<select multiple='multiple'>", "</select>" ],
		legend: [ 1, "<fieldset>", "</fieldset>" ],
		thead: [ 1, "<table>", "</table>" ],
		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
		area: [ 1, "<map>", "</map>" ],
		_default: [ 0, "", "" ]
	};

wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;

// IE can't serialize <link> and <script> tags normally
if ( !jQuery.support.htmlSerialize ) {
	wrapMap._default = [ 1, "div<div>", "</div>" ];
}

jQuery.fn.extend({
	text: function( text ) {
		if ( jQuery.isFunction(text) ) {
			return this.each(function(i) {
				var self = jQuery( this );

				self.text( text.call(this, i, self.text()) );
			});
		}

		if ( typeof text !== "object" && text !== undefined ) {
			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
		}

		return jQuery.text( this );
	},

	wrapAll: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each(function(i) {
				jQuery(this).wrapAll( html.call(this, i) );
			});
		}

		if ( this[0] ) {
			// The elements to wrap the target around
			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);

			if ( this[0].parentNode ) {
				wrap.insertBefore( this[0] );
			}

			wrap.map(function() {
				var elem = this;

				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
					elem = elem.firstChild;
				}

				return elem;
			}).append( this );
		}

		return this;
	},

	wrapInner: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each(function(i) {
				jQuery(this).wrapInner( html.call(this, i) );
			});
		}

		return this.each(function() {
			var self = jQuery( this ),
				contents = self.contents();

			if ( contents.length ) {
				contents.wrapAll( html );

			} else {
				self.append( html );
			}
		});
	},

	wrap: function( html ) {
		return this.each(function() {
			jQuery( this ).wrapAll( html );
		});
	},

	unwrap: function() {
		return this.parent().each(function() {
			if ( !jQuery.nodeName( this, "body" ) ) {
				jQuery( this ).replaceWith( this.childNodes );
			}
		}).end();
	},

	append: function() {
		return this.domManip(arguments, true, function( elem ) {
			if ( this.nodeType === 1 ) {
				this.appendChild( elem );
			}
		});
	},

	prepend: function() {
		return this.domManip(arguments, true, function( elem ) {
			if ( this.nodeType === 1 ) {
				this.insertBefore( elem, this.firstChild );
			}
		});
	},

	before: function() {
		if ( this[0] && this[0].parentNode ) {
			return this.domManip(arguments, false, function( elem ) {
				this.parentNode.insertBefore( elem, this );
			});
		} else if ( arguments.length ) {
			var set = jQuery(arguments[0]);
			set.push.apply( set, this.toArray() );
			return this.pushStack( set, "before", arguments );
		}
	},

	after: function() {
		if ( this[0] && this[0].parentNode ) {
			return this.domManip(arguments, false, function( elem ) {
				this.parentNode.insertBefore( elem, this.nextSibling );
			});
		} else if ( arguments.length ) {
			var set = this.pushStack( this, "after", arguments );
			set.push.apply( set, jQuery(arguments[0]).toArray() );
			return set;
		}
	},

	// keepData is for internal use only--do not document
	remove: function( selector, keepData ) {
		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
				if ( !keepData && elem.nodeType === 1 ) {
					jQuery.cleanData( elem.getElementsByTagName("*") );
					jQuery.cleanData( [ elem ] );
				}

				if ( elem.parentNode ) {
					elem.parentNode.removeChild( elem );
				}
			}
		}

		return this;
	},

	empty: function() {
		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
			// Remove element nodes and prevent memory leaks
			if ( elem.nodeType === 1 ) {
				jQuery.cleanData( elem.getElementsByTagName("*") );
			}

			// Remove any remaining nodes
			while ( elem.firstChild ) {
				elem.removeChild( elem.firstChild );
			}
		}

		return this;
	},

	clone: function( dataAndEvents, deepDataAndEvents ) {
		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

		return this.map( function () {
			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
		});
	},

	html: function( value ) {
		if ( value === undefined ) {
			return this[0] && this[0].nodeType === 1 ?
				this[0].innerHTML.replace(rinlinejQuery, "") :
				null;

		// See if we can take a shortcut and just use innerHTML
		} else if ( typeof value === "string" && !rnocache.test( value ) &&
			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {

			value = value.replace(rxhtmlTag, "<$1></$2>");

			try {
				for ( var i = 0, l = this.length; i < l; i++ ) {
					// Remove element nodes and prevent memory leaks
					if ( this[i].nodeType === 1 ) {
						jQuery.cleanData( this[i].getElementsByTagName("*") );
						this[i].innerHTML = value;
					}
				}

			// If using innerHTML throws an exception, use the fallback method
			} catch(e) {
				this.empty().append( value );
			}

		} else if ( jQuery.isFunction( value ) ) {
			this.each(function(i){
				var self = jQuery( this );

				self.html( value.call(this, i, self.html()) );
			});

		} else {
			this.empty().append( value );
		}

		return this;
	},

	replaceWith: function( value ) {
		if ( this[0] && this[0].parentNode ) {
			// Make sure that the elements are removed from the DOM before they are inserted
			// this can help fix replacing a parent with child elements
			if ( jQuery.isFunction( value ) ) {
				return this.each(function(i) {
					var self = jQuery(this), old = self.html();
					self.replaceWith( value.call( this, i, old ) );
				});
			}

			if ( typeof value !== "string" ) {
				value = jQuery( value ).detach();
			}

			return this.each(function() {
				var next = this.nextSibling,
					parent = this.parentNode;

				jQuery( this ).remove();

				if ( next ) {
					jQuery(next).before( value );
				} else {
					jQuery(parent).append( value );
				}
			});
		} else {
			return this.length ?
				this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
				this;
		}
	},

	detach: function( selector ) {
		return this.remove( selector, true );
	},

	domManip: function( args, table, callback ) {
		var results, first, fragment, parent,
			value = args[0],
			scripts = [];

		// We can't cloneNode fragments that contain checked, in WebKit
		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
			return this.each(function() {
				jQuery(this).domManip( args, table, callback, true );
			});
		}

		if ( jQuery.isFunction(value) ) {
			return this.each(function(i) {
				var self = jQuery(this);
				args[0] = value.call(this, i, table ? self.html() : undefined);
				self.domManip( args, table, callback );
			});
		}

		if ( this[0] ) {
			parent = value && value.parentNode;

			// If we're in a fragment, just use that instead of building a new one
			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
				results = { fragment: parent };

			} else {
				results = jQuery.buildFragment( args, this, scripts );
			}

			fragment = results.fragment;

			if ( fragment.childNodes.length === 1 ) {
				first = fragment = fragment.firstChild;
			} else {
				first = fragment.firstChild;
			}

			if ( first ) {
				table = table && jQuery.nodeName( first, "tr" );

				for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
					callback.call(
						table ?
							root(this[i], first) :
							this[i],
						// Make sure that we do not leak memory by inadvertently discarding
						// the original fragment (which might have attached data) instead of
						// using it; in addition, use the original fragment object for the last
						// item instead of first because it can end up being emptied incorrectly
						// in certain situations (Bug #8070).
						// Fragments from the fragment cache must always be cloned and never used
						// in place.
						results.cacheable || (l > 1 && i < lastIndex) ?
							jQuery.clone( fragment, true, true ) :
							fragment
					);
				}
			}

			if ( scripts.length ) {
				jQuery.each( scripts, evalScript );
			}
		}

		return this;
	}
});

function root( elem, cur ) {
	return jQuery.nodeName(elem, "table") ?
		(elem.getElementsByTagName("tbody")[0] ||
		elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
		elem;
}

function cloneCopyEvent( src, dest ) {

	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
		return;
	}

	var internalKey = jQuery.expando,
		oldData = jQuery.data( src ),
		curData = jQuery.data( dest, oldData );

	// Switch to use the internal data object, if it exists, for the next
	// stage of data copying
	if ( (oldData = oldData[ internalKey ]) ) {
		var events = oldData.events;
				curData = curData[ internalKey ] = jQuery.extend({}, oldData);

		if ( events ) {
			delete curData.handle;
			curData.events = {};

			for ( var type in events ) {
				for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
					jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
				}
			}
		}
	}
}

function cloneFixAttributes( src, dest ) {
	var nodeName;

	// We do not need to do anything for non-Elements
	if ( dest.nodeType !== 1 ) {
		return;
	}

	// clearAttributes removes the attributes, which we don't want,
	// but also removes the attachEvent events, which we *do* want
	if ( dest.clearAttributes ) {
		dest.clearAttributes();
	}

	// mergeAttributes, in contrast, only merges back on the
	// original attributes, not the events
	if ( dest.mergeAttributes ) {
		dest.mergeAttributes( src );
	}

	nodeName = dest.nodeName.toLowerCase();

	// IE6-8 fail to clone children inside object elements that use
	// the proprietary classid attribute value (rather than the type
	// attribute) to identify the type of content to display
	if ( nodeName === "object" ) {
		dest.outerHTML = src.outerHTML;

	} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
		// IE6-8 fails to persist the checked state of a cloned checkbox
		// or radio button. Worse, IE6-7 fail to give the cloned element
		// a checked appearance if the defaultChecked value isn't also set
		if ( src.checked ) {
			dest.defaultChecked = dest.checked = src.checked;
		}

		// IE6-7 get confused and end up setting the value of a cloned
		// checkbox/radio button to an empty string instead of "on"
		if ( dest.value !== src.value ) {
			dest.value = src.value;
		}

	// IE6-8 fails to return the selected option to the default selected
	// state when cloning options
	} else if ( nodeName === "option" ) {
		dest.selected = src.defaultSelected;

	// IE6-8 fails to set the defaultValue to the correct value when
	// cloning other types of input fields
	} else if ( nodeName === "input" || nodeName === "textarea" ) {
		dest.defaultValue = src.defaultValue;
	}

	// Event data gets referenced instead of copied if the expando
	// gets copied too
	dest.removeAttribute( jQuery.expando );
}

jQuery.buildFragment = function( args, nodes, scripts ) {
	var fragment, cacheable, cacheresults,
		doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);

	// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
	// Cloning options loses the selected state, so don't cache them
	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
	if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
		args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {

		cacheable = true;

		cacheresults = jQuery.fragments[ args[0] ];
		if ( cacheresults && cacheresults !== 1 ) {
			fragment = cacheresults;
		}
	}

	if ( !fragment ) {
		fragment = doc.createDocumentFragment();
		jQuery.clean( args, doc, fragment, scripts );
	}

	if ( cacheable ) {
		jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
	}

	return { fragment: fragment, cacheable: cacheable };
};

jQuery.fragments = {};

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function( name, original ) {
	jQuery.fn[ name ] = function( selector ) {
		var ret = [],
			insert = jQuery( selector ),
			parent = this.length === 1 && this[0].parentNode;

		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
			insert[ original ]( this[0] );
			return this;

		} else {
			for ( var i = 0, l = insert.length; i < l; i++ ) {
				var elems = (i > 0 ? this.clone(true) : this).get();
				jQuery( insert[i] )[ original ]( elems );
				ret = ret.concat( elems );
			}

			return this.pushStack( ret, name, insert.selector );
		}
	};
});

function getAll( elem ) {
	if ( "getElementsByTagName" in elem ) {
		return elem.getElementsByTagName( "*" );
	
	} else if ( "querySelectorAll" in elem ) {
		return elem.querySelectorAll( "*" );

	} else {
		return [];
	}
}

// Used in clean, fixes the defaultChecked property
function fixDefaultChecked( elem ) {
	if ( elem.type === "checkbox" || elem.type === "radio" ) {
		elem.defaultChecked = elem.checked;
	}
}
// Finds all inputs and passes them to fixDefaultChecked
function findInputs( elem ) {
	if ( jQuery.nodeName( elem, "input" ) ) {
		fixDefaultChecked( elem );
	} else if ( elem.getElementsByTagName ) {
		jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
	}
}

jQuery.extend({
	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
		var clone = elem.cloneNode(true),
				srcElements,
				destElements,
				i;

		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
			// IE copies events bound via attachEvent when using cloneNode.
			// Calling detachEvent on the clone will also remove the events
			// from the original. In order to get around this, we use some
			// proprietary methods to clear the events. Thanks to MooTools
			// guys for this hotness.

			cloneFixAttributes( elem, clone );

			// Using Sizzle here is crazy slow, so we use getElementsByTagName
			// instead
			srcElements = getAll( elem );
			destElements = getAll( clone );

			// Weird iteration because IE will replace the length property
			// with an element if you are cloning the body and one of the
			// elements on the page has a name or id of "length"
			for ( i = 0; srcElements[i]; ++i ) {
				cloneFixAttributes( srcElements[i], destElements[i] );
			}
		}

		// Copy the events from the original to the clone
		if ( dataAndEvents ) {
			cloneCopyEvent( elem, clone );

			if ( deepDataAndEvents ) {
				srcElements = getAll( elem );
				destElements = getAll( clone );

				for ( i = 0; srcElements[i]; ++i ) {
					cloneCopyEvent( srcElements[i], destElements[i] );
				}
			}
		}

		// Return the cloned set
		return clone;
	},

	clean: function( elems, context, fragment, scripts ) {
		var checkScriptType;

		context = context || document;

		// !context.createElement fails in IE with an error but returns typeof 'object'
		if ( typeof context.createElement === "undefined" ) {
			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
		}

		var ret = [];

		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
			if ( typeof elem === "number" ) {
				elem += "";
			}

			if ( !elem ) {
				continue;
			}

			// Convert html string into DOM nodes
			if ( typeof elem === "string" ) {
				if ( !rhtml.test( elem ) ) {
					elem = context.createTextNode( elem );
				} else {
					// Fix "XHTML"-style tags in all browsers
					elem = elem.replace(rxhtmlTag, "<$1></$2>");

					// Trim whitespace, otherwise indexOf won't work as expected
					var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
						wrap = wrapMap[ tag ] || wrapMap._default,
						depth = wrap[0],
						div = context.createElement("div");

					// Go to html and back, then peel off extra wrappers
					div.innerHTML = wrap[1] + elem + wrap[2];

					// Move to the right depth
					while ( depth-- ) {
						div = div.lastChild;
					}

					// Remove IE's autoinserted <tbody> from table fragments
					if ( !jQuery.support.tbody ) {

						// String was a <table>, *may* have spurious <tbody>
						var hasBody = rtbody.test(elem),
							tbody = tag === "table" && !hasBody ?
								div.firstChild && div.firstChild.childNodes :

								// String was a bare <thead> or <tfoot>
								wrap[1] === "<table>" && !hasBody ?
									div.childNodes :
									[];

						for ( var j = tbody.length - 1; j >= 0 ; --j ) {
							if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
								tbody[ j ].parentNode.removeChild( tbody[ j ] );
							}
						}
					}

					// IE completely kills leading whitespace when innerHTML is used
					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
						div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
					}

					elem = div.childNodes;
				}
			}

			// Resets defaultChecked for any radios and checkboxes
			// about to be appended to the DOM in IE 6/7 (#8060)
			var len;
			if ( !jQuery.support.appendChecked ) {
				if ( elem[0] && typeof (len = elem.length) === "number" ) {
					for ( i = 0; i < len; i++ ) {
						findInputs( elem[i] );
					}
				} else {
					findInputs( elem );
				}
			}

			if ( elem.nodeType ) {
				ret.push( elem );
			} else {
				ret = jQuery.merge( ret, elem );
			}
		}

		if ( fragment ) {
			checkScriptType = function( elem ) {
				return !elem.type || rscriptType.test( elem.type );
			};
			for ( i = 0; ret[i]; i++ ) {
				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );

				} else {
					if ( ret[i].nodeType === 1 ) {
						var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );

						ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
					}
					fragment.appendChild( ret[i] );
				}
			}
		}

		return ret;
	},

	cleanData: function( elems ) {
		var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
			deleteExpando = jQuery.support.deleteExpando;

		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
			if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
				continue;
			}

			id = elem[ jQuery.expando ];

			if ( id ) {
				data = cache[ id ] && cache[ id ][ internalKey ];

				if ( data && data.events ) {
					for ( var type in data.events ) {
						if ( special[ type ] ) {
							jQuery.event.remove( elem, type );

						// This is a shortcut to avoid jQuery.event.remove's overhead
						} else {
							jQuery.removeEvent( elem, type, data.handle );
						}
					}

					// Null the DOM reference to avoid IE6/7/8 leak (#7054)
					if ( data.handle ) {
						data.handle.elem = null;
					}
				}

				if ( deleteExpando ) {
					delete elem[ jQuery.expando ];

				} else if ( elem.removeAttribute ) {
					elem.removeAttribute( jQuery.expando );
				}

				delete cache[ id ];
			}
		}
	}
});

function evalScript( i, elem ) {
	if ( elem.src ) {
		jQuery.ajax({
			url: elem.src,
			async: false,
			dataType: "script"
		});
	} else {
		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
	}

	if ( elem.parentNode ) {
		elem.parentNode.removeChild( elem );
	}
}




var ralpha = /alpha\([^)]*\)/i,
	ropacity = /opacity=([^)]*)/,
	rdashAlpha = /-([a-z])/ig,
	// fixed for IE9, see #8346
	rupper = /([A-Z]|^ms)/g,
	rnumpx = /^-?\d+(?:px)?$/i,
	rnum = /^-?\d/,
	rrelNum = /^[+\-]=/,
	rrelNumFilter = /[^+\-\.\de]+/g,

	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
	cssWidth = [ "Left", "Right" ],
	cssHeight = [ "Top", "Bottom" ],
	curCSS,

	getComputedStyle,
	currentStyle,

	fcamelCase = function( all, letter ) {
		return letter.toUpperCase();
	};

jQuery.fn.css = function( name, value ) {
	// Setting 'undefined' is a no-op
	if ( arguments.length === 2 && value === undefined ) {
		return this;
	}

	return jQuery.access( this, name, value, true, function( elem, name, value ) {
		return value !== undefined ?
			jQuery.style( elem, name, value ) :
			jQuery.css( elem, name );
	});
};

jQuery.extend({
	// Add in style property hooks for overriding the default
	// behavior of getting and setting a style property
	cssHooks: {
		opacity: {
			get: function( elem, computed ) {
				if ( computed ) {
					// We should always get a number back from opacity
					var ret = curCSS( elem, "opacity", "opacity" );
					return ret === "" ? "1" : ret;

				} else {
					return elem.style.opacity;
				}
			}
		}
	},

	// Exclude the following css properties to add px
	cssNumber: {
		"zIndex": true,
		"fontWeight": true,
		"opacity": true,
		"zoom": true,
		"lineHeight": true,
		"widows": true,
		"orphans": true
	},

	// Add in properties whose names you wish to fix before
	// setting or getting the value
	cssProps: {
		// normalize float css property
		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
	},

	// Get and set the style property on a DOM Node
	style: function( elem, name, value, extra ) {
		// Don't set styles on text and comment nodes
		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
			return;
		}

		// Make sure that we're working with the right name
		var ret, type, origName = jQuery.camelCase( name ),
			style = elem.style, hooks = jQuery.cssHooks[ origName ];

		name = jQuery.cssProps[ origName ] || origName;

		// Check if we're setting a value
		if ( value !== undefined ) {
			type = typeof value;

			// Make sure that NaN and null values aren't set. See: #7116
			if ( type === "number" && isNaN( value ) || value == null ) {
				return;
			}

			// convert relative number strings (+= or -=) to relative numbers. #7345
			if ( type === "string" && rrelNum.test( value ) ) {
				value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) );
			}

			// If a number was passed in, add 'px' to the (except for certain CSS properties)
			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
				value += "px";
			}

			// If a hook was provided, use that value, otherwise just set the specified value
			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
				// Fixes bug #5509
				try {
					style[ name ] = value;
				} catch(e) {}
			}

		} else {
			// If a hook was provided get the non-computed value from there
			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
				return ret;
			}

			// Otherwise just get the value from the style object
			return style[ name ];
		}
	},

	css: function( elem, name, extra ) {
		var ret, hooks;

		// Make sure that we're working with the right name
		name = jQuery.camelCase( name );
		hooks = jQuery.cssHooks[ name ];
		name = jQuery.cssProps[ name ] || name;

		// cssFloat needs a special treatment
		if ( name === "cssFloat" ) {
			name = "float";
		}

		// If a hook was provided get the computed value from there
		if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
			return ret;

		// Otherwise, if a way to get the computed value exists, use that
		} else if ( curCSS ) {
			return curCSS( elem, name );
		}
	},

	// A method for quickly swapping in/out CSS properties to get correct calculations
	swap: function( elem, options, callback ) {
		var old = {};

		// Remember the old values, and insert the new ones
		for ( var name in options ) {
			old[ name ] = elem.style[ name ];
			elem.style[ name ] = options[ name ];
		}

		callback.call( elem );

		// Revert the old values
		for ( name in options ) {
			elem.style[ name ] = old[ name ];
		}
	},

	camelCase: function( string ) {
		return string.replace( rdashAlpha, fcamelCase );
	}
});

// DEPRECATED, Use jQuery.css() instead
jQuery.curCSS = jQuery.css;

jQuery.each(["height", "width"], function( i, name ) {
	jQuery.cssHooks[ name ] = {
		get: function( elem, computed, extra ) {
			var val;

			if ( computed ) {
				if ( elem.offsetWidth !== 0 ) {
					val = getWH( elem, name, extra );

				} else {
					jQuery.swap( elem, cssShow, function() {
						val = getWH( elem, name, extra );
					});
				}

				if ( val <= 0 ) {
					val = curCSS( elem, name, name );

					if ( val === "0px" && currentStyle ) {
						val = currentStyle( elem, name, name );
					}

					if ( val != null ) {
						// Should return "auto" instead of 0, use 0 for
						// temporary backwards-compat
						return val === "" || val === "auto" ? "0px" : val;
					}
				}

				if ( val < 0 || val == null ) {
					val = elem.style[ name ];

					// Should return "auto" instead of 0, use 0 for
					// temporary backwards-compat
					return val === "" || val === "auto" ? "0px" : val;
				}

				return typeof val === "string" ? val : val + "px";
			}
		},

		set: function( elem, value ) {
			if ( rnumpx.test( value ) ) {
				// ignore negative width and height values #1599
				value = parseFloat(value);

				if ( value >= 0 ) {
					return value + "px";
				}

			} else {
				return value;
			}
		}
	};
});

if ( !jQuery.support.opacity ) {
	jQuery.cssHooks.opacity = {
		get: function( elem, computed ) {
			// IE uses filters for opacity
			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
				( parseFloat( RegExp.$1 ) / 100 ) + "" :
				computed ? "1" : "";
		},

		set: function( elem, value ) {
			var style = elem.style,
				currentStyle = elem.currentStyle;

			// IE has trouble with opacity if it does not have layout
			// Force it by setting the zoom level
			style.zoom = 1;

			// Set the alpha filter to set the opacity
			var opacity = jQuery.isNaN( value ) ?
				"" :
				"alpha(opacity=" + value * 100 + ")",
				filter = currentStyle && currentStyle.filter || style.filter || "";

			style.filter = ralpha.test( filter ) ?
				filter.replace( ralpha, opacity ) :
				filter + " " + opacity;
		}
	};
}

jQuery(function() {
	// This hook cannot be added until DOM ready because the support test
	// for it is not run until after DOM ready
	if ( !jQuery.support.reliableMarginRight ) {
		jQuery.cssHooks.marginRight = {
			get: function( elem, computed ) {
				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
				// Work around by temporarily setting element display to inline-block
				var ret;
				jQuery.swap( elem, { "display": "inline-block" }, function() {
					if ( computed ) {
						ret = curCSS( elem, "margin-right", "marginRight" );
					} else {
						ret = elem.style.marginRight;
					}
				});
				return ret;
			}
		};
	}
});

if ( document.defaultView && document.defaultView.getComputedStyle ) {
	getComputedStyle = function( elem, name ) {
		var ret, defaultView, computedStyle;

		name = name.replace( rupper, "-$1" ).toLowerCase();

		if ( !(defaultView = elem.ownerDocument.defaultView) ) {
			return undefined;
		}

		if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
			ret = computedStyle.getPropertyValue( name );
			if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
				ret = jQuery.style( elem, name );
			}
		}

		return ret;
	};
}

if ( document.documentElement.currentStyle ) {
	currentStyle = function( elem, name ) {
		var left,
			ret = elem.currentStyle && elem.currentStyle[ name ],
			rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
			style = elem.style;

		// From the awesome hack by Dean Edwards
		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

		// If we're not dealing with a regular pixel number
		// but a number that has a weird ending, we need to convert it to pixels
		if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
			// Remember the original values
			left = style.left;

			// Put in the new values to get a computed value out
			if ( rsLeft ) {
				elem.runtimeStyle.left = elem.currentStyle.left;
			}
			style.left = name === "fontSize" ? "1em" : (ret || 0);
			ret = style.pixelLeft + "px";

			// Revert the changed values
			style.left = left;
			if ( rsLeft ) {
				elem.runtimeStyle.left = rsLeft;
			}
		}

		return ret === "" ? "auto" : ret;
	};
}

curCSS = getComputedStyle || currentStyle;

function getWH( elem, name, extra ) {
	var which = name === "width" ? cssWidth : cssHeight,
		val = name === "width" ? elem.offsetWidth : elem.offsetHeight;

	if ( extra === "border" ) {
		return val;
	}

	jQuery.each( which, function() {
		if ( !extra ) {
			val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0;
		}

		if ( extra === "margin" ) {
			val += parseFloat(jQuery.css( elem, "margin" + this )) || 0;

		} else {
			val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0;
		}
	});

	return val;
}

if ( jQuery.expr && jQuery.expr.filters ) {
	jQuery.expr.filters.hidden = function( elem ) {
		var width = elem.offsetWidth,
			height = elem.offsetHeight;

		return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
	};

	jQuery.expr.filters.visible = function( elem ) {
		return !jQuery.expr.filters.hidden( elem );
	};
}




var r20 = /%20/g,
	rbracket = /\[\]$/,
	rCRLF = /\r?\n/g,
	rhash = /#.*$/,
	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
	rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
	// #7653, #8125, #8152: local protocol detection
	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
	rnoContent = /^(?:GET|HEAD)$/,
	rprotocol = /^\/\//,
	rquery = /\?/,
	rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
	rselectTextarea = /^(?:select|textarea)/i,
	rspacesAjax = /\s+/,
	rts = /([?&])_=[^&]*/,
	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,

	// Keep a copy of the old load method
	_load = jQuery.fn.load,

	/* Prefilters
	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
	 * 2) These are called:
	 *    - BEFORE asking for a transport
	 *    - AFTER param serialization (s.data is a string if s.processData is true)
	 * 3) key is the dataType
	 * 4) the catchall symbol "*" can be used
	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
	 */
	prefilters = {},

	/* Transports bindings
	 * 1) key is the dataType
	 * 2) the catchall symbol "*" can be used
	 * 3) selection will start with transport dataType and THEN go to "*" if needed
	 */
	transports = {},

	// Document location
	ajaxLocation,

	// Document location segments
	ajaxLocParts;

// #8138, IE may throw an exception when accessing
// a field from window.location if document.domain has been set
try {
	ajaxLocation = location.href;
} catch( e ) {
	// Use the href attribute of an A element
	// since IE will modify it given document.location
	ajaxLocation = document.createElement( "a" );
	ajaxLocation.href = "";
	ajaxLocation = ajaxLocation.href;
}

// Segment location into parts
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];

// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {

	// dataTypeExpression is optional and defaults to "*"
	return function( dataTypeExpression, func ) {

		if ( typeof dataTypeExpression !== "string" ) {
			func = dataTypeExpression;
			dataTypeExpression = "*";
		}

		if ( jQuery.isFunction( func ) ) {
			var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
				i = 0,
				length = dataTypes.length,
				dataType,
				list,
				placeBefore;

			// For each dataType in the dataTypeExpression
			for(; i < length; i++ ) {
				dataType = dataTypes[ i ];
				// We control if we're asked to add before
				// any existing element
				placeBefore = /^\+/.test( dataType );
				if ( placeBefore ) {
					dataType = dataType.substr( 1 ) || "*";
				}
				list = structure[ dataType ] = structure[ dataType ] || [];
				// then we add to the structure accordingly
				list[ placeBefore ? "unshift" : "push" ]( func );
			}
		}
	};
}

// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
		dataType /* internal */, inspected /* internal */ ) {

	dataType = dataType || options.dataTypes[ 0 ];
	inspected = inspected || {};

	inspected[ dataType ] = true;

	var list = structure[ dataType ],
		i = 0,
		length = list ? list.length : 0,
		executeOnly = ( structure === prefilters ),
		selection;

	for(; i < length && ( executeOnly || !selection ); i++ ) {
		selection = list[ i ]( options, originalOptions, jqXHR );
		// If we got redirected to another dataType
		// we try there if executing only and not done already
		if ( typeof selection === "string" ) {
			if ( !executeOnly || inspected[ selection ] ) {
				selection = undefined;
			} else {
				options.dataTypes.unshift( selection );
				selection = inspectPrefiltersOrTransports(
						structure, options, originalOptions, jqXHR, selection, inspected );
			}
		}
	}
	// If we're only executing or nothing was selected
	// we try the catchall dataType if not done already
	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
		selection = inspectPrefiltersOrTransports(
				structure, options, originalOptions, jqXHR, "*", inspected );
	}
	// unnecessary when only executing (prefilters)
	// but it'll be ignored by the caller in that case
	return selection;
}

jQuery.fn.extend({
	load: function( url, params, callback ) {
		if ( typeof url !== "string" && _load ) {
			return _load.apply( this, arguments );

		// Don't do a request if no elements are being requested
		} else if ( !this.length ) {
			return this;
		}

		var off = url.indexOf( " " );
		if ( off >= 0 ) {
			var selector = url.slice( off, url.length );
			url = url.slice( 0, off );
		}

		// Default to a GET request
		var type = "GET";

		// If the second parameter was provided
		if ( params ) {
			// If it's a function
			if ( jQuery.isFunction( params ) ) {
				// We assume that it's the callback
				callback = params;
				params = undefined;

			// Otherwise, build a param string
			} else if ( typeof params === "object" ) {
				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
				type = "POST";
			}
		}

		var self = this;

		// Request the remote document
		jQuery.ajax({
			url: url,
			type: type,
			dataType: "html",
			data: params,
			// Complete callback (responseText is used internally)
			complete: function( jqXHR, status, responseText ) {
				// Store the response as specified by the jqXHR object
				responseText = jqXHR.responseText;
				// If successful, inject the HTML into all the matched elements
				if ( jqXHR.isResolved() ) {
					// #4825: Get the actual response in case
					// a dataFilter is present in ajaxSettings
					jqXHR.done(function( r ) {
						responseText = r;
					});
					// See if a selector was specified
					self.html( selector ?
						// Create a dummy div to hold the results
						jQuery("<div>")
							// inject the contents of the document in, removing the scripts
							// to avoid any 'Permission Denied' errors in IE
							.append(responseText.replace(rscript, ""))

							// Locate the specified elements
							.find(selector) :

						// If not, just inject the full result
						responseText );
				}

				if ( callback ) {
					self.each( callback, [ responseText, status, jqXHR ] );
				}
			}
		});

		return this;
	},

	serialize: function() {
		return jQuery.param( this.serializeArray() );
	},

	serializeArray: function() {
		return this.map(function(){
			return this.elements ? jQuery.makeArray( this.elements ) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				( this.checked || rselectTextarea.test( this.nodeName ) ||
					rinput.test( this.type ) );
		})
		.map(function( i, elem ){
			var val = jQuery( this ).val();

			return val == null ?
				null :
				jQuery.isArray( val ) ?
					jQuery.map( val, function( val, i ){
						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
					}) :
					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
		}).get();
	}
});

// Attach a bunch of functions for handling common AJAX events
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
	jQuery.fn[ o ] = function( f ){
		return this.bind( o, f );
	};
});

jQuery.each( [ "get", "post" ], function( i, method ) {
	jQuery[ method ] = function( url, data, callback, type ) {
		// shift arguments if data argument was omitted
		if ( jQuery.isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = undefined;
		}

		return jQuery.ajax({
			type: method,
			url: url,
			data: data,
			success: callback,
			dataType: type
		});
	};
});

jQuery.extend({

	getScript: function( url, callback ) {
		return jQuery.get( url, undefined, callback, "script" );
	},

	getJSON: function( url, data, callback ) {
		return jQuery.get( url, data, callback, "json" );
	},

	// Creates a full fledged settings object into target
	// with both ajaxSettings and settings fields.
	// If target is omitted, writes into ajaxSettings.
	ajaxSetup: function ( target, settings ) {
		if ( !settings ) {
			// Only one parameter, we extend ajaxSettings
			settings = target;
			target = jQuery.extend( true, jQuery.ajaxSettings, settings );
		} else {
			// target was provided, we extend into it
			jQuery.extend( true, target, jQuery.ajaxSettings, settings );
		}
		// Flatten fields we don't want deep extended
		for( var field in { context: 1, url: 1 } ) {
			if ( field in settings ) {
				target[ field ] = settings[ field ];
			} else if( field in jQuery.ajaxSettings ) {
				target[ field ] = jQuery.ajaxSettings[ field ];
			}
		}
		return target;
	},

	ajaxSettings: {
		url: ajaxLocation,
		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
		global: true,
		type: "GET",
		contentType: "application/x-www-form-urlencoded",
		processData: true,
		async: true,
		/*
		timeout: 0,
		data: null,
		dataType: null,
		username: null,
		password: null,
		cache: null,
		traditional: false,
		headers: {},
		*/

		accepts: {
			xml: "application/xml, text/xml",
			html: "text/html",
			text: "text/plain",
			json: "application/json, text/javascript",
			"*": "*/*"
		},

		contents: {
			xml: /xml/,
			html: /html/,
			json: /json/
		},

		responseFields: {
			xml: "responseXML",
			text: "responseText"
		},

		// List of data converters
		// 1) key format is "source_type destination_type" (a single space in-between)
		// 2) the catchall symbol "*" can be used for source_type
		converters: {

			// Convert anything to text
			"* text": window.String,

			// Text to html (true = no transformation)
			"text html": true,

			// Evaluate text as a json expression
			"text json": jQuery.parseJSON,

			// Parse text as xml
			"text xml": jQuery.parseXML
		}
	},

	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
	ajaxTransport: addToPrefiltersOrTransports( transports ),

	// Main method
	ajax: function( url, options ) {

		// If url is an object, simulate pre-1.5 signature
		if ( typeof url === "object" ) {
			options = url;
			url = undefined;
		}

		// Force options to be an object
		options = options || {};

		var // Create the final options object
			s = jQuery.ajaxSetup( {}, options ),
			// Callbacks context
			callbackContext = s.context || s,
			// Context for global events
			// It's the callbackContext if one was provided in the options
			// and if it's a DOM node or a jQuery collection
			globalEventContext = callbackContext !== s &&
				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
						jQuery( callbackContext ) : jQuery.event,
			// Deferreds
			deferred = jQuery.Deferred(),
			completeDeferred = jQuery._Deferred(),
			// Status-dependent callbacks
			statusCode = s.statusCode || {},
			// ifModified key
			ifModifiedKey,
			// Headers (they are sent all at once)
			requestHeaders = {},
			requestHeadersNames = {},
			// Response headers
			responseHeadersString,
			responseHeaders,
			// transport
			transport,
			// timeout handle
			timeoutTimer,
			// Cross-domain detection vars
			parts,
			// The jqXHR state
			state = 0,
			// To know if global events are to be dispatched
			fireGlobals,
			// Loop variable
			i,
			// Fake xhr
			jqXHR = {

				readyState: 0,

				// Caches the header
				setRequestHeader: function( name, value ) {
					if ( !state ) {
						var lname = name.toLowerCase();
						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
						requestHeaders[ name ] = value;
					}
					return this;
				},

				// Raw string
				getAllResponseHeaders: function() {
					return state === 2 ? responseHeadersString : null;
				},

				// Builds headers hashtable if needed
				getResponseHeader: function( key ) {
					var match;
					if ( state === 2 ) {
						if ( !responseHeaders ) {
							responseHeaders = {};
							while( ( match = rheaders.exec( responseHeadersString ) ) ) {
								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
							}
						}
						match = responseHeaders[ key.toLowerCase() ];
					}
					return match === undefined ? null : match;
				},

				// Overrides response content-type header
				overrideMimeType: function( type ) {
					if ( !state ) {
						s.mimeType = type;
					}
					return this;
				},

				// Cancel the request
				abort: function( statusText ) {
					statusText = statusText || "abort";
					if ( transport ) {
						transport.abort( statusText );
					}
					done( 0, statusText );
					return this;
				}
			};

		// Callback for when everything is done
		// It is defined here because jslint complains if it is declared
		// at the end of the function (which would be more logical and readable)
		function done( status, statusText, responses, headers ) {

			// Called once
			if ( state === 2 ) {
				return;
			}

			// State is "done" now
			state = 2;

			// Clear timeout if it exists
			if ( timeoutTimer ) {
				clearTimeout( timeoutTimer );
			}

			// Dereference transport for early garbage collection
			// (no matter how long the jqXHR object will be used)
			transport = undefined;

			// Cache response headers
			responseHeadersString = headers || "";

			// Set readyState
			jqXHR.readyState = status ? 4 : 0;

			var isSuccess,
				success,
				error,
				response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
				lastModified,
				etag;

			// If successful, handle type chaining
			if ( status >= 200 && status < 300 || status === 304 ) {

				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
				if ( s.ifModified ) {

					if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
						jQuery.lastModified[ ifModifiedKey ] = lastModified;
					}
					if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
						jQuery.etag[ ifModifiedKey ] = etag;
					}
				}

				// If not modified
				if ( status === 304 ) {

					statusText = "notmodified";
					isSuccess = true;

				// If we have data
				} else {

					try {
						success = ajaxConvert( s, response );
						statusText = "success";
						isSuccess = true;
					} catch(e) {
						// We have a parsererror
						statusText = "parsererror";
						error = e;
					}
				}
			} else {
				// We extract error from statusText
				// then normalize statusText and status for non-aborts
				error = statusText;
				if( !statusText || status ) {
					statusText = "error";
					if ( status < 0 ) {
						status = 0;
					}
				}
			}

			// Set data for the fake xhr object
			jqXHR.status = status;
			jqXHR.statusText = statusText;

			// Success/Error
			if ( isSuccess ) {
				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
			} else {
				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
			}

			// Status-dependent callbacks
			jqXHR.statusCode( statusCode );
			statusCode = undefined;

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
						[ jqXHR, s, isSuccess ? success : error ] );
			}

			// Complete
			completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
				// Handle the global AJAX counter
				if ( !( --jQuery.active ) ) {
					jQuery.event.trigger( "ajaxStop" );
				}
			}
		}

		// Attach deferreds
		deferred.promise( jqXHR );
		jqXHR.success = jqXHR.done;
		jqXHR.error = jqXHR.fail;
		jqXHR.complete = completeDeferred.done;

		// Status-dependent callbacks
		jqXHR.statusCode = function( map ) {
			if ( map ) {
				var tmp;
				if ( state < 2 ) {
					for( tmp in map ) {
						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
					}
				} else {
					tmp = map[ jqXHR.status ];
					jqXHR.then( tmp, tmp );
				}
			}
			return this;
		};

		// Remove hash character (#7531: and string promotion)
		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
		// We also use the url parameter if available
		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );

		// Extract dataTypes list
		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );

		// Determine if a cross-domain request is in order
		if ( s.crossDomain == null ) {
			parts = rurl.exec( s.url.toLowerCase() );
			s.crossDomain = !!( parts &&
				( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
			);
		}

		// Convert data if not already a string
		if ( s.data && s.processData && typeof s.data !== "string" ) {
			s.data = jQuery.param( s.data, s.traditional );
		}

		// Apply prefilters
		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

		// If request was aborted inside a prefiler, stop there
		if ( state === 2 ) {
			return false;
		}

		// We can fire global events as of now if asked to
		fireGlobals = s.global;

		// Uppercase the type
		s.type = s.type.toUpperCase();

		// Determine if request has content
		s.hasContent = !rnoContent.test( s.type );

		// Watch for a new set of requests
		if ( fireGlobals && jQuery.active++ === 0 ) {
			jQuery.event.trigger( "ajaxStart" );
		}

		// More options handling for requests with no content
		if ( !s.hasContent ) {

			// If data is available, append data to url
			if ( s.data ) {
				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
			}

			// Get ifModifiedKey before adding the anti-cache parameter
			ifModifiedKey = s.url;

			// Add anti-cache in url if needed
			if ( s.cache === false ) {

				var ts = jQuery.now(),
					// try replacing _= if it is there
					ret = s.url.replace( rts, "$1_=" + ts );

				// if nothing was replaced, add timestamp to the end
				s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
			}
		}

		// Set the correct header, if data is being sent
		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
			jqXHR.setRequestHeader( "Content-Type", s.contentType );
		}

		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
		if ( s.ifModified ) {
			ifModifiedKey = ifModifiedKey || s.url;
			if ( jQuery.lastModified[ ifModifiedKey ] ) {
				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
			}
			if ( jQuery.etag[ ifModifiedKey ] ) {
				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
			}
		}

		// Set the Accepts header for the server, depending on the dataType
		jqXHR.setRequestHeader(
			"Accept",
			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
				s.accepts[ "*" ]
		);

		// Check for headers option
		for ( i in s.headers ) {
			jqXHR.setRequestHeader( i, s.headers[ i ] );
		}

		// Allow custom headers/mimetypes and early abort
		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
				// Abort if not done already
				jqXHR.abort();
				return false;

		}

		// Install callbacks on deferreds
		for ( i in { success: 1, error: 1, complete: 1 } ) {
			jqXHR[ i ]( s[ i ] );
		}

		// Get transport
		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

		// If no transport, we auto-abort
		if ( !transport ) {
			done( -1, "No Transport" );
		} else {
			jqXHR.readyState = 1;
			// Send global event
			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
			}
			// Timeout
			if ( s.async && s.timeout > 0 ) {
				timeoutTimer = setTimeout( function(){
					jqXHR.abort( "timeout" );
				}, s.timeout );
			}

			try {
				state = 1;
				transport.send( requestHeaders, done );
			} catch (e) {
				// Propagate exception as error if not done
				if ( status < 2 ) {
					done( -1, e );
				// Simply rethrow otherwise
				} else {
					jQuery.error( e );
				}
			}
		}

		return jqXHR;
	},

	// Serialize an array of form elements or a set of
	// key/values into a query string
	param: function( a, traditional ) {
		var s = [],
			add = function( key, value ) {
				// If value is a function, invoke it and return its value
				value = jQuery.isFunction( value ) ? value() : value;
				s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
			};

		// Set traditional to true for jQuery <= 1.3.2 behavior.
		if ( traditional === undefined ) {
			traditional = jQuery.ajaxSettings.traditional;
		}

		// If an array was passed in, assume that it is an array of form elements.
		if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
			// Serialize the form elements
			jQuery.each( a, function() {
				add( this.name, this.value );
			});

		} else {
			// If traditional, encode the "old" way (the way 1.3.2 or older
			// did it), otherwise encode params recursively.
			for ( var prefix in a ) {
				buildParams( prefix, a[ prefix ], traditional, add );
			}
		}

		// Return the resulting serialization
		return s.join( "&" ).replace( r20, "+" );
	}
});

function buildParams( prefix, obj, traditional, add ) {
	if ( jQuery.isArray( obj ) ) {
		// Serialize array item.
		jQuery.each( obj, function( i, v ) {
			if ( traditional || rbracket.test( prefix ) ) {
				// Treat each array item as a scalar.
				add( prefix, v );

			} else {
				// If array item is non-scalar (array or object), encode its
				// numeric index to resolve deserialization ambiguity issues.
				// Note that rack (as of 1.0.0) can't currently deserialize
				// nested arrays properly, and attempting to do so may cause
				// a server error. Possible fixes are to modify rack's
				// deserialization algorithm or to provide an option or flag
				// to force array serialization to be shallow.
				buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
			}
		});

	} else if ( !traditional && obj != null && typeof obj === "object" ) {
		// Serialize object item.
		for ( var name in obj ) {
			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
		}

	} else {
		// Serialize scalar item.
		add( prefix, obj );
	}
}

// This is still on the jQuery object... for now
// Want to move this to jQuery.ajax some day
jQuery.extend({

	// Counter for holding the number of active queries
	active: 0,

	// Last-Modified header cache for next request
	lastModified: {},
	etag: {}

});

/* Handles responses to an ajax request:
 * - sets all responseXXX fields accordingly
 * - finds the right dataType (mediates between content-type and expected dataType)
 * - returns the corresponding response
 */
function ajaxHandleResponses( s, jqXHR, responses ) {

	var contents = s.contents,
		dataTypes = s.dataTypes,
		responseFields = s.responseFields,
		ct,
		type,
		finalDataType,
		firstDataType;

	// Fill responseXXX fields
	for( type in responseFields ) {
		if ( type in responses ) {
			jqXHR[ responseFields[type] ] = responses[ type ];
		}
	}

	// Remove auto dataType and get content-type in the process
	while( dataTypes[ 0 ] === "*" ) {
		dataTypes.shift();
		if ( ct === undefined ) {
			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
		}
	}

	// Check if we're dealing with a known content-type
	if ( ct ) {
		for ( type in contents ) {
			if ( contents[ type ] && contents[ type ].test( ct ) ) {
				dataTypes.unshift( type );
				break;
			}
		}
	}

	// Check to see if we have a response for the expected dataType
	if ( dataTypes[ 0 ] in responses ) {
		finalDataType = dataTypes[ 0 ];
	} else {
		// Try convertible dataTypes
		for ( type in responses ) {
			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
				finalDataType = type;
				break;
			}
			if ( !firstDataType ) {
				firstDataType = type;
			}
		}
		// Or just use first one
		finalDataType = finalDataType || firstDataType;
	}

	// If we found a dataType
	// We add the dataType to the list if needed
	// and return the corresponding response
	if ( finalDataType ) {
		if ( finalDataType !== dataTypes[ 0 ] ) {
			dataTypes.unshift( finalDataType );
		}
		return responses[ finalDataType ];
	}
}

// Chain conversions given the request and the original response
function ajaxConvert( s, response ) {

	// Apply the dataFilter if provided
	if ( s.dataFilter ) {
		response = s.dataFilter( response, s.dataType );
	}

	var dataTypes = s.dataTypes,
		converters = {},
		i,
		key,
		length = dataTypes.length,
		tmp,
		// Current and previous dataTypes
		current = dataTypes[ 0 ],
		prev,
		// Conversion expression
		conversion,
		// Conversion function
		conv,
		// Conversion functions (transitive conversion)
		conv1,
		conv2;

	// For each dataType in the chain
	for( i = 1; i < length; i++ ) {

		// Create converters map
		// with lowercased keys
		if ( i === 1 ) {
			for( key in s.converters ) {
				if( typeof key === "string" ) {
					converters[ key.toLowerCase() ] = s.converters[ key ];
				}
			}
		}

		// Get the dataTypes
		prev = current;
		current = dataTypes[ i ];

		// If current is auto dataType, update it to prev
		if( current === "*" ) {
			current = prev;
		// If no auto and dataTypes are actually different
		} else if ( prev !== "*" && prev !== current ) {

			// Get the converter
			conversion = prev + " " + current;
			conv = converters[ conversion ] || converters[ "* " + current ];

			// If there is no direct converter, search transitively
			if ( !conv ) {
				conv2 = undefined;
				for( conv1 in converters ) {
					tmp = conv1.split( " " );
					if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
						conv2 = converters[ tmp[1] + " " + current ];
						if ( conv2 ) {
							conv1 = converters[ conv1 ];
							if ( conv1 === true ) {
								conv = conv2;
							} else if ( conv2 === true ) {
								conv = conv1;
							}
							break;
						}
					}
				}
			}
			// If we found no converter, dispatch an error
			if ( !( conv || conv2 ) ) {
				jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
			}
			// If found converter is not an equivalence
			if ( conv !== true ) {
				// Convert with 1 or 2 converters accordingly
				response = conv ? conv( response ) : conv2( conv1(response) );
			}
		}
	}
	return response;
}




var jsc = jQuery.now(),
	jsre = /(\=)\?(&|$)|\?\?/i;

// Default jsonp settings
jQuery.ajaxSetup({
	jsonp: "callback",
	jsonpCallback: function() {
		return jQuery.expando + "_" + ( jsc++ );
	}
});

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

	var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
		( typeof s.data === "string" );

	if ( s.dataTypes[ 0 ] === "jsonp" ||
		s.jsonp !== false && ( jsre.test( s.url ) ||
				inspectData && jsre.test( s.data ) ) ) {

		var responseContainer,
			jsonpCallback = s.jsonpCallback =
				jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
			previous = window[ jsonpCallback ],
			url = s.url,
			data = s.data,
			replace = "$1" + jsonpCallback + "$2";

		if ( s.jsonp !== false ) {
			url = url.replace( jsre, replace );
			if ( s.url === url ) {
				if ( inspectData ) {
					data = data.replace( jsre, replace );
				}
				if ( s.data === data ) {
					// Add callback manually
					url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
				}
			}
		}

		s.url = url;
		s.data = data;

		// Install callback
		window[ jsonpCallback ] = function( response ) {
			responseContainer = [ response ];
		};

		// Clean-up function
		jqXHR.always(function() {
			// Set callback back to previous value
			window[ jsonpCallback ] = previous;
			// Call if it was a function and we have a response
			if ( responseContainer && jQuery.isFunction( previous ) ) {
				window[ jsonpCallback ]( responseContainer[ 0 ] );
			}
		});

		// Use data converter to retrieve json after script execution
		s.converters["script json"] = function() {
			if ( !responseContainer ) {
				jQuery.error( jsonpCallback + " was not called" );
			}
			return responseContainer[ 0 ];
		};

		// force json dataType
		s.dataTypes[ 0 ] = "json";

		// Delegate to script
		return "script";
	}
});




// Install script dataType
jQuery.ajaxSetup({
	accepts: {
		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
	},
	contents: {
		script: /javascript|ecmascript/
	},
	converters: {
		"text script": function( text ) {
			jQuery.globalEval( text );
			return text;
		}
	}
});

// Handle cache's special case and global
jQuery.ajaxPrefilter( "script", function( s ) {
	if ( s.cache === undefined ) {
		s.cache = false;
	}
	if ( s.crossDomain ) {
		s.type = "GET";
		s.global = false;
	}
});

// Bind script tag hack transport
jQuery.ajaxTransport( "script", function(s) {

	// This transport only deals with cross domain requests
	if ( s.crossDomain ) {

		var script,
			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;

		return {

			send: function( _, callback ) {

				script = document.createElement( "script" );

				script.async = "async";

				if ( s.scriptCharset ) {
					script.charset = s.scriptCharset;
				}

				script.src = s.url;

				// Attach handlers for all browsers
				script.onload = script.onreadystatechange = function( _, isAbort ) {

					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

						// Handle memory leak in IE
						script.onload = script.onreadystatechange = null;

						// Remove the script
						if ( head && script.parentNode ) {
							head.removeChild( script );
						}

						// Dereference the script
						script = undefined;

						// Callback if not abort
						if ( !isAbort ) {
							callback( 200, "success" );
						}
					}
				};
				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
				// This arises when a base node is used (#2709 and #4378).
				head.insertBefore( script, head.firstChild );
			},

			abort: function() {
				if ( script ) {
					script.onload( 0, 1 );
				}
			}
		};
	}
});




var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
	xhrOnUnloadAbort = window.ActiveXObject ? function() {
		// Abort all pending requests
		for ( var key in xhrCallbacks ) {
			xhrCallbacks[ key ]( 0, 1 );
		}
	} : false,
	xhrId = 0,
	xhrCallbacks;

// Functions to create xhrs
function createStandardXHR() {
	try {
		return new window.XMLHttpRequest();
	} catch( e ) {}
}

function createActiveXHR() {
	try {
		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
	} catch( e ) {}
}

// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject ?
	/* Microsoft failed to properly
	 * implement the XMLHttpRequest in IE7 (can't request local files),
	 * so we use the ActiveXObject when it is available
	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
	 * we need a fallback.
	 */
	function() {
		return !this.isLocal && createStandardXHR() || createActiveXHR();
	} :
	// For all other browsers, use the standard XMLHttpRequest object
	createStandardXHR;

// Determine support properties
(function( xhr ) {
	jQuery.extend( jQuery.support, {
		ajax: !!xhr,
		cors: !!xhr && ( "withCredentials" in xhr )
	});
})( jQuery.ajaxSettings.xhr() );

// Create transport if the browser can provide an xhr
if ( jQuery.support.ajax ) {

	jQuery.ajaxTransport(function( s ) {
		// Cross domain only allowed if supported through XMLHttpRequest
		if ( !s.crossDomain || jQuery.support.cors ) {

			var callback;

			return {
				send: function( headers, complete ) {

					// Get a new xhr
					var xhr = s.xhr(),
						handle,
						i;

					// Open the socket
					// Passing null username, generates a login popup on Opera (#2865)
					if ( s.username ) {
						xhr.open( s.type, s.url, s.async, s.username, s.password );
					} else {
						xhr.open( s.type, s.url, s.async );
					}

					// Apply custom fields if provided
					if ( s.xhrFields ) {
						for ( i in s.xhrFields ) {
							xhr[ i ] = s.xhrFields[ i ];
						}
					}

					// Override mime type if needed
					if ( s.mimeType && xhr.overrideMimeType ) {
						xhr.overrideMimeType( s.mimeType );
					}

					// X-Requested-With header
					// For cross-domain requests, seeing as conditions for a preflight are
					// akin to a jigsaw puzzle, we simply never set it to be sure.
					// (it can always be set on a per-request basis or even using ajaxSetup)
					// For same-domain requests, won't change header if already provided.
					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
						headers[ "X-Requested-With" ] = "XMLHttpRequest";
					}

					// Need an extra try/catch for cross domain requests in Firefox 3
					try {
						for ( i in headers ) {
							xhr.setRequestHeader( i, headers[ i ] );
						}
					} catch( _ ) {}

					// Do send the request
					// This may raise an exception which is actually
					// handled in jQuery.ajax (so no try/catch here)
					xhr.send( ( s.hasContent && s.data ) || null );

					// Listener
					callback = function( _, isAbort ) {

						var status,
							statusText,
							responseHeaders,
							responses,
							xml;

						// Firefox throws exceptions when accessing properties
						// of an xhr when a network error occured
						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
						try {

							// Was never called and is aborted or complete
							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {

								// Only called once
								callback = undefined;

								// Do not keep as active anymore
								if ( handle ) {
									xhr.onreadystatechange = jQuery.noop;
									if ( xhrOnUnloadAbort ) {
										delete xhrCallbacks[ handle ];
									}
								}

								// If it's an abort
								if ( isAbort ) {
									// Abort it manually if needed
									if ( xhr.readyState !== 4 ) {
										xhr.abort();
									}
								} else {
									status = xhr.status;
									responseHeaders = xhr.getAllResponseHeaders();
									responses = {};
									xml = xhr.responseXML;

									// Construct response list
									if ( xml && xml.documentElement /* #4958 */ ) {
										responses.xml = xml;
									}
									responses.text = xhr.responseText;

									// Firefox throws an exception when accessing
									// statusText for faulty cross-domain requests
									try {
										statusText = xhr.statusText;
									} catch( e ) {
										// We normalize with Webkit giving an empty statusText
										statusText = "";
									}

									// Filter status for non standard behaviors

									// If the request is local and we have data: assume a success
									// (success with no data won't get notified, that's the best we
									// can do given current implementations)
									if ( !status && s.isLocal && !s.crossDomain ) {
										status = responses.text ? 200 : 404;
									// IE - #1450: sometimes returns 1223 when it should be 204
									} else if ( status === 1223 ) {
										status = 204;
									}
								}
							}
						} catch( firefoxAccessException ) {
							if ( !isAbort ) {
								complete( -1, firefoxAccessException );
							}
						}

						// Call complete if needed
						if ( responses ) {
							complete( status, statusText, responses, responseHeaders );
						}
					};

					// if we're in sync mode or it's in cache
					// and has been retrieved directly (IE6 & IE7)
					// we need to manually fire the callback
					if ( !s.async || xhr.readyState === 4 ) {
						callback();
					} else {
						handle = ++xhrId;
						if ( xhrOnUnloadAbort ) {
							// Create the active xhrs callbacks list if needed
							// and attach the unload handler
							if ( !xhrCallbacks ) {
								xhrCallbacks = {};
								jQuery( window ).unload( xhrOnUnloadAbort );
							}
							// Add to list of active xhrs callbacks
							xhrCallbacks[ handle ] = callback;
						}
						xhr.onreadystatechange = callback;
					}
				},

				abort: function() {
					if ( callback ) {
						callback(0,1);
					}
				}
			};
		}
	});
}




var elemdisplay = {},
	iframe, iframeDoc,
	rfxtypes = /^(?:toggle|show|hide)$/,
	rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
	timerId,
	fxAttrs = [
		// height animations
		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
		// width animations
		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
		// opacity animations
		[ "opacity" ]
	],
	fxNow,
	requestAnimationFrame = window.webkitRequestAnimationFrame ||
	    window.mozRequestAnimationFrame ||
	    window.oRequestAnimationFrame;

jQuery.fn.extend({
	show: function( speed, easing, callback ) {
		var elem, display;

		if ( speed || speed === 0 ) {
			return this.animate( genFx("show", 3), speed, easing, callback);

		} else {
			for ( var i = 0, j = this.length; i < j; i++ ) {
				elem = this[i];

				if ( elem.style ) {
					display = elem.style.display;

					// Reset the inline display of this element to learn if it is
					// being hidden by cascaded rules or not
					if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
						display = elem.style.display = "";
					}

					// Set elements which have been overridden with display: none
					// in a stylesheet to whatever the default browser style is
					// for such an element
					if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
						jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
					}
				}
			}

			// Set the display of most of the elements in a second loop
			// to avoid the constant reflow
			for ( i = 0; i < j; i++ ) {
				elem = this[i];

				if ( elem.style ) {
					display = elem.style.display;

					if ( display === "" || display === "none" ) {
						elem.style.display = jQuery._data(elem, "olddisplay") || "";
					}
				}
			}

			return this;
		}
	},

	hide: function( speed, easing, callback ) {
		if ( speed || speed === 0 ) {
			return this.animate( genFx("hide", 3), speed, easing, callback);

		} else {
			for ( var i = 0, j = this.length; i < j; i++ ) {
				if ( this[i].style ) {
					var display = jQuery.css( this[i], "display" );

					if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
						jQuery._data( this[i], "olddisplay", display );
					}
				}
			}

			// Set the display of the elements in a second loop
			// to avoid the constant reflow
			for ( i = 0; i < j; i++ ) {
				if ( this[i].style ) {
					this[i].style.display = "none";
				}
			}

			return this;
		}
	},

	// Save the old toggle function
	_toggle: jQuery.fn.toggle,

	toggle: function( fn, fn2, callback ) {
		var bool = typeof fn === "boolean";

		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
			this._toggle.apply( this, arguments );

		} else if ( fn == null || bool ) {
			this.each(function() {
				var state = bool ? fn : jQuery(this).is(":hidden");
				jQuery(this)[ state ? "show" : "hide" ]();
			});

		} else {
			this.animate(genFx("toggle", 3), fn, fn2, callback);
		}

		return this;
	},

	fadeTo: function( speed, to, easing, callback ) {
		return this.filter(":hidden").css("opacity", 0).show().end()
					.animate({opacity: to}, speed, easing, callback);
	},

	animate: function( prop, speed, easing, callback ) {
		var optall = jQuery.speed(speed, easing, callback);

		if ( jQuery.isEmptyObject( prop ) ) {
			return this.each( optall.complete, [ false ] );
		}

		return this[ optall.queue === false ? "each" : "queue" ](function() {
			// XXX 'this' does not always have a nodeName when running the
			// test suite

			if ( optall.queue === false ) {
				jQuery._mark( this );
			}

			var opt = jQuery.extend({}, optall),
				isElement = this.nodeType === 1,
				hidden = isElement && jQuery(this).is(":hidden"),
				name, val, p,
				display, e,
				parts, start, end, unit;

			// will store per property easing and be used to determine when an animation is complete
			opt.animatedProperties = {};

			for ( p in prop ) {

				// property name normalization
				name = jQuery.camelCase( p );
				if ( p !== name ) {
					prop[ name ] = prop[ p ];
					delete prop[ p ];
				}

				val = prop[name];

				if ( val === "hide" && hidden || val === "show" && !hidden ) {
					return opt.complete.call(this);
				}

				if ( isElement && ( name === "height" || name === "width" ) ) {
					// Make sure that nothing sneaks out
					// Record all 3 overflow attributes because IE does not
					// change the overflow attribute when overflowX and
					// overflowY are set to the same value
					opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];

					// Set display property to inline-block for height/width
					// animations on inline elements that are having width/height
					// animated
					if ( jQuery.css( this, "display" ) === "inline" &&
							jQuery.css( this, "float" ) === "none" ) {
						if ( !jQuery.support.inlineBlockNeedsLayout ) {
							this.style.display = "inline-block";

						} else {
							display = defaultDisplay(this.nodeName);

							// inline-level elements accept inline-block;
							// block-level elements need to be inline with layout
							if ( display === "inline" ) {
								this.style.display = "inline-block";

							} else {
								this.style.display = "inline";
								this.style.zoom = 1;
							}
						}
					}
				}

				// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
				opt.animatedProperties[name] = jQuery.isArray( val ) ?
					val[1]:
					opt.specialEasing && opt.specialEasing[name] || opt.easing || 'swing';
			}

			if ( opt.overflow != null ) {
				this.style.overflow = "hidden";
			}

			for ( p in prop ) {
				e = new jQuery.fx( this, opt, p );

				val = prop[p];

				if ( rfxtypes.test(val) ) {
					e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();

				} else {
					parts = rfxnum.exec(val);
					start = e.cur();

					if ( parts ) {
						end = parseFloat( parts[2] );
						unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" );

						// We need to compute starting value
						if ( unit !== "px" ) {
							jQuery.style( this, p, (end || 1) + unit);
							start = ((end || 1) / e.cur()) * start;
							jQuery.style( this, p, start + unit);
						}

						// If a +=/-= token was provided, we're doing a relative animation
						if ( parts[1] ) {
							end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
						}

						e.custom( start, end, unit );

					} else {
						e.custom( start, val, "" );
					}
				}
			}

			// For JS strict compliance
			return true;
		});
	},

	stop: function( clearQueue, gotoEnd ) {
		if ( clearQueue ) {
			this.queue([]);
		}

		this.each(function() {
			var timers = jQuery.timers,
				i = timers.length;
			// clear marker counters if we know they won't be
			if ( !gotoEnd ) {
				jQuery._unmark( true, this );
			}
			// go in reverse order so anything added to the queue during the loop is ignored
			while ( i-- ) {
				if ( timers[i].elem === this ) {
					if (gotoEnd) {
						// force the next step to be the last
						timers[i](true);
					}

					timers.splice(i, 1);
				}
			}
		});

		// start the next in the queue if the last step wasn't forced
		if ( !gotoEnd ) {
			this.dequeue();
		}

		return this;
	}

});

// Animations created synchronously will run synchronously
function createFxNow() {
	setTimeout( clearFxNow, 0 );
	return ( fxNow = jQuery.now() );
}

function clearFxNow() {
	fxNow = undefined;
}

// Generate parameters to create a standard animation
function genFx( type, num ) {
	var obj = {};

	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
		obj[ this ] = type;
	});

	return obj;
}

// Generate shortcuts for custom animations
jQuery.each({
	slideDown: genFx("show", 1),
	slideUp: genFx("hide", 1),
	slideToggle: genFx("toggle", 1),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" },
	fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return this.animate( props, speed, easing, callback );
	};
});

jQuery.extend({
	speed: function( speed, easing, fn ) {
		var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
			complete: fn || !fn && easing ||
				jQuery.isFunction( speed ) && speed,
			duration: speed,
			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
		};

		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
			opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;

		// Queueing
		opt.old = opt.complete;
		opt.complete = function( noUnmark ) {
			if ( opt.queue !== false ) {
				jQuery.dequeue( this );
			} else if ( noUnmark !== false ) {
				jQuery._unmark( this );
			}

			if ( jQuery.isFunction( opt.old ) ) {
				opt.old.call( this );
			}
		};

		return opt;
	},

	easing: {
		linear: function( p, n, firstNum, diff ) {
			return firstNum + diff * p;
		},
		swing: function( p, n, firstNum, diff ) {
			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
		}
	},

	timers: [],

	fx: function( elem, options, prop ) {
		this.options = options;
		this.elem = elem;
		this.prop = prop;

		options.orig = options.orig || {};
	}

});

jQuery.fx.prototype = {
	// Simple function for setting a style value
	update: function() {
		if ( this.options.step ) {
			this.options.step.call( this.elem, this.now, this );
		}

		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
	},

	// Get the current size
	cur: function() {
		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
			return this.elem[ this.prop ];
		}

		var parsed,
			r = jQuery.css( this.elem, this.prop );
		// Empty strings, null, undefined and "auto" are converted to 0,
		// complex values such as "rotate(1rad)" are returned as is,
		// simple values such as "10px" are parsed to Float.
		return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
	},

	// Start an animation from one number to another
	custom: function( from, to, unit ) {
		var self = this,
			fx = jQuery.fx,
			raf;

		this.startTime = fxNow || createFxNow();
		this.start = from;
		this.end = to;
		this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
		this.now = this.start;
		this.pos = this.state = 0;

		function t( gotoEnd ) {
			return self.step(gotoEnd);
		}

		t.elem = this.elem;

		if ( t() && jQuery.timers.push(t) && !timerId ) {
			// Use requestAnimationFrame instead of setInterval if available
			if ( requestAnimationFrame ) {
				timerId = 1;
				raf = function() {
					// When timerId gets set to null at any point, this stops
					if ( timerId ) {
						requestAnimationFrame( raf );
						fx.tick();
					}
				};
				requestAnimationFrame( raf );
			} else {
				timerId = setInterval( fx.tick, fx.interval );
			}
		}
	},

	// Simple 'show' function
	show: function() {
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
		this.options.show = true;

		// Begin the animation
		// Make sure that we start at a small width/height to avoid any
		// flash of content
		this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());

		// Start by showing the element
		jQuery( this.elem ).show();
	},

	// Simple 'hide' function
	hide: function() {
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
		this.options.hide = true;

		// Begin the animation
		this.custom(this.cur(), 0);
	},

	// Each step of an animation
	step: function( gotoEnd ) {
		var t = fxNow || createFxNow(),
			done = true,
			elem = this.elem,
			options = this.options,
			i, n;

		if ( gotoEnd || t >= options.duration + this.startTime ) {
			this.now = this.end;
			this.pos = this.state = 1;
			this.update();

			options.animatedProperties[ this.prop ] = true;

			for ( i in options.animatedProperties ) {
				if ( options.animatedProperties[i] !== true ) {
					done = false;
				}
			}

			if ( done ) {
				// Reset the overflow
				if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {

					jQuery.each( [ "", "X", "Y" ], function (index, value) {
						elem.style[ "overflow" + value ] = options.overflow[index];
					});
				}

				// Hide the element if the "hide" operation was done
				if ( options.hide ) {
					jQuery(elem).hide();
				}

				// Reset the properties, if the item has been hidden or shown
				if ( options.hide || options.show ) {
					for ( var p in options.animatedProperties ) {
						jQuery.style( elem, p, options.orig[p] );
					}
				}

				// Execute the complete function
				options.complete.call( elem );
			}

			return false;

		} else {
			// classical easing cannot be used with an Infinity duration
			if ( options.duration == Infinity ) {
				this.now = t;
			} else {
				n = t - this.startTime;

				this.state = n / options.duration;
				// Perform the easing function, defaults to swing
				this.pos = jQuery.easing[options.animatedProperties[this.prop]](this.state, n, 0, 1, options.duration);
				this.now = this.start + ((this.end - this.start) * this.pos);
			}
			// Perform the next step of the animation
			this.update();
		}

		return true;
	}
};

jQuery.extend( jQuery.fx, {
	tick: function() {
		var timers = jQuery.timers,
			i = timers.length;
		while ( i-- ) {
			if ( !timers[i]() ) {
				timers.splice(i, 1);
			}
		}

		if ( !timers.length ) {
			jQuery.fx.stop();
		}
	},

	interval: 13,

	stop: function() {
		clearInterval( timerId );
		timerId = null;
	},

	speeds: {
		slow: 600,
		fast: 200,
		// Default speed
		_default: 400
	},

	step: {
		opacity: function( fx ) {
			jQuery.style( fx.elem, "opacity", fx.now );
		},

		_default: function( fx ) {
			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
				fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
			} else {
				fx.elem[ fx.prop ] = fx.now;
			}
		}
	}
});

if ( jQuery.expr && jQuery.expr.filters ) {
	jQuery.expr.filters.animated = function( elem ) {
		return jQuery.grep(jQuery.timers, function( fn ) {
			return elem === fn.elem;
		}).length;
	};
}

// Try to restore the default display value of an element
function defaultDisplay( nodeName ) {

	if ( !elemdisplay[ nodeName ] ) {

		var elem = jQuery( "<" + nodeName + ">" ).appendTo( "body" ),
			display = elem.css( "display" );

		elem.remove();

		// If the simple way fails,
		// get element's real default display by attaching it to a temp iframe
		if ( display === "none" || display === "" ) {
			// No iframe to use yet, so create it
			if ( !iframe ) {
				iframe = document.createElement( "iframe" );
				iframe.frameBorder = iframe.width = iframe.height = 0;
			}

			document.body.appendChild( iframe );

			// Create a cacheable copy of the iframe document on first call.
			// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake html
			// document to it, Webkit & Firefox won't allow reusing the iframe document
			if ( !iframeDoc || !iframe.createElement ) {
				iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
				iframeDoc.write( "<!doctype><html><body></body></html>" );
			}

			elem = iframeDoc.createElement( nodeName );

			iframeDoc.body.appendChild( elem );

			display = jQuery.css( elem, "display" );

			document.body.removeChild( iframe );
		}

		// Store the correct default display
		elemdisplay[ nodeName ] = display;
	}

	return elemdisplay[ nodeName ];
}




var rtable = /^t(?:able|d|h)$/i,
	rroot = /^(?:body|html)$/i;

if ( "getBoundingClientRect" in document.documentElement ) {
	jQuery.fn.offset = function( options ) {
		var elem = this[0], box;

		if ( options ) {
			return this.each(function( i ) {
				jQuery.offset.setOffset( this, options, i );
			});
		}

		if ( !elem || !elem.ownerDocument ) {
			return null;
		}

		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		try {
			box = elem.getBoundingClientRect();
		} catch(e) {}

		var doc = elem.ownerDocument,
			docElem = doc.documentElement;

		// Make sure we're not dealing with a disconnected DOM node
		if ( !box || !jQuery.contains( docElem, elem ) ) {
			return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
		}

		var body = doc.body,
			win = getWindow(doc),
			clientTop  = docElem.clientTop  || body.clientTop  || 0,
			clientLeft = docElem.clientLeft || body.clientLeft || 0,
			scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
			scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
			top  = box.top  + scrollTop  - clientTop,
			left = box.left + scrollLeft - clientLeft;

		return { top: top, left: left };
	};

} else {
	jQuery.fn.offset = function( options ) {
		var elem = this[0];

		if ( options ) {
			return this.each(function( i ) {
				jQuery.offset.setOffset( this, options, i );
			});
		}

		if ( !elem || !elem.ownerDocument ) {
			return null;
		}

		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		jQuery.offset.initialize();

		var computedStyle,
			offsetParent = elem.offsetParent,
			prevOffsetParent = elem,
			doc = elem.ownerDocument,
			docElem = doc.documentElement,
			body = doc.body,
			defaultView = doc.defaultView,
			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
			top = elem.offsetTop,
			left = elem.offsetLeft;

		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
			if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
				break;
			}

			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
			top  -= elem.scrollTop;
			left -= elem.scrollLeft;

			if ( elem === offsetParent ) {
				top  += elem.offsetTop;
				left += elem.offsetLeft;

				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
				}

				prevOffsetParent = offsetParent;
				offsetParent = elem.offsetParent;
			}

			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
			}

			prevComputedStyle = computedStyle;
		}

		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
			top  += body.offsetTop;
			left += body.offsetLeft;
		}

		if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
			top  += Math.max( docElem.scrollTop, body.scrollTop );
			left += Math.max( docElem.scrollLeft, body.scrollLeft );
		}

		return { top: top, left: left };
	};
}

jQuery.offset = {
	initialize: function() {
		var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
			html = "<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>";

		jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );

		container.innerHTML = html;
		body.insertBefore( container, body.firstChild );
		innerDiv = container.firstChild;
		checkDiv = innerDiv.firstChild;
		td = innerDiv.nextSibling.firstChild.firstChild;

		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);

		checkDiv.style.position = "fixed";
		checkDiv.style.top = "20px";

		// safari subtracts parent border width here which is 5px
		this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
		checkDiv.style.position = checkDiv.style.top = "";

		innerDiv.style.overflow = "hidden";
		innerDiv.style.position = "relative";

		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);

		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);

		body.removeChild( container );
		jQuery.offset.initialize = jQuery.noop;
	},

	bodyOffset: function( body ) {
		var top = body.offsetTop,
			left = body.offsetLeft;

		jQuery.offset.initialize();

		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
		}

		return { top: top, left: left };
	},

	setOffset: function( elem, options, i ) {
		var position = jQuery.css( elem, "position" );

		// set position first, in-case top/left are set even on static elem
		if ( position === "static" ) {
			elem.style.position = "relative";
		}

		var curElem = jQuery( elem ),
			curOffset = curElem.offset(),
			curCSSTop = jQuery.css( elem, "top" ),
			curCSSLeft = jQuery.css( elem, "left" ),
			calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
			props = {}, curPosition = {}, curTop, curLeft;

		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
		if ( calculatePosition ) {
			curPosition = curElem.position();
			curTop = curPosition.top;
			curLeft = curPosition.left;
		} else {
			curTop = parseFloat( curCSSTop ) || 0;
			curLeft = parseFloat( curCSSLeft ) || 0;
		}

		if ( jQuery.isFunction( options ) ) {
			options = options.call( elem, i, curOffset );
		}

		if (options.top != null) {
			props.top = (options.top - curOffset.top) + curTop;
		}
		if (options.left != null) {
			props.left = (options.left - curOffset.left) + curLeft;
		}

		if ( "using" in options ) {
			options.using.call( elem, props );
		} else {
			curElem.css( props );
		}
	}
};


jQuery.fn.extend({
	position: function() {
		if ( !this[0] ) {
			return null;
		}

		var elem = this[0],

		// Get *real* offsetParent
		offsetParent = this.offsetParent(),

		// Get correct offsets
		offset       = this.offset(),
		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();

		// Subtract element margins
		// note: when an element has margin: auto the offsetLeft and marginLeft
		// are the same in Safari causing offset.left to incorrectly be 0
		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;

		// Add offsetParent borders
		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;

		// Subtract the two offsets
		return {
			top:  offset.top  - parentOffset.top,
			left: offset.left - parentOffset.left
		};
	},

	offsetParent: function() {
		return this.map(function() {
			var offsetParent = this.offsetParent || document.body;
			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
				offsetParent = offsetParent.offsetParent;
			}
			return offsetParent;
		});
	}
});


// Create scrollLeft and scrollTop methods
jQuery.each( ["Left", "Top"], function( i, name ) {
	var method = "scroll" + name;

	jQuery.fn[ method ] = function( val ) {
		var elem, win;

		if ( val === undefined ) {
			elem = this[ 0 ];

			if ( !elem ) {
				return null;
			}

			win = getWindow( elem );

			// Return the scroll offset
			return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
				jQuery.support.boxModel && win.document.documentElement[ method ] ||
					win.document.body[ method ] :
				elem[ method ];
		}

		// Set the scroll offset
		return this.each(function() {
			win = getWindow( this );

			if ( win ) {
				win.scrollTo(
					!i ? val : jQuery( win ).scrollLeft(),
					 i ? val : jQuery( win ).scrollTop()
				);

			} else {
				this[ method ] = val;
			}
		});
	};
});

function getWindow( elem ) {
	return jQuery.isWindow( elem ) ?
		elem :
		elem.nodeType === 9 ?
			elem.defaultView || elem.parentWindow :
			false;
}




// Create innerHeight, innerWidth, outerHeight and outerWidth methods
jQuery.each([ "Height", "Width" ], function( i, name ) {

	var type = name.toLowerCase();

	// innerHeight and innerWidth
	jQuery.fn["inner" + name] = function() {
		return this[0] ?
			parseFloat( jQuery.css( this[0], type, "padding" ) ) :
			null;
	};

	// outerHeight and outerWidth
	jQuery.fn["outer" + name] = function( margin ) {
		return this[0] ?
			parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) :
			null;
	};

	jQuery.fn[ type ] = function( size ) {
		// Get window width or height
		var elem = this[0];
		if ( !elem ) {
			return size == null ? null : this;
		}

		if ( jQuery.isFunction( size ) ) {
			return this.each(function( i ) {
				var self = jQuery( this );
				self[ type ]( size.call( this, i, self[ type ]() ) );
			});
		}

		if ( jQuery.isWindow( elem ) ) {
			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
			// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
			var docElemProp = elem.document.documentElement[ "client" + name ];
			return elem.document.compatMode === "CSS1Compat" && docElemProp ||
				elem.document.body[ "client" + name ] || docElemProp;

		// Get document width or height
		} else if ( elem.nodeType === 9 ) {
			// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
			return Math.max(
				elem.documentElement["client" + name],
				elem.body["scroll" + name], elem.documentElement["scroll" + name],
				elem.body["offset" + name], elem.documentElement["offset" + name]
			);

		// Get or set width or height on the element
		} else if ( size === undefined ) {
			var orig = jQuery.css( elem, type ),
				ret = parseFloat( orig );

			return jQuery.isNaN( ret ) ? orig : ret;

		// Set the width or height on the element (default to pixels if value is unitless)
		} else {
			return this.css( type, typeof size === "string" ? size : size + "px" );
		}
	};

});


window.jQuery = window.$ = jQuery;
})(window);
/*!
 * jQuery UI 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * licensed under MIT 
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI
 */
(function( $, undefined ) {

// prevent duplicate loading
// this is only a problem because we proxy existing functions
// and we don't want to double proxy them
$.ui = $.ui || {};
if ( $.ui.version ) {
	return;
}

$.extend( $.ui, {
	version: "1.8.12",

	keyCode: {
		ALT: 18,
		BACKSPACE: 8,
		CAPS_LOCK: 20,
		COMMA: 188,
		COMMAND: 91,
		COMMAND_LEFT: 91, // COMMAND
		COMMAND_RIGHT: 93,
		CONTROL: 17,
		DELETE: 46,
		DOWN: 40,
		END: 35,
		ENTER: 13,
		ESCAPE: 27,
		HOME: 36,
		INSERT: 45,
		LEFT: 37,
		MENU: 93, // COMMAND_RIGHT
		NUMPAD_ADD: 107,
		NUMPAD_DECIMAL: 110,
		NUMPAD_DIVIDE: 111,
		NUMPAD_ENTER: 108,
		NUMPAD_MULTIPLY: 106,
		NUMPAD_SUBTRACT: 109,
		PAGE_DOWN: 34,
		PAGE_UP: 33,
		PERIOD: 190,
		RIGHT: 39,
		SHIFT: 16,
		SPACE: 32,
		TAB: 9,
		UP: 38,
		WINDOWS: 91 // COMMAND
	}
});

// plugins
$.fn.extend({
	_focus: $.fn.focus,
	focus: function( delay, fn ) {
		return typeof delay === "number" ?
			this.each(function() {
				var elem = this;
				setTimeout(function() {
					$( elem ).focus();
					if ( fn ) {
						fn.call( elem );
					}
				}, delay );
			}) :
			this._focus.apply( this, arguments );
	},

	scrollParent: function() {
		var scrollParent;
		if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
			scrollParent = this.parents().filter(function() {
				return (/(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));
			}).eq(0);
		} else {
			scrollParent = this.parents().filter(function() {
				return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
			}).eq(0);
		}

		return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
	},

	zIndex: function( zIndex ) {
		if ( zIndex !== undefined ) {
			return this.css( "zIndex", zIndex );
		}

		if ( this.length ) {
			var elem = $( this[ 0 ] ), position, value;
			while ( elem.length && elem[ 0 ] !== document ) {
				// Ignore z-index if position is set to a value where z-index is ignored by the browser
				// This makes behavior of this function consistent across browsers
				// WebKit always returns auto if the element is positioned
				position = elem.css( "position" );
				if ( position === "absolute" || position === "relative" || position === "fixed" ) {
					// IE returns 0 when zIndex is not specified
					// other browsers return a string
					// we ignore the case of nested elements with an explicit value of 0
					// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
					value = parseInt( elem.css( "zIndex" ), 10 );
					if ( !isNaN( value ) && value !== 0 ) {
						return value;
					}
				}
				elem = elem.parent();
			}
		}

		return 0;
	},

	disableSelection: function() {
		return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
			".ui-disableSelection", function( event ) {
				event.preventDefault();
			});
	},

	enableSelection: function() {
		return this.unbind( ".ui-disableSelection" );
	}
});

$.each( [ "Width", "Height" ], function( i, name ) {
	var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
		type = name.toLowerCase(),
		orig = {
			innerWidth: $.fn.innerWidth,
			innerHeight: $.fn.innerHeight,
			outerWidth: $.fn.outerWidth,
			outerHeight: $.fn.outerHeight
		};

	function reduce( elem, size, border, margin ) {
		$.each( side, function() {
			size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
			if ( border ) {
				size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
			}
			if ( margin ) {
				size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
			}
		});
		return size;
	}

	$.fn[ "inner" + name ] = function( size ) {
		if ( size === undefined ) {
			return orig[ "inner" + name ].call( this );
		}

		return this.each(function() {
			$( this ).css( type, reduce( this, size ) + "px" );
		});
	};

	$.fn[ "outer" + name] = function( size, margin ) {
		if ( typeof size !== "number" ) {
			return orig[ "outer" + name ].call( this, size );
		}

		return this.each(function() {
			$( this).css( type, reduce( this, size, true, margin ) + "px" );
		});
	};
});

// selectors
function visible( element ) {
	return !$( element ).parents().andSelf().filter(function() {
		return $.curCSS( this, "visibility" ) === "hidden" ||
			$.expr.filters.hidden( this );
	}).length;
}

$.extend( $.expr[ ":" ], {
	data: function( elem, i, match ) {
		return !!$.data( elem, match[ 3 ] );
	},

	focusable: function( element ) {
		var nodeName = element.nodeName.toLowerCase(),
			tabIndex = $.attr( element, "tabindex" );
		if ( "area" === nodeName ) {
			var map = element.parentNode,
				mapName = map.name,
				img;
			if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
				return false;
			}
			img = $( "img[usemap=#" + mapName + "]" )[0];
			return !!img && visible( img );
		}
		return ( /input|select|textarea|button|object/.test( nodeName )
			? !element.disabled
			: "a" == nodeName
				? element.href || !isNaN( tabIndex )
				: !isNaN( tabIndex ))
			// the element and all of its ancestors must be visible
			&& visible( element );
	},

	tabbable: function( element ) {
		var tabIndex = $.attr( element, "tabindex" );
		return ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( ":focusable" );
	}
});

// support
$(function() {
	var body = document.body,
		div = body.appendChild( div = document.createElement( "div" ) );

	$.extend( div.style, {
		minHeight: "100px",
		height: "auto",
		padding: 0,
		borderWidth: 0
	});

	$.support.minHeight = div.offsetHeight === 100;
	$.support.selectstart = "onselectstart" in div;

	// set display to none to avoid a layout bug in IE
	// http://dev.jquery.com/ticket/4014
	body.removeChild( div ).style.display = "none";
});





// deprecated
$.extend( $.ui, {
	// $.ui.plugin is deprecated.  Use the proxy pattern instead.
	plugin: {
		add: function( module, option, set ) {
			var proto = $.ui[ module ].prototype;
			for ( var i in set ) {
				proto.plugins[ i ] = proto.plugins[ i ] || [];
				proto.plugins[ i ].push( [ option, set[ i ] ] );
			}
		},
		call: function( instance, name, args ) {
			var set = instance.plugins[ name ];
			if ( !set || !instance.element[ 0 ].parentNode ) {
				return;
			}
	
			for ( var i = 0; i < set.length; i++ ) {
				if ( instance.options[ set[ i ][ 0 ] ] ) {
					set[ i ][ 1 ].apply( instance.element, args );
				}
			}
		}
	},
	
	// will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
	contains: function( a, b ) {
		return document.compareDocumentPosition ?
			a.compareDocumentPosition( b ) & 16 :
			a !== b && a.contains( b );
	},
	
	// only used by resizable
	hasScroll: function( el, a ) {
	
		//If overflow is hidden, the element might have extra content, but the user wants to hide it
		if ( $( el ).css( "overflow" ) === "hidden") {
			return false;
		}
	
		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
			has = false;
	
		if ( el[ scroll ] > 0 ) {
			return true;
		}
	
		// TODO: determine which cases actually cause this to happen
		// if the element doesn't have the scroll set, see if it's possible to
		// set the scroll
		el[ scroll ] = 1;
		has = ( el[ scroll ] > 0 );
		el[ scroll ] = 0;
		return has;
	},
	
	// these are odd functions, fix the API or move into individual plugins
	isOverAxis: function( x, reference, size ) {
		//Determines when x coordinate is over "b" element axis
		return ( x > reference ) && ( x < ( reference + size ) );
	},
	isOver: function( y, x, top, left, height, width ) {
		//Determines when x, y coordinates is over "b" element
		return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
	}
});

})( jQuery );
/*!
 * jQuery UI Widget 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Widget
 */
(function( $, undefined ) {

// jQuery 1.4+
if ( $.cleanData ) {
	var _cleanData = $.cleanData;
	$.cleanData = function( elems ) {
		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
			$( elem ).triggerHandler( "remove" );
		}
		_cleanData( elems );
	};
} else {
	var _remove = $.fn.remove;
	$.fn.remove = function( selector, keepData ) {
		return this.each(function() {
			if ( !keepData ) {
				if ( !selector || $.filter( selector, [ this ] ).length ) {
					$( "*", this ).add( [ this ] ).each(function() {
						$( this ).triggerHandler( "remove" );
					});
				}
			}
			return _remove.call( $(this), selector, keepData );
		});
	};
}

$.widget = function( name, base, prototype ) {
	var namespace = name.split( "." )[ 0 ],
		fullName;
	name = name.split( "." )[ 1 ];
	fullName = namespace + "-" + name;

	if ( !prototype ) {
		prototype = base;
		base = $.Widget;
	}

	// create selector for plugin
	$.expr[ ":" ][ fullName ] = function( elem ) {
		return !!$.data( elem, name );
	};

	$[ namespace ] = $[ namespace ] || {};
	$[ namespace ][ name ] = function( options, element ) {
		// allow instantiation without initializing for simple inheritance
		if ( arguments.length ) {
			this._createWidget( options, element );
		}
	};

	var basePrototype = new base();
	// we need to make the options hash a property directly on the new instance
	// otherwise we'll modify the options hash on the prototype that we're
	// inheriting from
//	$.each( basePrototype, function( key, val ) {
//		if ( $.isPlainObject(val) ) {
//			basePrototype[ key ] = $.extend( {}, val );
//		}
//	});
	basePrototype.options = $.extend( true, {}, basePrototype.options );
	$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
		namespace: namespace,
		widgetName: name,
		widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
		widgetBaseClass: fullName
	}, prototype );

	$.widget.bridge( name, $[ namespace ][ name ] );
};

$.widget.bridge = function( name, object ) {
	$.fn[ name ] = function( options ) {
		var isMethodCall = typeof options === "string",
			args = Array.prototype.slice.call( arguments, 1 ),
			returnValue = this;

		// allow multiple hashes to be passed on init
		options = !isMethodCall && args.length ?
			$.extend.apply( null, [ true, options ].concat(args) ) :
			options;

		// prevent calls to internal methods
		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
			return returnValue;
		}

		if ( isMethodCall ) {
			this.each(function() {
				var instance = $.data( this, name ),
					methodValue = instance && $.isFunction( instance[options] ) ?
						instance[ options ].apply( instance, args ) :
						instance;
				// TODO: add this back in 1.9 and use $.error() (see #5972)
//				if ( !instance ) {
//					throw "cannot call methods on " + name + " prior to initialization; " +
//						"attempted to call method '" + options + "'";
//				}
//				if ( !$.isFunction( instance[options] ) ) {
//					throw "no such method '" + options + "' for " + name + " widget instance";
//				}
//				var methodValue = instance[ options ].apply( instance, args );
				if ( methodValue !== instance && methodValue !== undefined ) {
					returnValue = methodValue;
					return false;
				}
			});
		} else {
			this.each(function() {
				var instance = $.data( this, name );
				if ( instance ) {
					instance.option( options || {} )._init();
				} else {
					$.data( this, name, new object( options, this ) );
				}
			});
		}

		return returnValue;
	};
};

$.Widget = function( options, element ) {
	// allow instantiation without initializing for simple inheritance
	if ( arguments.length ) {
		this._createWidget( options, element );
	}
};

$.Widget.prototype = {
	widgetName: "widget",
	widgetEventPrefix: "",
	options: {
		disabled: false
	},
	_createWidget: function( options, element ) {
		// $.widget.bridge stores the plugin instance, but we do it anyway
		// so that it's stored even before the _create function runs
		$.data( element, this.widgetName, this );
		this.element = $( element );
		this.options = $.extend( true, {},
			this.options,
			this._getCreateOptions(),
			options );

		var self = this;
		this.element.bind( "remove." + this.widgetName, function() {
			self.destroy();
		});

		this._create();
		this._trigger( "create" );
		this._init();
	},
	_getCreateOptions: function() {
		return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
	},
	_create: function() {},
	_init: function() {},

	destroy: function() {
		this.element
			.unbind( "." + this.widgetName )
			.removeData( this.widgetName );
		this.widget()
			.unbind( "." + this.widgetName )
			.removeAttr( "aria-disabled" )
			.removeClass(
				this.widgetBaseClass + "-disabled " +
				"ui-state-disabled" );
	},

	widget: function() {
		return this.element;
	},

	option: function( key, value ) {
		var options = key;

		if ( arguments.length === 0 ) {
			// don't return a reference to the internal hash
			return $.extend( {}, this.options );
		}

		if  (typeof key === "string" ) {
			if ( value === undefined ) {
				return this.options[ key ];
			}
			options = {};
			options[ key ] = value;
		}

		this._setOptions( options );

		return this;
	},
	_setOptions: function( options ) {
		var self = this;
		$.each( options, function( key, value ) {
			self._setOption( key, value );
		});

		return this;
	},
	_setOption: function( key, value ) {
		this.options[ key ] = value;

		if ( key === "disabled" ) {
			this.widget()
				[ value ? "addClass" : "removeClass"](
					this.widgetBaseClass + "-disabled" + " " +
					"ui-state-disabled" )
				.attr( "aria-disabled", value );
		}

		return this;
	},

	enable: function() {
		return this._setOption( "disabled", false );
	},
	disable: function() {
		return this._setOption( "disabled", true );
	},

	_trigger: function( type, event, data ) {
		var callback = this.options[ type ];

		event = $.Event( event );
		event.type = ( type === this.widgetEventPrefix ?
			type :
			this.widgetEventPrefix + type ).toLowerCase();
		data = data || {};

		// copy original event properties over to the new event
		// this would happen if we could call $.event.fix instead of $.Event
		// but we don't have a way to force an event to be fixed multiple times
		if ( event.originalEvent ) {
			for ( var i = $.event.props.length, prop; i; ) {
				prop = $.event.props[ --i ];
				event[ prop ] = event.originalEvent[ prop ];
			}
		}

		this.element.trigger( event, data );

		return !( $.isFunction(callback) &&
			callback.call( this.element[0], event, data ) === false ||
			event.isDefaultPrevented() );
	}
};

})( jQuery );
/*!
 * jQuery UI Mouse 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Mouse
 *
 * Depends:
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget("ui.mouse", {
	options: {
		cancel: ':input,option',
		distance: 1,
		delay: 0
	},
	_mouseInit: function() {
		var self = this;

		this.element
			.bind('mousedown.'+this.widgetName, function(event) {
				return self._mouseDown(event);
			})
			.bind('click.'+this.widgetName, function(event) {
				if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) {
				    $.removeData(event.target, self.widgetName + '.preventClickEvent');
					event.stopImmediatePropagation();
					return false;
				}
			});

		this.started = false;
	},

	// TODO: make sure destroying one instance of mouse doesn't mess with
	// other instances of mouse
	_mouseDestroy: function() {
		this.element.unbind('.'+this.widgetName);
	},

	_mouseDown: function(event) {
		// don't let more than one widget handle mouseStart
		// TODO: figure out why we have to use originalEvent
		event.originalEvent = event.originalEvent || {};
		if (event.originalEvent.mouseHandled) { return; }

		// we may have missed mouseup (out of window)
		(this._mouseStarted && this._mouseUp(event));

		this._mouseDownEvent = event;

		var self = this,
			btnIsLeft = (event.which == 1),
			elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
		if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
			return true;
		}

		this.mouseDelayMet = !this.options.delay;
		if (!this.mouseDelayMet) {
			this._mouseDelayTimer = setTimeout(function() {
				self.mouseDelayMet = true;
			}, this.options.delay);
		}

		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
			this._mouseStarted = (this._mouseStart(event) !== false);
			if (!this._mouseStarted) {
				event.preventDefault();
				return true;
			}
		}

		// Click event may never have fired (Gecko & Opera)
		if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
			$.removeData(event.target, this.widgetName + '.preventClickEvent');
		}

		// these delegates are required to keep context
		this._mouseMoveDelegate = function(event) {
			return self._mouseMove(event);
		};
		this._mouseUpDelegate = function(event) {
			return self._mouseUp(event);
		};
		$(document)
			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);

		event.preventDefault();
		event.originalEvent.mouseHandled = true;
		return true;
	},

	_mouseMove: function(event) {
		// IE mouseup check - mouseup happened when mouse was out of window
		if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
			return this._mouseUp(event);
		}

		if (this._mouseStarted) {
			this._mouseDrag(event);
			return event.preventDefault();
		}

		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
			this._mouseStarted =
				(this._mouseStart(this._mouseDownEvent, event) !== false);
			(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
		}

		return !this._mouseStarted;
	},

	_mouseUp: function(event) {
		$(document)
			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);

		if (this._mouseStarted) {
			this._mouseStarted = false;

			if (event.target == this._mouseDownEvent.target) {
			    $.data(event.target, this.widgetName + '.preventClickEvent', true);
			}

			this._mouseStop(event);
		}

		return false;
	},

	_mouseDistanceMet: function(event) {
		return (Math.max(
				Math.abs(this._mouseDownEvent.pageX - event.pageX),
				Math.abs(this._mouseDownEvent.pageY - event.pageY)
			) >= this.options.distance
		);
	},

	_mouseDelayMet: function(event) {
		return this.mouseDelayMet;
	},

	// These are placeholder methods, to be overriden by extending plugin
	_mouseStart: function(event) {},
	_mouseDrag: function(event) {},
	_mouseStop: function(event) {},
	_mouseCapture: function(event) { return true; }
});

})(jQuery);
/*
 * jQuery UI Draggable 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Draggables
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.mouse.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget("ui.draggable", $.ui.mouse, {
	widgetEventPrefix: "drag",
	options: {
		addClasses: true,
		appendTo: "parent",
		axis: false,
		connectToSortable: false,
		containment: false,
		cursor: "auto",
		cursorAt: false,
		grid: false,
		handle: false,
		helper: "original",
		iframeFix: false,
		opacity: false,
		refreshPositions: false,
		revert: false,
		revertDuration: 500,
		scope: "default",
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		snap: false,
		snapMode: "both",
		snapTolerance: 20,
		stack: false,
		zIndex: false
	},
	_create: function() {

		if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
			this.element[0].style.position = 'relative';

		(this.options.addClasses && this.element.addClass("ui-draggable"));
		(this.options.disabled && this.element.addClass("ui-draggable-disabled"));

		this._mouseInit();

	},

	destroy: function() {
		if(!this.element.data('draggable')) return;
		this.element
			.removeData("draggable")
			.unbind(".draggable")
			.removeClass("ui-draggable"
				+ " ui-draggable-dragging"
				+ " ui-draggable-disabled");
		this._mouseDestroy();

		return this;
	},

	_mouseCapture: function(event) {

		var o = this.options;

		// among others, prevent a drag on a resizable-handle
		if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
			return false;

		//Quit if we're not on a valid handle
		this.handle = this._getHandle(event);
		if (!this.handle)
			return false;

		return true;

	},

	_mouseStart: function(event) {

		var o = this.options;

		//Create and append the visible helper
		this.helper = this._createHelper(event);

		//Cache the helper size
		this._cacheHelperProportions();

		//If ddmanager is used for droppables, set the global draggable
		if($.ui.ddmanager)
			$.ui.ddmanager.current = this;

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//Store the helper's css position
		this.cssPosition = this.helper.css("position");
		this.scrollParent = this.helper.scrollParent();

		//The element's absolute position on the page minus margins
		this.offset = this.positionAbs = this.element.offset();
		this.offset = {
			top: this.offset.top - this.margins.top,
			left: this.offset.left - this.margins.left
		};

		$.extend(this.offset, {
			click: { //Where the click happened, relative to the element
				left: event.pageX - this.offset.left,
				top: event.pageY - this.offset.top
			},
			parent: this._getParentOffset(),
			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
		});

		//Generate the original position
		this.originalPosition = this.position = this._generatePosition(event);
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;

		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));

		//Set a containment if given in the options
		if(o.containment)
			this._setContainment();

		//Trigger event + callbacks
		if(this._trigger("start", event) === false) {
			this._clear();
			return false;
		}

		//Recache the helper size
		this._cacheHelperProportions();

		//Prepare the droppable offsets
		if ($.ui.ddmanager && !o.dropBehaviour)
			$.ui.ddmanager.prepareOffsets(this, event);

		this.helper.addClass("ui-draggable-dragging");
		this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
		return true;
	},

	_mouseDrag: function(event, noPropagation) {

		//Compute the helpers position
		this.position = this._generatePosition(event);
		this.positionAbs = this._convertPositionTo("absolute");

		//Call plugins and callbacks and use the resulting position if something is returned
		if (!noPropagation) {
			var ui = this._uiHash();
			if(this._trigger('drag', event, ui) === false) {
				this._mouseUp({});
				return false;
			}
			this.position = ui.position;
		}

		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

		return false;
	},

	_mouseStop: function(event) {

		//If we are using droppables, inform the manager about the drop
		var dropped = false;
		if ($.ui.ddmanager && !this.options.dropBehaviour)
			dropped = $.ui.ddmanager.drop(this, event);

		//if a drop comes from outside (a sortable)
		if(this.dropped) {
			dropped = this.dropped;
			this.dropped = false;
		}
		
		//if the original element is removed, don't bother to continue if helper is set to "original"
		if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original")
			return false;

		if((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))) {
			var self = this;
			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
				if(self._trigger("stop", event) !== false) {
					self._clear();
				}
			});
		} else {
			if(this._trigger("stop", event) !== false) {
				this._clear();
			}
		}

		return false;
	},
	
	cancel: function() {
		
		if(this.helper.is(".ui-draggable-dragging")) {
			this._mouseUp({});
		} else {
			this._clear();
		}
		
		return this;
		
	},

	_getHandle: function(event) {

		var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
		$(this.options.handle, this.element)
			.find("*")
			.andSelf()
			.each(function() {
				if(this == event.target) handle = true;
			});

		return handle;

	},

	_createHelper: function(event) {

		var o = this.options;
		var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);

		if(!helper.parents('body').length)
			helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));

		if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
			helper.css("position", "absolute");

		return helper;

	},

	_adjustOffsetFromHelper: function(obj) {
		if (typeof obj == 'string') {
			obj = obj.split(' ');
		}
		if ($.isArray(obj)) {
			obj = {left: +obj[0], top: +obj[1] || 0};
		}
		if ('left' in obj) {
			this.offset.click.left = obj.left + this.margins.left;
		}
		if ('right' in obj) {
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		}
		if ('top' in obj) {
			this.offset.click.top = obj.top + this.margins.top;
		}
		if ('bottom' in obj) {
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
		}
	},

	_getParentOffset: function() {

		//Get the offsetParent and cache its position
		this.offsetParent = this.helper.offsetParent();
		var po = this.offsetParent.offset();

		// This is a special case where we need to modify a offset calculated on start, since the following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
		if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
			po = { top: 0, left: 0 };

		return {
			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
		};

	},

	_getRelativeOffset: function() {

		if(this.cssPosition == "relative") {
			var p = this.element.position();
			return {
				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
			};
		} else {
			return { top: 0, left: 0 };
		}

	},

	_cacheMargins: function() {
		this.margins = {
			left: (parseInt(this.element.css("marginLeft"),10) || 0),
			top: (parseInt(this.element.css("marginTop"),10) || 0),
			right: (parseInt(this.element.css("marginRight"),10) || 0),
			bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var o = this.options;
		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
		if(o.containment == 'document' || o.containment == 'window') this.containment = [
			(o.containment == 'document' ? 0 : $(window).scrollLeft()) - this.offset.relative.left - this.offset.parent.left,
			(o.containment == 'document' ? 0 : $(window).scrollTop()) - this.offset.relative.top - this.offset.parent.top,
			(o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
			(o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
		];

		if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
			var ce = $(o.containment)[0]; if(!ce) return;
			var co = $(o.containment).offset();
			var over = ($(ce).css("overflow") != 'hidden');

			this.containment = [
				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
				co.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 - this.margins.right,
				co.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  - this.margins.bottom
			];
		} else if(o.containment.constructor == Array) {
			this.containment = o.containment;
		}

	},

	_convertPositionTo: function(d, pos) {

		if(!pos) pos = this.position;
		var mod = d == "absolute" ? 1 : -1;
		var 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);

		return {
			top: (
				pos.top																	// The absolute mouse position
				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
				- ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
			),
			left: (
				pos.left																// The absolute mouse position
				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
				- ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
			)
		};

	},

	_generatePosition: function(event) {

		var 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);
		var pageX = event.pageX;
		var pageY = event.pageY;

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		if(this.originalPosition) { //If we are not dragging yet, we won't check for options

			if(this.containment) {
				if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
				if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
				if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
				if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
			}

			if(o.grid) {
				var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
				pageY = 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;

				var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
				pageX = 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;
			}

		}

		return {
			top: (
				pageY																// The absolute mouse position
				- this.offset.click.top													// Click offset (relative to the element)
				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
			),
			left: (
				pageX																// The absolute mouse position
				- this.offset.click.left												// Click offset (relative to the element)
				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
			)
		};

	},

	_clear: function() {
		this.helper.removeClass("ui-draggable-dragging");
		if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
		//if($.ui.ddmanager) $.ui.ddmanager.current = null;
		this.helper = null;
		this.cancelHelperRemoval = false;
	},

	// From now on bulk stuff - mainly helpers

	_trigger: function(type, event, ui) {
		ui = ui || this._uiHash();
		$.ui.plugin.call(this, type, [event, ui]);
		if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
		return $.Widget.prototype._trigger.call(this, type, event, ui);
	},

	plugins: {},

	_uiHash: function(event) {
		return {
			helper: this.helper,
			position: this.position,
			originalPosition: this.originalPosition,
			offset: this.positionAbs
		};
	}

});

$.extend($.ui.draggable, {
	version: "1.8.12"
});

$.ui.plugin.add("draggable", "connectToSortable", {
	start: function(event, ui) {

		var inst = $(this).data("draggable"), o = inst.options,
			uiSortable = $.extend({}, ui, { item: inst.element });
		inst.sortables = [];
		$(o.connectToSortable).each(function() {
			var sortable = $.data(this, 'sortable');
			if (sortable && !sortable.options.disabled) {
				inst.sortables.push({
					instance: sortable,
					shouldRevert: sortable.options.revert
				});
				sortable.refreshPositions();	// Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
				sortable._trigger("activate", event, uiSortable);
			}
		});

	},
	stop: function(event, ui) {

		//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
		var inst = $(this).data("draggable"),
			uiSortable = $.extend({}, ui, { item: inst.element });

		$.each(inst.sortables, function() {
			if(this.instance.isOver) {

				this.instance.isOver = 0;

				inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
				this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)

				//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
				if(this.shouldRevert) this.instance.options.revert = true;

				//Trigger the stop of the sortable
				this.instance._mouseStop(event);

				this.instance.options.helper = this.instance.options._helper;

				//If the helper has been the original item, restore properties in the sortable
				if(inst.options.helper == 'original')
					this.instance.currentItem.css({ top: 'auto', left: 'auto' });

			} else {
				this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
				this.instance._trigger("deactivate", event, uiSortable);
			}

		});

	},
	drag: function(event, ui) {

		var inst = $(this).data("draggable"), self = this;

		var checkPos = function(o) {
			var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
			var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
			var itemHeight = o.height, itemWidth = o.width;
			var itemTop = o.top, itemLeft = o.left;

			return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
		};

		$.each(inst.sortables, function(i) {
			
			//Copy over some variables to allow calling the sortable's native _intersectsWith
			this.instance.positionAbs = inst.positionAbs;
			this.instance.helperProportions = inst.helperProportions;
			this.instance.offset.click = inst.offset.click;
			
			if(this.instance._intersectsWith(this.instance.containerCache)) {

				//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
				if(!this.instance.isOver) {

					this.instance.isOver = 1;
					//Now we fake the start of dragging for the sortable instance,
					//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
					//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)
					this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
					this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
					this.instance.options.helper = function() { return ui.helper[0]; };

					event.target = this.instance.currentItem[0];
					this.instance._mouseCapture(event, true);
					this.instance._mouseStart(event, true, true);

					//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
					this.instance.offset.click.top = inst.offset.click.top;
					this.instance.offset.click.left = inst.offset.click.left;
					this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
					this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;

					inst._trigger("toSortable", event);
					inst.dropped = this.instance.element; //draggable revert needs that
					//hack so receive/update callbacks work (mostly)
					inst.currentItem = inst.element;
					this.instance.fromOutside = inst;

				}

				//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
				if(this.instance.currentItem) this.instance._mouseDrag(event);

			} else {

				//If it doesn't intersect with the sortable, and it intersected before,
				//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
				if(this.instance.isOver) {

					this.instance.isOver = 0;
					this.instance.cancelHelperRemoval = true;
					
					//Prevent reverting on this forced stop
					this.instance.options.revert = false;
					
					// The out event needs to be triggered independently
					this.instance._trigger('out', event, this.instance._uiHash(this.instance));
					
					this.instance._mouseStop(event, true);
					this.instance.options.helper = this.instance.options._helper;

					//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
					this.instance.currentItem.remove();
					if(this.instance.placeholder) this.instance.placeholder.remove();

					inst._trigger("fromSortable", event);
					inst.dropped = false; //draggable revert needs that
				}

			};

		});

	}
});

$.ui.plugin.add("draggable", "cursor", {
	start: function(event, ui) {
		var t = $('body'), o = $(this).data('draggable').options;
		if (t.css("cursor")) o._cursor = t.css("cursor");
		t.css("cursor", o.cursor);
	},
	stop: function(event, ui) {
		var o = $(this).data('draggable').options;
		if (o._cursor) $('body').css("cursor", o._cursor);
	}
});

$.ui.plugin.add("draggable", "iframeFix", {
	start: function(event, ui) {
		var o = $(this).data('draggable').options;
		$(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
			$('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
			.css({
				width: this.offsetWidth+"px", height: this.offsetHeight+"px",
				position: "absolute", opacity: "0.001", zIndex: 1000
			})
			.css($(this).offset())
			.appendTo("body");
		});
	},
	stop: function(event, ui) {
		$("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
	}
});

$.ui.plugin.add("draggable", "opacity", {
	start: function(event, ui) {
		var t = $(ui.helper), o = $(this).data('draggable').options;
		if(t.css("opacity")) o._opacity = t.css("opacity");
		t.css('opacity', o.opacity);
	},
	stop: function(event, ui) {
		var o = $(this).data('draggable').options;
		if(o._opacity) $(ui.helper).css('opacity', o._opacity);
	}
});

$.ui.plugin.add("draggable", "scroll", {
	start: function(event, ui) {
		var i = $(this).data("draggable");
		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
	},
	drag: function(event, ui) {

		var i = $(this).data("draggable"), o = i.options, scrolled = false;

		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {

			if(!o.axis || o.axis != 'x') {
				if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
				else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
			}

			if(!o.axis || o.axis != 'y') {
				if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
				else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
			}

		} else {

			if(!o.axis || o.axis != 'x') {
				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
				else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
			}

			if(!o.axis || o.axis != 'y') {
				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
				else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
			}

		}

		if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
			$.ui.ddmanager.prepareOffsets(i, event);

	}
});

$.ui.plugin.add("draggable", "snap", {
	start: function(event, ui) {

		var i = $(this).data("draggable"), o = i.options;
		i.snapElements = [];

		$(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
			var $t = $(this); var $o = $t.offset();
			if(this != i.element[0]) i.snapElements.push({
				item: this,
				width: $t.outerWidth(), height: $t.outerHeight(),
				top: $o.top, left: $o.left
			});
		});

	},
	drag: function(event, ui) {

		var inst = $(this).data("draggable"), o = inst.options;
		var d = o.snapTolerance;

		var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;

		for (var i = inst.snapElements.length - 1; i >= 0; i--){

			var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
				t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;

			//Yes, I know, this is insane ;)
			if(!((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))) {
				if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
				inst.snapElements[i].snapping = false;
				continue;
			}

			if(o.snapMode != 'inner') {
				var ts = Math.abs(t - y2) <= d;
				var bs = Math.abs(b - y1) <= d;
				var ls = Math.abs(l - x2) <= d;
				var rs = Math.abs(r - x1) <= d;
				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
			}

			var first = (ts || bs || ls || rs);

			if(o.snapMode != 'outer') {
				var ts = Math.abs(t - y1) <= d;
				var bs = Math.abs(b - y2) <= d;
				var ls = Math.abs(l - x1) <= d;
				var rs = Math.abs(r - x2) <= d;
				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
			}

			if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);

		};

	}
});

$.ui.plugin.add("draggable", "stack", {
	start: function(event, ui) {

		var o = $(this).data("draggable").options;

		var group = $.makeArray($(o.stack)).sort(function(a,b) {
			return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
		});
		if (!group.length) { return; }
		
		var min = parseInt(group[0].style.zIndex) || 0;
		$(group).each(function(i) {
			this.style.zIndex = min + i;
		});

		this[0].style.zIndex = min + group.length;

	}
});

$.ui.plugin.add("draggable", "zIndex", {
	start: function(event, ui) {
		var t = $(ui.helper), o = $(this).data("draggable").options;
		if(t.css("zIndex")) o._zIndex = t.css("zIndex");
		t.css('zIndex', o.zIndex);
	},
	stop: function(event, ui) {
		var o = $(this).data("draggable").options;
		if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
	}
});

})(jQuery);
/*
 * jQuery UI Droppable 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Droppables
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *	jquery.ui.mouse.js
 *	jquery.ui.draggable.js
 */
(function( $, undefined ) {

$.widget("ui.droppable", {
	widgetEventPrefix: "drop",
	options: {
		accept: '*',
		activeClass: false,
		addClasses: true,
		greedy: false,
		hoverClass: false,
		scope: 'default',
		tolerance: 'intersect'
	},
	_create: function() {

		var o = this.options, accept = o.accept;
		this.isover = 0; this.isout = 1;

		this.accept = $.isFunction(accept) ? accept : function(d) {
			return d.is(accept);
		};

		//Store the droppable's proportions
		this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };

		// Add the reference and positions to the manager
		$.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
		$.ui.ddmanager.droppables[o.scope].push(this);

		(o.addClasses && this.element.addClass("ui-droppable"));

	},

	destroy: function() {
		var drop = $.ui.ddmanager.droppables[this.options.scope];
		for ( var i = 0; i < drop.length; i++ )
			if ( drop[i] == this )
				drop.splice(i, 1);

		this.element
			.removeClass("ui-droppable ui-droppable-disabled")
			.removeData("droppable")
			.unbind(".droppable");

		return this;
	},

	_setOption: function(key, value) {

		if(key == 'accept') {
			this.accept = $.isFunction(value) ? value : function(d) {
				return d.is(value);
			};
		}
		$.Widget.prototype._setOption.apply(this, arguments);
	},

	_activate: function(event) {
		var draggable = $.ui.ddmanager.current;
		if(this.options.activeClass) this.element.addClass(this.options.activeClass);
		(draggable && this._trigger('activate', event, this.ui(draggable)));
	},

	_deactivate: function(event) {
		var draggable = $.ui.ddmanager.current;
		if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
		(draggable && this._trigger('deactivate', event, this.ui(draggable)));
	},

	_over: function(event) {

		var draggable = $.ui.ddmanager.current;
		if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

		if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
			if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
			this._trigger('over', event, this.ui(draggable));
		}

	},

	_out: function(event) {

		var draggable = $.ui.ddmanager.current;
		if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

		if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
			if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
			this._trigger('out', event, this.ui(draggable));
		}

	},

	_drop: function(event,custom) {

		var draggable = custom || $.ui.ddmanager.current;
		if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element

		var childrenIntersection = false;
		this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
			var inst = $.data(this, 'droppable');
			if(
				inst.options.greedy
				&& !inst.options.disabled
				&& inst.options.scope == draggable.options.scope
				&& inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
				&& $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
			) { childrenIntersection = true; return false; }
		});
		if(childrenIntersection) return false;

		if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
			if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
			if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
			this._trigger('drop', event, this.ui(draggable));
			return this.element;
		}

		return false;

	},

	ui: function(c) {
		return {
			draggable: (c.currentItem || c.element),
			helper: c.helper,
			position: c.position,
			offset: c.positionAbs
		};
	}

});

$.extend($.ui.droppable, {
	version: "1.8.12"
});

$.ui.intersect = function(draggable, droppable, toleranceMode) {

	if (!droppable.offset) return false;

	var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
		y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
	var l = droppable.offset.left, r = l + droppable.proportions.width,
		t = droppable.offset.top, b = t + droppable.proportions.height;

	switch (toleranceMode) {
		case 'fit':
			return (l <= x1 && x2 <= r
				&& t <= y1 && y2 <= b);
			break;
		case 'intersect':
			return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
				&& x2 - (draggable.helperProportions.width / 2) < r // Left Half
				&& t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
				&& y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
			break;
		case 'pointer':
			var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
				draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
				isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
			return isOver;
			break;
		case 'touch':
			return (
					(y1 >= t && y1 <= b) ||	// Top edge touching
					(y2 >= t && y2 <= b) ||	// Bottom edge touching
					(y1 < t && y2 > b)		// Surrounded vertically
				) && (
					(x1 >= l && x1 <= r) ||	// Left edge touching
					(x2 >= l && x2 <= r) ||	// Right edge touching
					(x1 < l && x2 > r)		// Surrounded horizontally
				);
			break;
		default:
			return false;
			break;
		}

};

/*
	This manager tracks offsets of draggables and droppables
*/
$.ui.ddmanager = {
	current: null,
	droppables: { 'default': [] },
	prepareOffsets: function(t, event) {

		var m = $.ui.ddmanager.droppables[t.options.scope] || [];
		var type = event ? event.type : null; // workaround for #2317
		var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();

		droppablesLoop: for (var i = 0; i < m.length; i++) {

			if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue;	//No disabled and non-accepted
			for (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
			m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; 									//If the element is not visible, continue

			if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables

			m[i].offset = m[i].element.offset();
			m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };

		}

	},
	drop: function(draggable, event) {

		var dropped = false;
		$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {

			if(!this.options) return;
			if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
				dropped = dropped || this._drop.call(this, event);

			if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
				this.isout = 1; this.isover = 0;
				this._deactivate.call(this, event);
			}

		});
		return dropped;

	},
	drag: function(draggable, event) {

		//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
		if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);

		//Run through all droppables and check their positions based on specific tolerance options
		$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {

			if(this.options.disabled || this.greedyChild || !this.visible) return;
			var intersects = $.ui.intersect(draggable, this, this.options.tolerance);

			var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
			if(!c) return;

			var parentInstance;
			if (this.options.greedy) {
				var parent = this.element.parents(':data(droppable):eq(0)');
				if (parent.length) {
					parentInstance = $.data(parent[0], 'droppable');
					parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
				}
			}

			// we just moved into a greedy child
			if (parentInstance && c == 'isover') {
				parentInstance['isover'] = 0;
				parentInstance['isout'] = 1;
				parentInstance._out.call(parentInstance, event);
			}

			this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
			this[c == "isover" ? "_over" : "_out"].call(this, event);

			// we just moved out of a greedy child
			if (parentInstance && c == 'isout') {
				parentInstance['isout'] = 0;
				parentInstance['isover'] = 1;
				parentInstance._over.call(parentInstance, event);
			}
		});

	}
};

})(jQuery);
/*
 * jQuery UI Resizable 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Resizables
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.mouse.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget("ui.resizable", $.ui.mouse, {
	widgetEventPrefix: "resize",
	options: {
		alsoResize: false,
		animate: false,
		animateDuration: "slow",
		animateEasing: "swing",
		aspectRatio: false,
		autoHide: false,
		containment: false,
		ghost: false,
		grid: false,
		handles: "e,s,se",
		helper: false,
		maxHeight: null,
		maxWidth: null,
		minHeight: 10,
		minWidth: 10,
		zIndex: 1000
	},
	_create: function() {

		var self = this, o = this.options;
		this.element.addClass("ui-resizable");

		$.extend(this, {
			_aspectRatio: !!(o.aspectRatio),
			aspectRatio: o.aspectRatio,
			originalElement: this.element,
			_proportionallyResizeElements: [],
			_helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
		});

		//Wrap the element if it cannot hold child nodes
		if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {

			//Opera fix for relative positioning
			if (/relative/.test(this.element.css('position')) && $.browser.opera)
				this.element.css({ position: 'relative', top: 'auto', left: 'auto' });

			//Create a wrapper element and set the wrapper to the new current internal element
			this.element.wrap(
				$('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
					position: this.element.css('position'),
					width: this.element.outerWidth(),
					height: this.element.outerHeight(),
					top: this.element.css('top'),
					left: this.element.css('left')
				})
			);

			//Overwrite the original this.element
			this.element = this.element.parent().data(
				"resizable", this.element.data('resizable')
			);

			this.elementIsWrapper = true;

			//Move margins to the wrapper
			this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
			this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});

			//Prevent Safari textarea resize
			this.originalResizeStyle = this.originalElement.css('resize');
			this.originalElement.css('resize', 'none');

			//Push the actual element to our proportionallyResize internal array
			this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));

			// avoid IE jump (hard set the margin)
			this.originalElement.css({ margin: this.originalElement.css('margin') });

			// fix handlers offset
			this._proportionallyResize();

		}

		this.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' });
		if(this.handles.constructor == String) {

			if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
			var n = this.handles.split(","); this.handles = {};

			for(var i = 0; i < n.length; i++) {

				var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
				var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');

				// increase zIndex of sw, se, ne, nw axis
				//TODO : this modifies original option
				if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });

				//TODO : What's going on here?
				if ('se' == handle) {
					axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
				};

				//Insert into internal handles object and append to element
				this.handles[handle] = '.ui-resizable-'+handle;
				this.element.append(axis);
			}

		}

		this._renderAxis = function(target) {

			target = target || this.element;

			for(var i in this.handles) {

				if(this.handles[i].constructor == String)
					this.handles[i] = $(this.handles[i], this.element).show();

				//Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
				if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {

					var axis = $(this.handles[i], this.element), padWrapper = 0;

					//Checking the correct pad and border
					padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();

					//The padding type i have to apply...
					var padPos = [ 'padding',
						/ne|nw|n/.test(i) ? 'Top' :
						/se|sw|s/.test(i) ? 'Bottom' :
						/^e$/.test(i) ? 'Right' : 'Left' ].join("");

					target.css(padPos, padWrapper);

					this._proportionallyResize();

				}

				//TODO: What's that good for? There's not anything to be executed left
				if(!$(this.handles[i]).length)
					continue;

			}
		};

		//TODO: make renderAxis a prototype function
		this._renderAxis(this.element);

		this._handles = $('.ui-resizable-handle', this.element)
			.disableSelection();

		//Matching axis name
		this._handles.mouseover(function() {
			if (!self.resizing) {
				if (this.className)
					var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
				//Axis, default = se
				self.axis = axis && axis[1] ? axis[1] : 'se';
			}
		});

		//If we want to auto hide the elements
		if (o.autoHide) {
			this._handles.hide();
			$(this.element)
				.addClass("ui-resizable-autohide")
				.hover(function() {
					$(this).removeClass("ui-resizable-autohide");
					self._handles.show();
				},
				function(){
					if (!self.resizing) {
						$(this).addClass("ui-resizable-autohide");
						self._handles.hide();
					}
				});
		}

		//Initialize the mouse interaction
		this._mouseInit();

	},

	destroy: function() {

		this._mouseDestroy();

		var _destroy = function(exp) {
			$(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
				.removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
		};

		//TODO: Unwrap at same DOM position
		if (this.elementIsWrapper) {
			_destroy(this.element);
			var wrapper = this.element;
			wrapper.after(
				this.originalElement.css({
					position: wrapper.css('position'),
					width: wrapper.outerWidth(),
					height: wrapper.outerHeight(),
					top: wrapper.css('top'),
					left: wrapper.css('left')
				})
			).remove();
		}

		this.originalElement.css('resize', this.originalResizeStyle);
		_destroy(this.originalElement);

		return this;
	},

	_mouseCapture: function(event) {
		var handle = false;
		for (var i in this.handles) {
			if ($(this.handles[i])[0] == event.target) {
				handle = true;
			}
		}

		return !this.options.disabled && handle;
	},

	_mouseStart: function(event) {

		var o = this.options, iniPos = this.element.position(), el = this.element;

		this.resizing = true;
		this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };

		// bugfix for http://dev.jquery.com/ticket/1749
		if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
			el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
		}

		//Opera fixing relative position
		if ($.browser.opera && (/relative/).test(el.css('position')))
			el.css({ position: 'relative', top: 'auto', left: 'auto' });

		this._renderProxy();

		var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));

		if (o.containment) {
			curleft += $(o.containment).scrollLeft() || 0;
			curtop += $(o.containment).scrollTop() || 0;
		}

		//Store needed variables
		this.offset = this.helper.offset();
		this.position = { left: curleft, top: curtop };
		this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
		this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
		this.originalPosition = { left: curleft, top: curtop };
		this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
		this.originalMousePosition = { left: event.pageX, top: event.pageY };

		//Aspect Ratio
		this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);

	    var cursor = $('.ui-resizable-' + this.axis).css('cursor');
	    $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);

		el.addClass("ui-resizable-resizing");
		this._propagate("start", event);
		return true;
	},

	_mouseDrag: function(event) {

		//Increase performance, avoid regex
		var el = this.helper, o = this.options, props = {},
			self = this, smp = this.originalMousePosition, a = this.axis;

		var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
		var trigger = this._change[a];
		if (!trigger) return false;

		// Calculate the attrs that will be change
		var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;

		if (this._aspectRatio || event.shiftKey)
			data = this._updateRatio(data, event);

		data = this._respectSize(data, event);

		// plugins callbacks need to be called first
		this._propagate("resize", event);

		el.css({
			top: this.position.top + "px", left: this.position.left + "px",
			width: this.size.width + "px", height: this.size.height + "px"
		});

		if (!this._helper && this._proportionallyResizeElements.length)
			this._proportionallyResize();

		this._updateCache(data);

		// calling the user callback at the end
		this._trigger('resize', event, this.ui());

		return false;
	},

	_mouseStop: function(event) {

		this.resizing = false;
		var o = this.options, self = this;

		if(this._helper) {
			var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
				soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
				soffsetw = ista ? 0 : self.sizeDiff.width;

			var s = { width: (self.helper.width()  - soffsetw), height: (self.helper.height() - soffseth) },
				left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
				top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;

			if (!o.animate)
				this.element.css($.extend(s, { top: top, left: left }));

			self.helper.height(self.size.height);
			self.helper.width(self.size.width);

			if (this._helper && !o.animate) this._proportionallyResize();
		}

		$('body').css('cursor', 'auto');

		this.element.removeClass("ui-resizable-resizing");

		this._propagate("stop", event);

		if (this._helper) this.helper.remove();
		return false;

	},

	_updateCache: function(data) {
		var o = this.options;
		this.offset = this.helper.offset();
		if (isNumber(data.left)) this.position.left = data.left;
		if (isNumber(data.top)) this.position.top = data.top;
		if (isNumber(data.height)) this.size.height = data.height;
		if (isNumber(data.width)) this.size.width = data.width;
	},

	_updateRatio: function(data, event) {

		var o = this.options, cpos = this.position, csize = this.size, a = this.axis;

		if (data.height) data.width = (csize.height * this.aspectRatio);
		else if (data.width) data.height = (csize.width / this.aspectRatio);

		if (a == 'sw') {
			data.left = cpos.left + (csize.width - data.width);
			data.top = null;
		}
		if (a == 'nw') {
			data.top = cpos.top + (csize.height - data.height);
			data.left = cpos.left + (csize.width - data.width);
		}

		return data;
	},

	_respectSize: function(data, event) {

		var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
				ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
					isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);

		if (isminw) data.width = o.minWidth;
		if (isminh) data.height = o.minHeight;
		if (ismaxw) data.width = o.maxWidth;
		if (ismaxh) data.height = o.maxHeight;

		var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
		var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);

		if (isminw && cw) data.left = dw - o.minWidth;
		if (ismaxw && cw) data.left = dw - o.maxWidth;
		if (isminh && ch)	data.top = dh - o.minHeight;
		if (ismaxh && ch)	data.top = dh - o.maxHeight;

		// fixing jump error on top/left - bug #2330
		var isNotwh = !data.width && !data.height;
		if (isNotwh && !data.left && data.top) data.top = null;
		else if (isNotwh && !data.top && data.left) data.left = null;

		return data;
	},

	_proportionallyResize: function() {

		var o = this.options;
		if (!this._proportionallyResizeElements.length) return;
		var element = this.helper || this.element;

		for (var i=0; i < this._proportionallyResizeElements.length; i++) {

			var prel = this._proportionallyResizeElements[i];

			if (!this.borderDif) {
				var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
					p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];

				this.borderDif = $.map(b, function(v, i) {
					var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
					return border + padding;
				});
			}

			if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))
				continue;

			prel.css({
				height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
				width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
			});

		};

	},

	_renderProxy: function() {

		var el = this.element, o = this.options;
		this.elementOffset = el.offset();

		if(this._helper) {

			this.helper = this.helper || $('<div style="overflow:hidden;"></div>');

			// fix ie6 offset TODO: This seems broken
			var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
			pxyoffset = ( ie6 ? 2 : -1 );

			this.helper.addClass(this._helper).css({
				width: this.element.outerWidth() + pxyoffset,
				height: this.element.outerHeight() + pxyoffset,
				position: 'absolute',
				left: this.elementOffset.left - ie6offset +'px',
				top: this.elementOffset.top - ie6offset +'px',
				zIndex: ++o.zIndex //TODO: Don't modify option
			});

			this.helper
				.appendTo("body")
				.disableSelection();

		} else {
			this.helper = this.element;
		}

	},

	_change: {
		e: function(event, dx, dy) {
			return { width: this.originalSize.width + dx };
		},
		w: function(event, dx, dy) {
			var o = this.options, cs = this.originalSize, sp = this.originalPosition;
			return { left: sp.left + dx, width: cs.width - dx };
		},
		n: function(event, dx, dy) {
			var o = this.options, cs = this.originalSize, sp = this.originalPosition;
			return { top: sp.top + dy, height: cs.height - dy };
		},
		s: function(event, dx, dy) {
			return { height: this.originalSize.height + dy };
		},
		se: function(event, dx, dy) {
			return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
		},
		sw: function(event, dx, dy) {
			return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
		},
		ne: function(event, dx, dy) {
			return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
		},
		nw: function(event, dx, dy) {
			return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
		}
	},

	_propagate: function(n, event) {
		$.ui.plugin.call(this, n, [event, this.ui()]);
		(n != "resize" && this._trigger(n, event, this.ui()));
	},

	plugins: {},

	ui: function() {
		return {
			originalElement: this.originalElement,
			element: this.element,
			helper: this.helper,
			position: this.position,
			size: this.size,
			originalSize: this.originalSize,
			originalPosition: this.originalPosition
		};
	}

});

$.extend($.ui.resizable, {
	version: "1.8.12"
});

/*
 * Resizable Extensions
 */

$.ui.plugin.add("resizable", "alsoResize", {

	start: function (event, ui) {
		var self = $(this).data("resizable"), o = self.options;

		var _store = function (exp) {
			$(exp).each(function() {
				var el = $(this);
				el.data("resizable-alsoresize", {
					width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
					left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10),
					position: el.css('position') // to reset Opera on stop()
				});
			});
		};

		if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
			if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
			else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
		}else{
			_store(o.alsoResize);
		}
	},

	resize: function (event, ui) {
		var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;

		var delta = {
			height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
			top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
		},

		_alsoResize = function (exp, c) {
			$(exp).each(function() {
				var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, 
					css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];

				$.each(css, function (i, prop) {
					var sum = (start[prop]||0) + (delta[prop]||0);
					if (sum && sum >= 0)
						style[prop] = sum || null;
				});

				// Opera fixing relative position
				if ($.browser.opera && /relative/.test(el.css('position'))) {
					self._revertToRelativePosition = true;
					el.css({ position: 'absolute', top: 'auto', left: 'auto' });
				}

				el.css(style);
			});
		};

		if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
			$.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
		}else{
			_alsoResize(o.alsoResize);
		}
	},

	stop: function (event, ui) {
		var self = $(this).data("resizable"), o = self.options;

		var _reset = function (exp) {
			$(exp).each(function() {
				var el = $(this);
				// reset position for Opera - no need to verify it was changed
				el.css({ position: el.data("resizable-alsoresize").position });
			});
		};

		if (self._revertToRelativePosition) {
			self._revertToRelativePosition = false;
			if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
				$.each(o.alsoResize, function (exp) { _reset(exp); });
			}else{
				_reset(o.alsoResize);
			}
		}

		$(this).removeData("resizable-alsoresize");
	}
});

$.ui.plugin.add("resizable", "animate", {

	stop: function(event, ui) {
		var self = $(this).data("resizable"), o = self.options;

		var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
					soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
						soffsetw = ista ? 0 : self.sizeDiff.width;

		var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
					left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
						top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;

		self.element.animate(
			$.extend(style, top && left ? { top: top, left: left } : {}), {
				duration: o.animateDuration,
				easing: o.animateEasing,
				step: function() {

					var data = {
						width: parseInt(self.element.css('width'), 10),
						height: parseInt(self.element.css('height'), 10),
						top: parseInt(self.element.css('top'), 10),
						left: parseInt(self.element.css('left'), 10)
					};

					if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });

					// propagating resize, and updating values for each animation step
					self._updateCache(data);
					self._propagate("resize", event);

				}
			}
		);
	}

});

$.ui.plugin.add("resizable", "containment", {

	start: function(event, ui) {
		var self = $(this).data("resizable"), o = self.options, el = self.element;
		var oc = o.containment,	ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
		if (!ce) return;

		self.containerElement = $(ce);

		if (/document/.test(oc) || oc == document) {
			self.containerOffset = { left: 0, top: 0 };
			self.containerPosition = { left: 0, top: 0 };

			self.parentData = {
				element: $(document), left: 0, top: 0,
				width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
			};
		}

		// i'm a node, so compute top, left, right, bottom
		else {
			var element = $(ce), p = [];
			$([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });

			self.containerOffset = element.offset();
			self.containerPosition = element.position();
			self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };

			var co = self.containerOffset, ch = self.containerSize.height,	cw = self.containerSize.width,
						width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);

			self.parentData = {
				element: ce, left: co.left, top: co.top, width: width, height: height
			};
		}
	},

	resize: function(event, ui) {
		var self = $(this).data("resizable"), o = self.options,
				ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
				pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;

		if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;

		if (cp.left < (self._helper ? co.left : 0)) {
			self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));
			if (pRatio) self.size.height = self.size.width / o.aspectRatio;
			self.position.left = o.helper ? co.left : 0;
		}

		if (cp.top < (self._helper ? co.top : 0)) {
			self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);
			if (pRatio) self.size.width = self.size.height * o.aspectRatio;
			self.position.top = self._helper ? co.top : 0;
		}

		self.offset.left = self.parentData.left+self.position.left;
		self.offset.top = self.parentData.top+self.position.top;

		var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
					hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );

		var isParent = self.containerElement.get(0) == self.element.parent().get(0),
		    isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));

		if(isParent && isOffsetRelative) woset -= self.parentData.left;

		if (woset + self.size.width >= self.parentData.width) {
			self.size.width = self.parentData.width - woset;
			if (pRatio) self.size.height = self.size.width / self.aspectRatio;
		}

		if (hoset + self.size.height >= self.parentData.height) {
			self.size.height = self.parentData.height - hoset;
			if (pRatio) self.size.width = self.size.height * self.aspectRatio;
		}
	},

	stop: function(event, ui){
		var self = $(this).data("resizable"), o = self.options, cp = self.position,
				co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;

		var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;

		if (self._helper && !o.animate && (/relative/).test(ce.css('position')))
			$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });

		if (self._helper && !o.animate && (/static/).test(ce.css('position')))
			$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });

	}
});

$.ui.plugin.add("resizable", "ghost", {

	start: function(event, ui) {

		var self = $(this).data("resizable"), o = self.options, cs = self.size;

		self.ghost = self.originalElement.clone();
		self.ghost
			.css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
			.addClass('ui-resizable-ghost')
			.addClass(typeof o.ghost == 'string' ? o.ghost : '');

		self.ghost.appendTo(self.helper);

	},

	resize: function(event, ui){
		var self = $(this).data("resizable"), o = self.options;
		if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
	},

	stop: function(event, ui){
		var self = $(this).data("resizable"), o = self.options;
		if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
	}

});

$.ui.plugin.add("resizable", "grid", {

	resize: function(event, ui) {
		var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;
		o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
		var 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);

		if (/^(se|s|e)$/.test(a)) {
			self.size.width = os.width + ox;
			self.size.height = os.height + oy;
		}
		else if (/^(ne)$/.test(a)) {
			self.size.width = os.width + ox;
			self.size.height = os.height + oy;
			self.position.top = op.top - oy;
		}
		else if (/^(sw)$/.test(a)) {
			self.size.width = os.width + ox;
			self.size.height = os.height + oy;
			self.position.left = op.left - ox;
		}
		else {
			self.size.width = os.width + ox;
			self.size.height = os.height + oy;
			self.position.top = op.top - oy;
			self.position.left = op.left - ox;
		}
	}

});

var num = function(v) {
	return parseInt(v, 10) || 0;
};

var isNumber = function(value) {
	return !isNaN(parseInt(value, 10));
};

})(jQuery);
/*
 * jQuery UI Selectable 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Selectables
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.mouse.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget("ui.selectable", $.ui.mouse, {
	options: {
		appendTo: 'body',
		autoRefresh: true,
		distance: 0,
		filter: '*',
		tolerance: 'touch'
	},
	_create: function() {
		var self = this;

		this.element.addClass("ui-selectable");

		this.dragged = false;

		// cache selectee children based on filter
		var selectees;
		this.refresh = function() {
			selectees = $(self.options.filter, self.element[0]);
			selectees.each(function() {
				var $this = $(this);
				var pos = $this.offset();
				$.data(this, "selectable-item", {
					element: this,
					$element: $this,
					left: pos.left,
					top: pos.top,
					right: pos.left + $this.outerWidth(),
					bottom: pos.top + $this.outerHeight(),
					startselected: false,
					selected: $this.hasClass('ui-selected'),
					selecting: $this.hasClass('ui-selecting'),
					unselecting: $this.hasClass('ui-unselecting')
				});
			});
		};
		this.refresh();

		this.selectees = selectees.addClass("ui-selectee");

		this._mouseInit();

		this.helper = $("<div class='ui-selectable-helper'></div>");
	},

	destroy: function() {
		this.selectees
			.removeClass("ui-selectee")
			.removeData("selectable-item");
		this.element
			.removeClass("ui-selectable ui-selectable-disabled")
			.removeData("selectable")
			.unbind(".selectable");
		this._mouseDestroy();

		return this;
	},

	_mouseStart: function(event) {
		var self = this;

		this.opos = [event.pageX, event.pageY];

		if (this.options.disabled)
			return;

		var options = this.options;

		this.selectees = $(options.filter, this.element[0]);

		this._trigger("start", event);

		$(options.appendTo).append(this.helper);
		// position helper (lasso)
		this.helper.css({
			"left": event.clientX,
			"top": event.clientY,
			"width": 0,
			"height": 0
		});

		if (options.autoRefresh) {
			this.refresh();
		}

		this.selectees.filter('.ui-selected').each(function() {
			var selectee = $.data(this, "selectable-item");
			selectee.startselected = true;
			if (!event.metaKey) {
				selectee.$element.removeClass('ui-selected');
				selectee.selected = false;
				selectee.$element.addClass('ui-unselecting');
				selectee.unselecting = true;
				// selectable UNSELECTING callback
				self._trigger("unselecting", event, {
					unselecting: selectee.element
				});
			}
		});

		$(event.target).parents().andSelf().each(function() {
			var selectee = $.data(this, "selectable-item");
			if (selectee) {
				var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected');
				selectee.$element
					.removeClass(doSelect ? "ui-unselecting" : "ui-selected")
					.addClass(doSelect ? "ui-selecting" : "ui-unselecting");
				selectee.unselecting = !doSelect;
				selectee.selecting = doSelect;
				selectee.selected = doSelect;
				// selectable (UN)SELECTING callback
				if (doSelect) {
					self._trigger("selecting", event, {
						selecting: selectee.element
					});
				} else {
					self._trigger("unselecting", event, {
						unselecting: selectee.element
					});
				}
				return false;
			}
		});

	},

	_mouseDrag: function(event) {
		var self = this;
		this.dragged = true;

		if (this.options.disabled)
			return;

		var options = this.options;

		var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
		if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
		if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
		this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});

		this.selectees.each(function() {
			var selectee = $.data(this, "selectable-item");
			//prevent helper from being selected if appendTo: selectable
			if (!selectee || selectee.element == self.element[0])
				return;
			var hit = false;
			if (options.tolerance == 'touch') {
				hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
			} else if (options.tolerance == 'fit') {
				hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
			}

			if (hit) {
				// SELECT
				if (selectee.selected) {
					selectee.$element.removeClass('ui-selected');
					selectee.selected = false;
				}
				if (selectee.unselecting) {
					selectee.$element.removeClass('ui-unselecting');
					selectee.unselecting = false;
				}
				if (!selectee.selecting) {
					selectee.$element.addClass('ui-selecting');
					selectee.selecting = true;
					// selectable SELECTING callback
					self._trigger("selecting", event, {
						selecting: selectee.element
					});
				}
			} else {
				// UNSELECT
				if (selectee.selecting) {
					if (event.metaKey && selectee.startselected) {
						selectee.$element.removeClass('ui-selecting');
						selectee.selecting = false;
						selectee.$element.addClass('ui-selected');
						selectee.selected = true;
					} else {
						selectee.$element.removeClass('ui-selecting');
						selectee.selecting = false;
						if (selectee.startselected) {
							selectee.$element.addClass('ui-unselecting');
							selectee.unselecting = true;
						}
						// selectable UNSELECTING callback
						self._trigger("unselecting", event, {
							unselecting: selectee.element
						});
					}
				}
				if (selectee.selected) {
					if (!event.metaKey && !selectee.startselected) {
						selectee.$element.removeClass('ui-selected');
						selectee.selected = false;

						selectee.$element.addClass('ui-unselecting');
						selectee.unselecting = true;
						// selectable UNSELECTING callback
						self._trigger("unselecting", event, {
							unselecting: selectee.element
						});
					}
				}
			}
		});

		return false;
	},

	_mouseStop: function(event) {
		var self = this;

		this.dragged = false;

		var options = this.options;

		$('.ui-unselecting', this.element[0]).each(function() {
			var selectee = $.data(this, "selectable-item");
			selectee.$element.removeClass('ui-unselecting');
			selectee.unselecting = false;
			selectee.startselected = false;
			self._trigger("unselected", event, {
				unselected: selectee.element
			});
		});
		$('.ui-selecting', this.element[0]).each(function() {
			var selectee = $.data(this, "selectable-item");
			selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
			selectee.selecting = false;
			selectee.selected = true;
			selectee.startselected = true;
			self._trigger("selected", event, {
				selected: selectee.element
			});
		});
		this._trigger("stop", event);

		this.helper.remove();

		return false;
	}

});

$.extend($.ui.selectable, {
	version: "1.8.12"
});

})(jQuery);
/*
 * jQuery UI Sortable 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Sortables
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.mouse.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget("ui.sortable", $.ui.mouse, {
	widgetEventPrefix: "sort",
	options: {
		appendTo: "parent",
		axis: false,
		connectWith: false,
		containment: false,
		cursor: 'auto',
		cursorAt: false,
		dropOnEmpty: true,
		forcePlaceholderSize: false,
		forceHelperSize: false,
		grid: false,
		handle: false,
		helper: "original",
		items: '> *',
		opacity: false,
		placeholder: false,
		revert: false,
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		scope: "default",
		tolerance: "intersect",
		zIndex: 1000
	},
	_create: function() {

		var o = this.options;
		this.containerCache = {};
		this.element.addClass("ui-sortable");

		//Get the items
		this.refresh();

		//Let's determine if the items are being displayed horizontally
		this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;

		//Let's determine the parent's offset
		this.offset = this.element.offset();

		//Initialize mouse events for interaction
		this._mouseInit();

	},

	destroy: function() {
		this.element
			.removeClass("ui-sortable ui-sortable-disabled")
			.removeData("sortable")
			.unbind(".sortable");
		this._mouseDestroy();

		for ( var i = this.items.length - 1; i >= 0; i-- )
			this.items[i].item.removeData("sortable-item");

		return this;
	},

	_setOption: function(key, value){
		if ( key === "disabled" ) {
			this.options[ key ] = value;
	
			this.widget()
				[ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" );
		} else {
			// Don't call widget base _setOption for disable as it adds ui-state-disabled class
			$.Widget.prototype._setOption.apply(this, arguments);
		}
	},

	_mouseCapture: function(event, overrideHandle) {

		if (this.reverting) {
			return false;
		}

		if(this.options.disabled || this.options.type == 'static') return false;

		//We have to refresh the items data once first
		this._refreshItems(event);

		//Find out if the clicked node (or one of its parents) is a actual item in this.items
		var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
			if($.data(this, 'sortable-item') == self) {
				currentItem = $(this);
				return false;
			}
		});
		if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);

		if(!currentItem) return false;
		if(this.options.handle && !overrideHandle) {
			var validHandle = false;

			$(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
			if(!validHandle) return false;
		}

		this.currentItem = currentItem;
		this._removeCurrentsFromItems();
		return true;

	},

	_mouseStart: function(event, overrideHandle, noActivation) {

		var o = this.options, self = this;
		this.currentContainer = this;

		//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
		this.refreshPositions();

		//Create and append the visible helper
		this.helper = this._createHelper(event);

		//Cache the helper size
		this._cacheHelperProportions();

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//Get the next scrolling parent
		this.scrollParent = this.helper.scrollParent();

		//The element's absolute position on the page minus margins
		this.offset = this.currentItem.offset();
		this.offset = {
			top: this.offset.top - this.margins.top,
			left: this.offset.left - this.margins.left
		};

		// Only after we got the offset, we can change the helper's position to absolute
		// TODO: Still need to figure out a way to make relative sorting possible
		this.helper.css("position", "absolute");
		this.cssPosition = this.helper.css("position");

		$.extend(this.offset, {
			click: { //Where the click happened, relative to the element
				left: event.pageX - this.offset.left,
				top: event.pageY - this.offset.top
			},
			parent: this._getParentOffset(),
			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
		});

		//Generate the original position
		this.originalPosition = this._generatePosition(event);
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;

		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));

		//Cache the former DOM position
		this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };

		//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
		if(this.helper[0] != this.currentItem[0]) {
			this.currentItem.hide();
		}

		//Create the placeholder
		this._createPlaceholder();

		//Set a containment if given in the options
		if(o.containment)
			this._setContainment();

		if(o.cursor) { // cursor option
			if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
			$('body').css("cursor", o.cursor);
		}

		if(o.opacity) { // opacity option
			if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
			this.helper.css("opacity", o.opacity);
		}

		if(o.zIndex) { // zIndex option
			if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
			this.helper.css("zIndex", o.zIndex);
		}

		//Prepare scrolling
		if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
			this.overflowOffset = this.scrollParent.offset();

		//Call callbacks
		this._trigger("start", event, this._uiHash());

		//Recache the helper size
		if(!this._preserveHelperProportions)
			this._cacheHelperProportions();


		//Post 'activate' events to possible containers
		if(!noActivation) {
			 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); }
		}

		//Prepare possible droppables
		if($.ui.ddmanager)
			$.ui.ddmanager.current = this;

		if ($.ui.ddmanager && !o.dropBehaviour)
			$.ui.ddmanager.prepareOffsets(this, event);

		this.dragging = true;

		this.helper.addClass("ui-sortable-helper");
		this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
		return true;

	},

	_mouseDrag: function(event) {

		//Compute the helpers position
		this.position = this._generatePosition(event);
		this.positionAbs = this._convertPositionTo("absolute");

		if (!this.lastPositionAbs) {
			this.lastPositionAbs = this.positionAbs;
		}

		//Do scrolling
		if(this.options.scroll) {
			var o = this.options, scrolled = false;
			if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {

				if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
				else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;

				if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
				else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;

			} else {

				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
				else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);

				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
				else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);

			}

			if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
				$.ui.ddmanager.prepareOffsets(this, event);
		}

		//Regenerate the absolute position used for position checks
		this.positionAbs = this._convertPositionTo("absolute");

		//Set the helper position
		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';

		//Rearrange
		for (var i = this.items.length - 1; i >= 0; i--) {

			//Cache variables and intersection, continue if no intersection
			var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
			if (!intersection) continue;

			if(itemElement != this.currentItem[0] //cannot intersect with itself
				&&	this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
				&&	!$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
				&& (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
				//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
			) {

				this.direction = intersection == 1 ? "down" : "up";

				if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
					this._rearrange(event, item);
				} else {
					break;
				}

				this._trigger("change", event, this._uiHash());
				break;
			}
		}

		//Post events to containers
		this._contactContainers(event);

		//Interconnect with droppables
		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

		//Call callbacks
		this._trigger('sort', event, this._uiHash());

		this.lastPositionAbs = this.positionAbs;
		return false;

	},

	_mouseStop: function(event, noPropagation) {

		if(!event) return;

		//If we are using droppables, inform the manager about the drop
		if ($.ui.ddmanager && !this.options.dropBehaviour)
			$.ui.ddmanager.drop(this, event);

		if(this.options.revert) {
			var self = this;
			var cur = self.placeholder.offset();

			self.reverting = true;

			$(this.helper).animate({
				left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
				top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
			}, parseInt(this.options.revert, 10) || 500, function() {
				self._clear(event);
			});
		} else {
			this._clear(event, noPropagation);
		}

		return false;

	},

	cancel: function() {

		var self = this;

		if(this.dragging) {

			this._mouseUp({ target: null });

			if(this.options.helper == "original")
				this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
			else
				this.currentItem.show();

			//Post deactivating events to containers
			for (var i = this.containers.length - 1; i >= 0; i--){
				this.containers[i]._trigger("deactivate", null, self._uiHash(this));
				if(this.containers[i].containerCache.over) {
					this.containers[i]._trigger("out", null, self._uiHash(this));
					this.containers[i].containerCache.over = 0;
				}
			}

		}

		if (this.placeholder) {
			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
			if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
			if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();

			$.extend(this, {
				helper: null,
				dragging: false,
				reverting: false,
				_noFinalSort: null
			});

			if(this.domPosition.prev) {
				$(this.domPosition.prev).after(this.currentItem);
			} else {
				$(this.domPosition.parent).prepend(this.currentItem);
			}
		}

		return this;

	},

	serialize: function(o) {

		var items = this._getItemsAsjQuery(o && o.connected);
		var str = []; o = o || {};

		$(items).each(function() {
			var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
			if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
		});

		if(!str.length && o.key) {
			str.push(o.key + '=');
		}

		return str.join('&');

	},

	toArray: function(o) {

		var items = this._getItemsAsjQuery(o && o.connected);
		var ret = []; o = o || {};

		items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
		return ret;

	},

	/* Be careful with the following core functions */
	_intersectsWith: function(item) {

		var x1 = this.positionAbs.left,
			x2 = x1 + this.helperProportions.width,
			y1 = this.positionAbs.top,
			y2 = y1 + this.helperProportions.height;

		var l = item.left,
			r = l + item.width,
			t = item.top,
			b = t + item.height;

		var dyClick = this.offset.click.top,
			dxClick = this.offset.click.left;

		var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;

		if(	   this.options.tolerance == "pointer"
			|| this.options.forcePointerForContainers
			|| (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
		) {
			return isOverElement;
		} else {

			return (l < x1 + (this.helperProportions.width / 2) // Right Half
				&& x2 - (this.helperProportions.width / 2) < r // Left Half
				&& t < y1 + (this.helperProportions.height / 2) // Bottom Half
				&& y2 - (this.helperProportions.height / 2) < b ); // Top Half

		}
	},

	_intersectsWithPointer: function(item) {

		var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
			isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
			isOverElement = isOverElementHeight && isOverElementWidth,
			verticalDirection = this._getDragVerticalDirection(),
			horizontalDirection = this._getDragHorizontalDirection();

		if (!isOverElement)
			return false;

		return this.floating ?
			( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
			: ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );

	},

	_intersectsWithSides: function(item) {

		var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
			isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
			verticalDirection = this._getDragVerticalDirection(),
			horizontalDirection = this._getDragHorizontalDirection();

		if (this.floating && horizontalDirection) {
			return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
		} else {
			return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
		}

	},

	_getDragVerticalDirection: function() {
		var delta = this.positionAbs.top - this.lastPositionAbs.top;
		return delta != 0 && (delta > 0 ? "down" : "up");
	},

	_getDragHorizontalDirection: function() {
		var delta = this.positionAbs.left - this.lastPositionAbs.left;
		return delta != 0 && (delta > 0 ? "right" : "left");
	},

	refresh: function(event) {
		this._refreshItems(event);
		this.refreshPositions();
		return this;
	},

	_connectWith: function() {
		var options = this.options;
		return options.connectWith.constructor == String
			? [options.connectWith]
			: options.connectWith;
	},
	
	_getItemsAsjQuery: function(connected) {

		var self = this;
		var items = [];
		var queries = [];
		var connectWith = this._connectWith();

		if(connectWith && connected) {
			for (var i = connectWith.length - 1; i >= 0; i--){
				var cur = $(connectWith[i]);
				for (var j = cur.length - 1; j >= 0; j--){
					var inst = $.data(cur[j], 'sortable');
					if(inst && inst != this && !inst.options.disabled) {
						queries.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]);
					}
				};
			};
		}

		queries.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]);

		for (var i = queries.length - 1; i >= 0; i--){
			queries[i][0].each(function() {
				items.push(this);
			});
		};

		return $(items);

	},

	_removeCurrentsFromItems: function() {

		var list = this.currentItem.find(":data(sortable-item)");

		for (var i=0; i < this.items.length; i++) {

			for (var j=0; j < list.length; j++) {
				if(list[j] == this.items[i].item[0])
					this.items.splice(i,1);
			};

		};

	},

	_refreshItems: function(event) {

		this.items = [];
		this.containers = [this];
		var items = this.items;
		var self = this;
		var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
		var connectWith = this._connectWith();

		if(connectWith) {
			for (var i = connectWith.length - 1; i >= 0; i--){
				var cur = $(connectWith[i]);
				for (var j = cur.length - 1; j >= 0; j--){
					var inst = $.data(cur[j], 'sortable');
					if(inst && inst != this && !inst.options.disabled) {
						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
						this.containers.push(inst);
					}
				};
			};
		}

		for (var i = queries.length - 1; i >= 0; i--) {
			var targetData = queries[i][1];
			var _queries = queries[i][0];

			for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
				var item = $(_queries[j]);

				item.data('sortable-item', targetData); // Data for target checking (mouse manager)

				items.push({
					item: item,
					instance: targetData,
					width: 0, height: 0,
					left: 0, top: 0
				});
			};
		};

	},

	refreshPositions: function(fast) {

		//This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
		if(this.offsetParent && this.helper) {
			this.offset.parent = this._getParentOffset();
		}

		for (var i = this.items.length - 1; i >= 0; i--){
			var item = this.items[i];

			//We ignore calculating positions of all connected containers when we're not over them
			if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
				continue;

			var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;

			if (!fast) {
				item.width = t.outerWidth();
				item.height = t.outerHeight();
			}

			var p = t.offset();
			item.left = p.left;
			item.top = p.top;
		};

		if(this.options.custom && this.options.custom.refreshContainers) {
			this.options.custom.refreshContainers.call(this);
		} else {
			for (var i = this.containers.length - 1; i >= 0; i--){
				var p = this.containers[i].element.offset();
				this.containers[i].containerCache.left = p.left;
				this.containers[i].containerCache.top = p.top;
				this.containers[i].containerCache.width	= this.containers[i].element.outerWidth();
				this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
			};
		}

		return this;
	},

	_createPlaceholder: function(that) {

		var self = that || this, o = self.options;

		if(!o.placeholder || o.placeholder.constructor == String) {
			var className = o.placeholder;
			o.placeholder = {
				element: function() {

					var el = $(document.createElement(self.currentItem[0].nodeName))
						.addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
						.removeClass("ui-sortable-helper")[0];

					if(!className)
						el.style.visibility = "hidden";

					return el;
				},
				update: function(container, p) {

					// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
					if(className && !o.forcePlaceholderSize) return;

					//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
					if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
					if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
				}
			};
		}

		//Create the placeholder
		self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));

		//Append it after the actual current item
		self.currentItem.after(self.placeholder);

		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
		o.placeholder.update(self, self.placeholder);

	},

	_contactContainers: function(event) {
		
		// get innermost container that intersects with item 
		var innermostContainer = null, innermostIndex = null;		
		
		
		for (var i = this.containers.length - 1; i >= 0; i--){

			// never consider a container that's located within the item itself 
			if($.ui.contains(this.currentItem[0], this.containers[i].element[0]))
				continue;

			if(this._intersectsWith(this.containers[i].containerCache)) {

				// if we've already found a container and it's more "inner" than this, then continue 
				if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0]))
					continue;

				innermostContainer = this.containers[i]; 
				innermostIndex = i;
					
			} else {
				// container doesn't intersect. trigger "out" event if necessary 
				if(this.containers[i].containerCache.over) {
					this.containers[i]._trigger("out", event, this._uiHash(this));
					this.containers[i].containerCache.over = 0;
				}
			}

		}
		
		// if no intersecting containers found, return 
		if(!innermostContainer) return; 

		// move the item into the container if it's not there already
		if(this.containers.length === 1) {
			this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
			this.containers[innermostIndex].containerCache.over = 1;
		} else if(this.currentContainer != this.containers[innermostIndex]) { 

			//When entering a new container, we will find the item with the least distance and append our item near it 
			var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top']; 
			for (var j = this.items.length - 1; j >= 0; j--) { 
				if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; 
				var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top']; 
				if(Math.abs(cur - base) < dist) { 
					dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; 
				} 
			} 

			if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled 
				return; 

			this.currentContainer = this.containers[innermostIndex]; 
			itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); 
			this._trigger("change", event, this._uiHash()); 
			this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); 

			//Update the placeholder 
			this.options.placeholder.update(this.currentContainer, this.placeholder); 
		
			this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 
			this.containers[innermostIndex].containerCache.over = 1;
		} 
	
		
	},

	_createHelper: function(event) {

		var o = this.options;
		var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);

		if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
			$(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);

		if(helper[0] == this.currentItem[0])
			this._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") };

		if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
		if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());

		return helper;

	},

	_adjustOffsetFromHelper: function(obj) {
		if (typeof obj == 'string') {
			obj = obj.split(' ');
		}
		if ($.isArray(obj)) {
			obj = {left: +obj[0], top: +obj[1] || 0};
		}
		if ('left' in obj) {
			this.offset.click.left = obj.left + this.margins.left;
		}
		if ('right' in obj) {
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		}
		if ('top' in obj) {
			this.offset.click.top = obj.top + this.margins.top;
		}
		if ('bottom' in obj) {
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
		}
	},

	_getParentOffset: function() {


		//Get the offsetParent and cache its position
		this.offsetParent = this.helper.offsetParent();
		var po = this.offsetParent.offset();

		// This is a special case where we need to modify a offset calculated on start, since the following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
		if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
			po = { top: 0, left: 0 };

		return {
			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
		};

	},

	_getRelativeOffset: function() {

		if(this.cssPosition == "relative") {
			var p = this.currentItem.position();
			return {
				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
			};
		} else {
			return { top: 0, left: 0 };
		}

	},

	_cacheMargins: function() {
		this.margins = {
			left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
			top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var o = this.options;
		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
		if(o.containment == 'document' || o.containment == 'window') this.containment = [
			0 - this.offset.relative.left - this.offset.parent.left,
			0 - this.offset.relative.top - this.offset.parent.top,
			$(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
			($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
		];

		if(!(/^(document|window|parent)$/).test(o.containment)) {
			var ce = $(o.containment)[0];
			var co = $(o.containment).offset();
			var over = ($(ce).css("overflow") != 'hidden');

			this.containment = [
				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
				co.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,
				co.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
			];
		}

	},

	_convertPositionTo: function(d, pos) {

		if(!pos) pos = this.position;
		var mod = d == "absolute" ? 1 : -1;
		var 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);

		return {
			top: (
				pos.top																	// The absolute mouse position
				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
				- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
			),
			left: (
				pos.left																// The absolute mouse position
				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
				- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
			)
		};

	},

	_generatePosition: function(event) {

		var 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);

		// This is another very weird special case that only happens for relative elements:
		// 1. If the css position is relative
		// 2. and the scroll parent is the document or similar to the offset parent
		// we have to refresh the relative offset during the scroll so there are no jumps
		if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
			this.offset.relative = this._getRelativeOffset();
		}

		var pageX = event.pageX;
		var pageY = event.pageY;

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		if(this.originalPosition) { //If we are not dragging yet, we won't check for options

			if(this.containment) {
				if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
				if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
				if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
				if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
			}

			if(o.grid) {
				var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
				pageY = 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;

				var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
				pageX = 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;
			}

		}

		return {
			top: (
				pageY																// The absolute mouse position
				- this.offset.click.top													// Click offset (relative to the element)
				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
			),
			left: (
				pageX																// The absolute mouse position
				- this.offset.click.left												// Click offset (relative to the element)
				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
			)
		};

	},

	_rearrange: function(event, i, a, hardRefresh) {

		a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));

		//Various things done here to improve the performance:
		// 1. we create a setTimeout, that calls refreshPositions
		// 2. on the instance, we have a counter variable, that get's higher after every append
		// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
		// 4. this lets only the last addition to the timeout stack through
		this.counter = this.counter ? ++this.counter : 1;
		var self = this, counter = this.counter;

		window.setTimeout(function() {
			if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
		},0);

	},

	_clear: function(event, noPropagation) {

		this.reverting = false;
		// We delay all events that have to be triggered to after the point where the placeholder has been removed and
		// everything else normalized again
		var delayedTriggers = [], self = this;

		// We first have to update the dom position of the actual currentItem
		// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
		if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem);
		this._noFinalSort = null;

		if(this.helper[0] == this.currentItem[0]) {
			for(var i in this._storedCSS) {
				if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
			}
			this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
		} else {
			this.currentItem.show();
		}

		if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
		if((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
		if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
			if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
			for (var i = this.containers.length - 1; i >= 0; i--){
				if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {
					delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
					delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this));  }; }).call(this, this.containers[i]));
				}
			};
		};

		//Post events to containers
		for (var i = this.containers.length - 1; i >= 0; i--){
			if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
			if(this.containers[i].containerCache.over) {
				delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
				this.containers[i].containerCache.over = 0;
			}
		}

		//Do what was originally in plugins
		if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
		if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
		if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index

		this.dragging = false;
		if(this.cancelHelperRemoval) {
			if(!noPropagation) {
				this._trigger("beforeStop", event, this._uiHash());
				for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
				this._trigger("stop", event, this._uiHash());
			}
			return false;
		}

		if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());

		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
		this.placeholder[0].parentNode.removeChild(this.placeholder[0]);

		if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;

		if(!noPropagation) {
			for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
			this._trigger("stop", event, this._uiHash());
		}

		this.fromOutside = false;
		return true;

	},

	_trigger: function() {
		if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
			this.cancel();
		}
	},

	_uiHash: function(inst) {
		var self = inst || this;
		return {
			helper: self.helper,
			placeholder: self.placeholder || $([]),
			position: self.position,
			originalPosition: self.originalPosition,
			offset: self.positionAbs,
			item: self.currentItem,
			sender: inst ? inst.element : null
		};
	}

});

$.extend($.ui.sortable, {
	version: "1.8.12"
});

})(jQuery);
/*
 * jQuery UI Effects 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/
 */
;jQuery.effects || (function($, undefined) {

$.effects = {};



/******************************************************************************/
/****************************** COLOR ANIMATIONS ******************************/
/******************************************************************************/

// override the animation for color styles
$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',
	'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'],
function(i, attr) {
	$.fx.step[attr] = function(fx) {
		if (!fx.colorInit) {
			fx.start = getColor(fx.elem, attr);
			fx.end = getRGB(fx.end);
			fx.colorInit = true;
		}

		fx.elem.style[attr] = 'rgb(' +
			Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +
			Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +
			Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';
	};
});

// Color Conversion functions from highlightFade
// By Blair Mitchelmore
// http://jquery.offput.ca/highlightFade/

// Parse strings looking for color tuples [255,255,255]
function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
				return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
				return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
				return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
				return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
				return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Look for rgba(0, 0, 0, 0) == transparent in Safari 3
		if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
				return colors['transparent'];

		// Otherwise, we're most likely dealing with a named color
		return colors[$.trim(color).toLowerCase()];
}

function getColor(elem, attr) {
		var color;

		do {
				color = $.curCSS(elem, attr);

				// Keep going until we find an element that has color, or we hit the body
				if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") )
						break;

				attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
};

// Some named colors to work with
// From Interface by Stefan Petre
// http://interface.eyecon.ro/

var colors = {
	aqua:[0,255,255],
	azure:[240,255,255],
	beige:[245,245,220],
	black:[0,0,0],
	blue:[0,0,255],
	brown:[165,42,42],
	cyan:[0,255,255],
	darkblue:[0,0,139],
	darkcyan:[0,139,139],
	darkgrey:[169,169,169],
	darkgreen:[0,100,0],
	darkkhaki:[189,183,107],
	darkmagenta:[139,0,139],
	darkolivegreen:[85,107,47],
	darkorange:[255,140,0],
	darkorchid:[153,50,204],
	darkred:[139,0,0],
	darksalmon:[233,150,122],
	darkviolet:[148,0,211],
	fuchsia:[255,0,255],
	gold:[255,215,0],
	green:[0,128,0],
	indigo:[75,0,130],
	khaki:[240,230,140],
	lightblue:[173,216,230],
	lightcyan:[224,255,255],
	lightgreen:[144,238,144],
	lightgrey:[211,211,211],
	lightpink:[255,182,193],
	lightyellow:[255,255,224],
	lime:[0,255,0],
	magenta:[255,0,255],
	maroon:[128,0,0],
	navy:[0,0,128],
	olive:[128,128,0],
	orange:[255,165,0],
	pink:[255,192,203],
	purple:[128,0,128],
	violet:[128,0,128],
	red:[255,0,0],
	silver:[192,192,192],
	white:[255,255,255],
	yellow:[255,255,0],
	transparent: [255,255,255]
};



/******************************************************************************/
/****************************** CLASS ANIMATIONS ******************************/
/******************************************************************************/

var classAnimationActions = ['add', 'remove', 'toggle'],
	shorthandStyles = {
		border: 1,
		borderBottom: 1,
		borderColor: 1,
		borderLeft: 1,
		borderRight: 1,
		borderTop: 1,
		borderWidth: 1,
		margin: 1,
		padding: 1
	};

function getElementStyles() {
	var style = document.defaultView
			? document.defaultView.getComputedStyle(this, null)
			: this.currentStyle,
		newStyle = {},
		key,
		camelCase;

	// webkit enumerates style porperties
	if (style && style.length && style[0] && style[style[0]]) {
		var len = style.length;
		while (len--) {
			key = style[len];
			if (typeof style[key] == 'string') {
				camelCase = key.replace(/\-(\w)/g, function(all, letter){
					return letter.toUpperCase();
				});
				newStyle[camelCase] = style[key];
			}
		}
	} else {
		for (key in style) {
			if (typeof style[key] === 'string') {
				newStyle[key] = style[key];
			}
		}
	}
	
	return newStyle;
}

function filterStyles(styles) {
	var name, value;
	for (name in styles) {
		value = styles[name];
		if (
			// ignore null and undefined values
			value == null ||
			// ignore functions (when does this occur?)
			$.isFunction(value) ||
			// shorthand styles that need to be expanded
			name in shorthandStyles ||
			// ignore scrollbars (break in IE)
			(/scrollbar/).test(name) ||

			// only colors or values that can be converted to numbers
			(!(/color/i).test(name) && isNaN(parseFloat(value)))
		) {
			delete styles[name];
		}
	}
	
	return styles;
}

function styleDifference(oldStyle, newStyle) {
	var diff = { _: 0 }, // http://dev.jquery.com/ticket/5459
		name;

	for (name in newStyle) {
		if (oldStyle[name] != newStyle[name]) {
			diff[name] = newStyle[name];
		}
	}

	return diff;
}

$.effects.animateClass = function(value, duration, easing, callback) {
	if ($.isFunction(easing)) {
		callback = easing;
		easing = null;
	}

	return this.queue('fx', function() {
		var that = $(this),
			originalStyleAttr = that.attr('style') || ' ',
			originalStyle = filterStyles(getElementStyles.call(this)),
			newStyle,
			className = that.attr('className');

		$.each(classAnimationActions, function(i, action) {
			if (value[action]) {
				that[action + 'Class'](value[action]);
			}
		});
		newStyle = filterStyles(getElementStyles.call(this));
		that.attr('className', className);

		that.animate(styleDifference(originalStyle, newStyle), duration, easing, function() {
			$.each(classAnimationActions, function(i, action) {
				if (value[action]) { that[action + 'Class'](value[action]); }
			});
			// work around bug in IE by clearing the cssText before setting it
			if (typeof that.attr('style') == 'object') {
				that.attr('style').cssText = '';
				that.attr('style').cssText = originalStyleAttr;
			} else {
				that.attr('style', originalStyleAttr);
			}
			if (callback) { callback.apply(this, arguments); }
		});

		// $.animate adds a function to the end of the queue
		// but we want it at the front
		var queue = $.queue(this),
			anim = queue.splice(queue.length - 1, 1)[0];
		queue.splice(1, 0, anim);
		$.dequeue(this);
	});
};

$.fn.extend({
	_addClass: $.fn.addClass,
	addClass: function(classNames, speed, easing, callback) {
		return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);
	},

	_removeClass: $.fn.removeClass,
	removeClass: function(classNames,speed,easing,callback) {
		return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);
	},

	_toggleClass: $.fn.toggleClass,
	toggleClass: function(classNames, force, speed, easing, callback) {
		if ( typeof force == "boolean" || force === undefined ) {
			if ( !speed ) {
				// without speed parameter;
				return this._toggleClass(classNames, force);
			} else {
				return $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]);
			}
		} else {
			// without switch parameter;
			return $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]);
		}
	},

	switchClass: function(remove,add,speed,easing,callback) {
		return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);
	}
});



/******************************************************************************/
/*********************************** EFFECTS **********************************/
/******************************************************************************/

$.extend($.effects, {
	version: "1.8.12",

	// Saves a set of properties in a data storage
	save: function(element, set) {
		for(var i=0; i < set.length; i++) {
			if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]);
		}
	},

	// Restores a set of previously saved properties from a data storage
	restore: function(element, set) {
		for(var i=0; i < set.length; i++) {
			if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i]));
		}
	},

	setMode: function(el, mode) {
		if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle
		return mode;
	},

	getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value
		// this should be a little more flexible in the future to handle a string & hash
		var y, x;
		switch (origin[0]) {
			case 'top': y = 0; break;
			case 'middle': y = 0.5; break;
			case 'bottom': y = 1; break;
			default: y = origin[0] / original.height;
		};
		switch (origin[1]) {
			case 'left': x = 0; break;
			case 'center': x = 0.5; break;
			case 'right': x = 1; break;
			default: x = origin[1] / original.width;
		};
		return {x: x, y: y};
	},

	// Wraps the element around a wrapper that copies position properties
	createWrapper: function(element) {

		// if the element is already wrapped, return it
		if (element.parent().is('.ui-effects-wrapper')) {
			return element.parent();
		}

		// wrap the element
		var props = {
				width: element.outerWidth(true),
				height: element.outerHeight(true),
				'float': element.css('float')
			},
			wrapper = $('<div></div>')
				.addClass('ui-effects-wrapper')
				.css({
					fontSize: '100%',
					background: 'transparent',
					border: 'none',
					margin: 0,
					padding: 0
				});

		element.wrap(wrapper);
		wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element

		// transfer positioning properties to the wrapper
		if (element.css('position') == 'static') {
			wrapper.css({ position: 'relative' });
			element.css({ position: 'relative' });
		} else {
			$.extend(props, {
				position: element.css('position'),
				zIndex: element.css('z-index')
			});
			$.each(['top', 'left', 'bottom', 'right'], function(i, pos) {
				props[pos] = element.css(pos);
				if (isNaN(parseInt(props[pos], 10))) {
					props[pos] = 'auto';
				}
			});
			element.css({position: 'relative', top: 0, left: 0, right: 'auto', bottom: 'auto' });
		}

		return wrapper.css(props).show();
	},

	removeWrapper: function(element) {
		if (element.parent().is('.ui-effects-wrapper'))
			return element.parent().replaceWith(element);
		return element;
	},

	setTransition: function(element, list, factor, value) {
		value = value || {};
		$.each(list, function(i, x){
			unit = element.cssUnit(x);
			if (unit[0] > 0) value[x] = unit[0] * factor + unit[1];
		});
		return value;
	}
});


function _normalizeArguments(effect, options, speed, callback) {
	// shift params for method overloading
	if (typeof effect == 'object') {
		callback = options;
		speed = null;
		options = effect;
		effect = options.effect;
	}
	if ($.isFunction(options)) {
		callback = options;
		speed = null;
		options = {};
	}
        if (typeof options == 'number' || $.fx.speeds[options]) {
		callback = speed;
		speed = options;
		options = {};
	}
	if ($.isFunction(speed)) {
		callback = speed;
		speed = null;
	}

	options = options || {};

	speed = speed || options.duration;
	speed = $.fx.off ? 0 : typeof speed == 'number'
		? speed : speed in $.fx.speeds ? $.fx.speeds[speed] : $.fx.speeds._default;

	callback = callback || options.complete;

	return [effect, options, speed, callback];
}

function standardSpeed( speed ) {
	// valid standard speeds
	if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
		return true;
	}
	
	// invalid strings - treat as "normal" speed
	if ( typeof speed === "string" && !$.effects[ speed ] ) {
		return true;
	}
	
	return false;
}

$.fn.extend({
	effect: function(effect, options, speed, callback) {
		var args = _normalizeArguments.apply(this, arguments),
			// TODO: make effects take actual parameters instead of a hash
			args2 = {
				options: args[1],
				duration: args[2],
				callback: args[3]
			},
			mode = args2.options.mode,
			effectMethod = $.effects[effect];
		
		if ( $.fx.off || !effectMethod ) {
			// delegate to the original method (e.g., .show()) if possible
			if ( mode ) {
				return this[ mode ]( args2.duration, args2.callback );
			} else {
				return this.each(function() {
					if ( args2.callback ) {
						args2.callback.call( this );
					}
				});
			}
		}
		
		return effectMethod.call(this, args2);
	},

	_show: $.fn.show,
	show: function(speed) {
		if ( standardSpeed( speed ) ) {
			return this._show.apply(this, arguments);
		} else {
			var args = _normalizeArguments.apply(this, arguments);
			args[1].mode = 'show';
			return this.effect.apply(this, args);
		}
	},

	_hide: $.fn.hide,
	hide: function(speed) {
		if ( standardSpeed( speed ) ) {
			return this._hide.apply(this, arguments);
		} else {
			var args = _normalizeArguments.apply(this, arguments);
			args[1].mode = 'hide';
			return this.effect.apply(this, args);
		}
	},

	// jQuery core overloads toggle and creates _toggle
	__toggle: $.fn.toggle,
	toggle: function(speed) {
		if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
			return this.__toggle.apply(this, arguments);
		} else {
			var args = _normalizeArguments.apply(this, arguments);
			args[1].mode = 'toggle';
			return this.effect.apply(this, args);
		}
	},

	// helper functions
	cssUnit: function(key) {
		var style = this.css(key), val = [];
		$.each( ['em','px','%','pt'], function(i, unit){
			if(style.indexOf(unit) > 0)
				val = [parseFloat(style), unit];
		});
		return val;
	}
});



/******************************************************************************/
/*********************************** EASING ***********************************/
/******************************************************************************/

/*
 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
 *
 * Uses the built in easing capabilities added In jQuery 1.1
 * to offer multiple easing options
 *
 * TERMS OF USE - jQuery Easing
 *
 * Open source under the BSD License.
 *
 * Copyright 2008 George McGinley Smith
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 *
 * Neither the name of the author nor the names of contributors may be used to endorse
 * or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/

// t: current time, b: begInnIng value, c: change In value, d: duration
$.easing.jswing = $.easing.swing;

$.extend($.easing,
{
	def: 'easeOutQuad',
	swing: function (x, t, b, c, d) {
		//alert($.easing.default);
		return $.easing[$.easing.def](x, t, b, c, d);
	},
	easeInQuad: function (x, t, b, c, d) {
		return c*(t/=d)*t + b;
	},
	easeOutQuad: function (x, t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	},
	easeInOutQuad: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	easeInCubic: function (x, t, b, c, d) {
		return c*(t/=d)*t*t + b;
	},
	easeOutCubic: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t + 1) + b;
	},
	easeInOutCubic: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t + b;
		return c/2*((t-=2)*t*t + 2) + b;
	},
	easeInQuart: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	},
	easeOutQuart: function (x, t, b, c, d) {
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},
	easeInOutQuart: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	},
	easeInQuint: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t*t + b;
	},
	easeOutQuint: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	},
	easeInOutQuint: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
		return c/2*((t-=2)*t*t*t*t + 2) + b;
	},
	easeInSine: function (x, t, b, c, d) {
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
	},
	easeOutSine: function (x, t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	},
	easeInOutSine: function (x, t, b, c, d) {
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
	},
	easeInExpo: function (x, t, b, c, d) {
		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	easeOutExpo: function (x, t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	easeInOutExpo: function (x, t, b, c, d) {
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
	easeInCirc: function (x, t, b, c, d) {
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
	},
	easeOutCirc: function (x, t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	},
	easeInOutCirc: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	},
	easeInElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	easeOutElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},
	easeInOutElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	},
	easeInBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	easeOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	},
	easeInOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	},
	easeInBounce: function (x, t, b, c, d) {
		return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;
	},
	easeOutBounce: function (x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},
	easeInOutBounce: function (x, t, b, c, d) {
		if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
		return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
	}
});

/*
 *
 * TERMS OF USE - EASING EQUATIONS
 *
 * Open source under the BSD License.
 *
 * Copyright 2001 Robert Penner
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 *
 * Neither the name of the author nor the names of contributors may be used to endorse
 * or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

})(jQuery);
/*
 * jQuery UI Effects Blind 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Blind
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.blind = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
		var direction = o.options.direction || 'vertical'; // Default direction

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
		var ref = (direction == 'vertical') ? 'height' : 'width';
		var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width();
		if(mode == 'show') wrapper.css(ref, 0); // Shift

		// Animation
		var animation = {};
		animation[ref] = mode == 'show' ? distance : 0;

		// Animate
		wrapper.animate(animation, o.duration, o.options.easing, function() {
			if(mode == 'hide') el.hide(); // Hide
			$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(el[0], arguments); // Callback
			el.dequeue();
		});

	});

};

})(jQuery);
/*
 * jQuery UI Effects Bounce 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Bounce
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.bounce = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
		var direction = o.options.direction || 'up'; // Default direction
		var distance = o.options.distance || 20; // Default distance
		var times = o.options.times || 5; // Default # of times
		var speed = o.duration || 250; // Default speed per bounce
		if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		$.effects.createWrapper(el); // Create Wrapper
		var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
		var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
		var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3);
		if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
		if (mode == 'hide') distance = distance / (times * 2);
		if (mode != 'hide') times--;

		// Animate
		if (mode == 'show') { // Show Bounce
			var animation = {opacity: 1};
			animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
			el.animate(animation, speed / 2, o.options.easing);
			distance = distance / 2;
			times--;
		};
		for (var i = 0; i < times; i++) { // Bounces
			var animation1 = {}, animation2 = {};
			animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
			animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
			el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing);
			distance = (mode == 'hide') ? distance * 2 : distance / 2;
		};
		if (mode == 'hide') { // Last Bounce
			var animation = {opacity: 0};
			animation[ref] = (motion == 'pos' ? '-=' : '+=')  + distance;
			el.animate(animation, speed / 2, o.options.easing, function(){
				el.hide(); // Hide
				$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
				if(o.callback) o.callback.apply(this, arguments); // Callback
			});
		} else {
			var animation1 = {}, animation2 = {};
			animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
			animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
			el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){
				$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
				if(o.callback) o.callback.apply(this, arguments); // Callback
			});
		};
		el.queue('fx', function() { el.dequeue(); });
		el.dequeue();
	});

};

})(jQuery);
/*
 * jQuery UI Effects Clip 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Clip
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.clip = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right','height','width'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
		var direction = o.options.direction || 'vertical'; // Default direction

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
		var animate = el[0].tagName == 'IMG' ? wrapper : el;
		var ref = {
			size: (direction == 'vertical') ? 'height' : 'width',
			position: (direction == 'vertical') ? 'top' : 'left'
		};
		var distance = (direction == 'vertical') ? animate.height() : animate.width();
		if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift

		// Animation
		var animation = {};
		animation[ref.size] = mode == 'show' ? distance : 0;
		animation[ref.position] = mode == 'show' ? 0 : distance / 2;

		// Animate
		animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
			if(mode == 'hide') el.hide(); // Hide
			$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(el[0], arguments); // Callback
			el.dequeue();
		}});

	});

};

})(jQuery);
/*
 * jQuery UI Effects Drop 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Drop
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.drop = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right','opacity'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
		var direction = o.options.direction || 'left'; // Default Direction

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		$.effects.createWrapper(el); // Create Wrapper
		var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
		var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
		var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2);
		if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift

		// Animation
		var animation = {opacity: mode == 'show' ? 1 : 0};
		animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;

		// Animate
		el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
			if(mode == 'hide') el.hide(); // Hide
			$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(this, arguments); // Callback
			el.dequeue();
		}});

	});

};

})(jQuery);
/*
 * jQuery UI Effects Explode 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Explode
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.explode = function(o) {

	return this.queue(function() {

	var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
	var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;

	o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode;
	var el = $(this).show().css('visibility', 'hidden');
	var offset = el.offset();

	//Substract the margins - not fixing the problem yet.
	offset.top -= parseInt(el.css("marginTop"),10) || 0;
	offset.left -= parseInt(el.css("marginLeft"),10) || 0;

	var width = el.outerWidth(true);
	var height = el.outerHeight(true);

	for(var i=0;i<rows;i++) { // =
		for(var j=0;j<cells;j++) { // ||
			el
				.clone()
				.appendTo('body')
				.wrap('<div></div>')
				.css({
					position: 'absolute',
					visibility: 'visible',
					left: -j*(width/cells),
					top: -i*(height/rows)
				})
				.parent()
				.addClass('ui-effects-explode')
				.css({
					position: 'absolute',
					overflow: 'hidden',
					width: width/cells,
					height: height/rows,
					left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0),
					top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0),
					opacity: o.options.mode == 'show' ? 0 : 1
				}).animate({
					left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)),
					top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)),
					opacity: o.options.mode == 'show' ? 1 : 0
				}, o.duration || 500);
		}
	}

	// Set a timeout, to call the callback approx. when the other animations have finished
	setTimeout(function() {

		o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide();
				if(o.callback) o.callback.apply(el[0]); // Callback
				el.dequeue();

				$('div.ui-effects-explode').remove();

	}, o.duration || 500);


	});

};

})(jQuery);
/*
 * jQuery UI Effects Fade 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Fade
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.fade = function(o) {
	return this.queue(function() {
		var elem = $(this),
			mode = $.effects.setMode(elem, o.options.mode || 'hide');

		elem.animate({ opacity: mode }, {
			queue: false,
			duration: o.duration,
			easing: o.options.easing,
			complete: function() {
				(o.callback && o.callback.apply(this, arguments));
				elem.dequeue();
			}
		});
	});
};

})(jQuery);
/*
 * jQuery UI Effects Fold 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Fold
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.fold = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
		var size = o.options.size || 15; // Default fold size
		var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value
		var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
		var widthFirst = ((mode == 'show') != horizFirst);
		var ref = widthFirst ? ['width', 'height'] : ['height', 'width'];
		var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()];
		var percent = /([0-9]+)%/.exec(size);
		if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1];
		if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift

		// Animation
		var animation1 = {}, animation2 = {};
		animation1[ref[0]] = mode == 'show' ? distance[0] : size;
		animation2[ref[1]] = mode == 'show' ? distance[1] : 0;

		// Animate
		wrapper.animate(animation1, duration, o.options.easing)
		.animate(animation2, duration, o.options.easing, function() {
			if(mode == 'hide') el.hide(); // Hide
			$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(el[0], arguments); // Callback
			el.dequeue();
		});

	});

};

})(jQuery);
/*
 * jQuery UI Effects Highlight 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Highlight
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.highlight = function(o) {
	return this.queue(function() {
		var elem = $(this),
			props = ['backgroundImage', 'backgroundColor', 'opacity'],
			mode = $.effects.setMode(elem, o.options.mode || 'show'),
			animation = {
				backgroundColor: elem.css('backgroundColor')
			};

		if (mode == 'hide') {
			animation.opacity = 0;
		}

		$.effects.save(elem, props);
		elem
			.show()
			.css({
				backgroundImage: 'none',
				backgroundColor: o.options.color || '#ffff99'
			})
			.animate(animation, {
				queue: false,
				duration: o.duration,
				easing: o.options.easing,
				complete: function() {
					(mode == 'hide' && elem.hide());
					$.effects.restore(elem, props);
					(mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter'));
					(o.callback && o.callback.apply(this, arguments));
					elem.dequeue();
				}
			});
	});
};

})(jQuery);
/*
 * jQuery UI Effects Pulsate 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Pulsate
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.pulsate = function(o) {
	return this.queue(function() {
		var elem = $(this),
			mode = $.effects.setMode(elem, o.options.mode || 'show');
			times = ((o.options.times || 5) * 2) - 1;
			duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2,
			isVisible = elem.is(':visible'),
			animateTo = 0;

		if (!isVisible) {
			elem.css('opacity', 0).show();
			animateTo = 1;
		}

		if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) {
			times--;
		}

		for (var i = 0; i < times; i++) {
			elem.animate({ opacity: animateTo }, duration, o.options.easing);
			animateTo = (animateTo + 1) % 2;
		}

		elem.animate({ opacity: animateTo }, duration, o.options.easing, function() {
			if (animateTo == 0) {
				elem.hide();
			}
			(o.callback && o.callback.apply(this, arguments));
		});

		elem
			.queue('fx', function() { elem.dequeue(); })
			.dequeue();
	});
};

})(jQuery);
/*
 * jQuery UI Effects Scale 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Scale
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.puff = function(o) {
	return this.queue(function() {
		var elem = $(this),
			mode = $.effects.setMode(elem, o.options.mode || 'hide'),
			percent = parseInt(o.options.percent, 10) || 150,
			factor = percent / 100,
			original = { height: elem.height(), width: elem.width() };

		$.extend(o.options, {
			fade: true,
			mode: mode,
			percent: mode == 'hide' ? percent : 100,
			from: mode == 'hide'
				? original
				: {
					height: original.height * factor,
					width: original.width * factor
				}
		});

		elem.effect('scale', o.options, o.duration, o.callback);
		elem.dequeue();
	});
};

$.effects.scale = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this);

		// Set options
		var options = $.extend(true, {}, o.options);
		var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
		var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent
		var direction = o.options.direction || 'both'; // Set default axis
		var origin = o.options.origin; // The origin of the scaling
		if (mode != 'effect') { // Set default origin and restore for show/hide
			options.origin = origin || ['middle','center'];
			options.restore = true;
		}
		var original = {height: el.height(), width: el.width()}; // Save original
		el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state

		// Adjust
		var factor = { // Set scaling factor
			y: direction != 'horizontal' ? (percent / 100) : 1,
			x: direction != 'vertical' ? (percent / 100) : 1
		};
		el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state

		if (o.options.fade) { // Fade option to support puff
			if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;};
			if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;};
		};

		// Animation
		options.from = el.from; options.to = el.to; options.mode = mode;

		// Animate
		el.effect('size', options, o.duration, o.callback);
		el.dequeue();
	});

};

$.effects.size = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right','width','height','overflow','opacity'];
		var props1 = ['position','top','bottom','left','right','overflow','opacity']; // Always restore
		var props2 = ['width','height','overflow']; // Copy for children
		var cProps = ['fontSize'];
		var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];
		var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
		var restore = o.options.restore || false; // Default restore
		var scale = o.options.scale || 'both'; // Default scale mode
		var origin = o.options.origin; // The origin of the sizing
		var original = {height: el.height(), width: el.width()}; // Save original
		el.from = o.options.from || original; // Default from state
		el.to = o.options.to || original; // Default to state
		// Adjust
		if (origin) { // Calculate baseline shifts
			var baseline = $.effects.getBaseline(origin, original);
			el.from.top = (original.height - el.from.height) * baseline.y;
			el.from.left = (original.width - el.from.width) * baseline.x;
			el.to.top = (original.height - el.to.height) * baseline.y;
			el.to.left = (original.width - el.to.width) * baseline.x;
		};
		var factor = { // Set scaling factor
			from: {y: el.from.height / original.height, x: el.from.width / original.width},
			to: {y: el.to.height / original.height, x: el.to.width / original.width}
		};
		if (scale == 'box' || scale == 'both') { // Scale the css box
			if (factor.from.y != factor.to.y) { // Vertical props scaling
				props = props.concat(vProps);
				el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from);
				el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to);
			};
			if (factor.from.x != factor.to.x) { // Horizontal props scaling
				props = props.concat(hProps);
				el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from);
				el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to);
			};
		};
		if (scale == 'content' || scale == 'both') { // Scale the content
			if (factor.from.y != factor.to.y) { // Vertical props scaling
				props = props.concat(cProps);
				el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from);
				el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to);
			};
		};
		$.effects.save(el, restore ? props : props1); el.show(); // Save & Show
		$.effects.createWrapper(el); // Create Wrapper
		el.css('overflow','hidden').css(el.from); // Shift

		// Animate
		if (scale == 'content' || scale == 'both') { // Scale the children
			vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size
			hProps = hProps.concat(['marginLeft','marginRight']); // Add margins
			props2 = props.concat(vProps).concat(hProps); // Concat
			el.find("*[width]").each(function(){
				child = $(this);
				if (restore) $.effects.save(child, props2);
				var c_original = {height: child.height(), width: child.width()}; // Save original
				child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x};
				child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x};
				if (factor.from.y != factor.to.y) { // Vertical props scaling
					child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from);
					child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to);
				};
				if (factor.from.x != factor.to.x) { // Horizontal props scaling
					child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from);
					child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to);
				};
				child.css(child.from); // Shift children
				child.animate(child.to, o.duration, o.options.easing, function(){
					if (restore) $.effects.restore(child, props2); // Restore children
				}); // Animate children
			});
		};

		// Animate
		el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
			if (el.to.opacity === 0) {
				el.css('opacity', el.from.opacity);
			}
			if(mode == 'hide') el.hide(); // Hide
			$.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(this, arguments); // Callback
			el.dequeue();
		}});

	});

};

})(jQuery);
/*
 * jQuery UI Effects Shake 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Shake
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.shake = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
		var direction = o.options.direction || 'left'; // Default direction
		var distance = o.options.distance || 20; // Default distance
		var times = o.options.times || 3; // Default # of times
		var speed = o.duration || o.options.duration || 140; // Default speed per shake

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		$.effects.createWrapper(el); // Create Wrapper
		var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
		var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';

		// Animation
		var animation = {}, animation1 = {}, animation2 = {};
		animation[ref] = (motion == 'pos' ? '-=' : '+=')  + distance;
		animation1[ref] = (motion == 'pos' ? '+=' : '-=')  + distance * 2;
		animation2[ref] = (motion == 'pos' ? '-=' : '+=')  + distance * 2;

		// Animate
		el.animate(animation, speed, o.options.easing);
		for (var i = 1; i < times; i++) { // Shakes
			el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing);
		};
		el.animate(animation1, speed, o.options.easing).
		animate(animation, speed / 2, o.options.easing, function(){ // Last shake
			$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(this, arguments); // Callback
		});
		el.queue('fx', function() { el.dequeue(); });
		el.dequeue();
	});

};

})(jQuery);
/*
 * jQuery UI Effects Slide 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Slide
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.slide = function(o) {

	return this.queue(function() {

		// Create element
		var el = $(this), props = ['position','top','bottom','left','right'];

		// Set options
		var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
		var direction = o.options.direction || 'left'; // Default Direction

		// Adjust
		$.effects.save(el, props); el.show(); // Save & Show
		$.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
		var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
		var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
		var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true}));
		if (mode == 'show') el.css(ref, motion == 'pos' ? (isNaN(distance) ? "-" + distance : -distance) : distance); // Shift

		// Animation
		var animation = {};
		animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;

		// Animate
		el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
			if(mode == 'hide') el.hide(); // Hide
			$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
			if(o.callback) o.callback.apply(this, arguments); // Callback
			el.dequeue();
		}});

	});

};

})(jQuery);
/*
 * jQuery UI Effects Transfer 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Transfer
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.transfer = function(o) {
	return this.queue(function() {
		var elem = $(this),
			target = $(o.options.to),
			endPosition = target.offset(),
			animation = {
				top: endPosition.top,
				left: endPosition.left,
				height: target.innerHeight(),
				width: target.innerWidth()
			},
			startPosition = elem.offset(),
			transfer = $('<div class="ui-effects-transfer"></div>')
				.appendTo(document.body)
				.addClass(o.options.className)
				.css({
					top: startPosition.top,
					left: startPosition.left,
					height: elem.innerHeight(),
					width: elem.innerWidth(),
					position: 'absolute'
				})
				.animate(animation, o.duration, o.options.easing, function() {
					transfer.remove();
					(o.callback && o.callback.apply(elem[0], arguments));
					elem.dequeue();
				});
	});
};

})(jQuery);
/*
 * jQuery UI Accordion 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Accordion
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget( "ui.accordion", {
	options: {
		active: 0,
		animated: "slide",
		autoHeight: true,
		clearStyle: false,
		collapsible: false,
		event: "click",
		fillSpace: false,
		header: "> li > :first-child,> :not(li):even",
		icons: {
			header: "ui-icon-triangle-1-e",
			headerSelected: "ui-icon-triangle-1-s"
		},
		navigation: false,
		navigationFilter: function() {
			return this.href.toLowerCase() === location.href.toLowerCase();
		}
	},

	_create: function() {
		var self = this,
			options = self.options;

		self.running = 0;

		self.element
			.addClass( "ui-accordion ui-widget ui-helper-reset" )
			// in lack of child-selectors in CSS
			// we need to mark top-LIs in a UL-accordion for some IE-fix
			.children( "li" )
				.addClass( "ui-accordion-li-fix" );

		self.headers = self.element.find( options.header )
			.addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" )
			.bind( "mouseenter.accordion", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).addClass( "ui-state-hover" );
			})
			.bind( "mouseleave.accordion", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).removeClass( "ui-state-hover" );
			})
			.bind( "focus.accordion", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).addClass( "ui-state-focus" );
			})
			.bind( "blur.accordion", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).removeClass( "ui-state-focus" );
			});

		self.headers.next()
			.addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" );

		if ( options.navigation ) {
			var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 );
			if ( current.length ) {
				var header = current.closest( ".ui-accordion-header" );
				if ( header.length ) {
					// anchor within header
					self.active = header;
				} else {
					// anchor within content
					self.active = current.closest( ".ui-accordion-content" ).prev();
				}
			}
		}

		self.active = self._findActive( self.active || options.active )
			.addClass( "ui-state-default ui-state-active" )
			.toggleClass( "ui-corner-all" )
			.toggleClass( "ui-corner-top" );
		self.active.next().addClass( "ui-accordion-content-active" );

		self._createIcons();
		self.resize();
		
		// ARIA
		self.element.attr( "role", "tablist" );

		self.headers
			.attr( "role", "tab" )
			.bind( "keydown.accordion", function( event ) {
				return self._keydown( event );
			})
			.next()
				.attr( "role", "tabpanel" );

		self.headers
			.not( self.active || "" )
			.attr({
				"aria-expanded": "false",
				"aria-selected": "false",
				tabIndex: -1
			})
			.next()
				.hide();

		// make sure at least one header is in the tab order
		if ( !self.active.length ) {
			self.headers.eq( 0 ).attr( "tabIndex", 0 );
		} else {
			self.active
				.attr({
					"aria-expanded": "true",
					"aria-selected": "true",
					tabIndex: 0
				});
		}

		// only need links in tab order for Safari
		if ( !$.browser.safari ) {
			self.headers.find( "a" ).attr( "tabIndex", -1 );
		}

		if ( options.event ) {
			self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) {
				self._clickHandler.call( self, event, this );
				event.preventDefault();
			});
		}
	},

	_createIcons: function() {
		var options = this.options;
		if ( options.icons ) {
			$( "<span></span>" )
				.addClass( "ui-icon " + options.icons.header )
				.prependTo( this.headers );
			this.active.children( ".ui-icon" )
				.toggleClass(options.icons.header)
				.toggleClass(options.icons.headerSelected);
			this.element.addClass( "ui-accordion-icons" );
		}
	},

	_destroyIcons: function() {
		this.headers.children( ".ui-icon" ).remove();
		this.element.removeClass( "ui-accordion-icons" );
	},

	destroy: function() {
		var options = this.options;

		this.element
			.removeClass( "ui-accordion ui-widget ui-helper-reset" )
			.removeAttr( "role" );

		this.headers
			.unbind( ".accordion" )
			.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" )
			.removeAttr( "role" )
			.removeAttr( "aria-expanded" )
			.removeAttr( "aria-selected" )
			.removeAttr( "tabIndex" );

		this.headers.find( "a" ).removeAttr( "tabIndex" );
		this._destroyIcons();
		var contents = this.headers.next()
			.css( "display", "" )
			.removeAttr( "role" )
			.removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" );
		if ( options.autoHeight || options.fillHeight ) {
			contents.css( "height", "" );
		}

		return $.Widget.prototype.destroy.call( this );
	},

	_setOption: function( key, value ) {
		$.Widget.prototype._setOption.apply( this, arguments );
			
		if ( key == "active" ) {
			this.activate( value );
		}
		if ( key == "icons" ) {
			this._destroyIcons();
			if ( value ) {
				this._createIcons();
			}
		}
		// #5332 - opacity doesn't cascade to positioned elements in IE
		// so we need to add the disabled class to the headers and panels
		if ( key == "disabled" ) {
			this.headers.add(this.headers.next())
				[ value ? "addClass" : "removeClass" ](
					"ui-accordion-disabled ui-state-disabled" );
		}
	},

	_keydown: function( event ) {
		if ( this.options.disabled || event.altKey || event.ctrlKey ) {
			return;
		}

		var keyCode = $.ui.keyCode,
			length = this.headers.length,
			currentIndex = this.headers.index( event.target ),
			toFocus = false;

		switch ( event.keyCode ) {
			case keyCode.RIGHT:
			case keyCode.DOWN:
				toFocus = this.headers[ ( currentIndex + 1 ) % length ];
				break;
			case keyCode.LEFT:
			case keyCode.UP:
				toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
				break;
			case keyCode.SPACE:
			case keyCode.ENTER:
				this._clickHandler( { target: event.target }, event.target );
				event.preventDefault();
		}

		if ( toFocus ) {
			$( event.target ).attr( "tabIndex", -1 );
			$( toFocus ).attr( "tabIndex", 0 );
			toFocus.focus();
			return false;
		}

		return true;
	},

	resize: function() {
		var options = this.options,
			maxHeight;

		if ( options.fillSpace ) {
			if ( $.browser.msie ) {
				var defOverflow = this.element.parent().css( "overflow" );
				this.element.parent().css( "overflow", "hidden");
			}
			maxHeight = this.element.parent().height();
			if ($.browser.msie) {
				this.element.parent().css( "overflow", defOverflow );
			}

			this.headers.each(function() {
				maxHeight -= $( this ).outerHeight( true );
			});

			this.headers.next()
				.each(function() {
					$( this ).height( Math.max( 0, maxHeight -
						$( this ).innerHeight() + $( this ).height() ) );
				})
				.css( "overflow", "auto" );
		} else if ( options.autoHeight ) {
			maxHeight = 0;
			this.headers.next()
				.each(function() {
					maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
				})
				.height( maxHeight );
		}

		return this;
	},

	activate: function( index ) {
		// TODO this gets called on init, changing the option without an explicit call for that
		this.options.active = index;
		// call clickHandler with custom event
		var active = this._findActive( index )[ 0 ];
		this._clickHandler( { target: active }, active );

		return this;
	},

	_findActive: function( selector ) {
		return selector
			? typeof selector === "number"
				? this.headers.filter( ":eq(" + selector + ")" )
				: this.headers.not( this.headers.not( selector ) )
			: selector === false
				? $( [] )
				: this.headers.filter( ":eq(0)" );
	},

	// TODO isn't event.target enough? why the separate target argument?
	_clickHandler: function( event, target ) {
		var options = this.options;
		if ( options.disabled ) {
			return;
		}

		// called only when using activate(false) to close all parts programmatically
		if ( !event.target ) {
			if ( !options.collapsible ) {
				return;
			}
			this.active
				.removeClass( "ui-state-active ui-corner-top" )
				.addClass( "ui-state-default ui-corner-all" )
				.children( ".ui-icon" )
					.removeClass( options.icons.headerSelected )
					.addClass( options.icons.header );
			this.active.next().addClass( "ui-accordion-content-active" );
			var toHide = this.active.next(),
				data = {
					options: options,
					newHeader: $( [] ),
					oldHeader: options.active,
					newContent: $( [] ),
					oldContent: toHide
				},
				toShow = ( this.active = $( [] ) );
			this._toggle( toShow, toHide, data );
			return;
		}

		// get the click target
		var clicked = $( event.currentTarget || target ),
			clickedIsActive = clicked[0] === this.active[0];

		// TODO the option is changed, is that correct?
		// TODO if it is correct, shouldn't that happen after determining that the click is valid?
		options.active = options.collapsible && clickedIsActive ?
			false :
			this.headers.index( clicked );

		// if animations are still active, or the active header is the target, ignore click
		if ( this.running || ( !options.collapsible && clickedIsActive ) ) {
			return;
		}

		// find elements to show and hide
		var active = this.active,
			toShow = clicked.next(),
			toHide = this.active.next(),
			data = {
				options: options,
				newHeader: clickedIsActive && options.collapsible ? $([]) : clicked,
				oldHeader: this.active,
				newContent: clickedIsActive && options.collapsible ? $([]) : toShow,
				oldContent: toHide
			},
			down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );

		// when the call to ._toggle() comes after the class changes
		// it causes a very odd bug in IE 8 (see #6720)
		this.active = clickedIsActive ? $([]) : clicked;
		this._toggle( toShow, toHide, data, clickedIsActive, down );

		// switch classes
		active
			.removeClass( "ui-state-active ui-corner-top" )
			.addClass( "ui-state-default ui-corner-all" )
			.children( ".ui-icon" )
				.removeClass( options.icons.headerSelected )
				.addClass( options.icons.header );
		if ( !clickedIsActive ) {
			clicked
				.removeClass( "ui-state-default ui-corner-all" )
				.addClass( "ui-state-active ui-corner-top" )
				.children( ".ui-icon" )
					.removeClass( options.icons.header )
					.addClass( options.icons.headerSelected );
			clicked
				.next()
				.addClass( "ui-accordion-content-active" );
		}

		return;
	},

	_toggle: function( toShow, toHide, data, clickedIsActive, down ) {
		var self = this,
			options = self.options;

		self.toShow = toShow;
		self.toHide = toHide;
		self.data = data;

		var complete = function() {
			if ( !self ) {
				return;
			}
			return self._completed.apply( self, arguments );
		};

		// trigger changestart event
		self._trigger( "changestart", null, self.data );

		// count elements to animate
		self.running = toHide.size() === 0 ? toShow.size() : toHide.size();

		if ( options.animated ) {
			var animOptions = {};

			if ( options.collapsible && clickedIsActive ) {
				animOptions = {
					toShow: $( [] ),
					toHide: toHide,
					complete: complete,
					down: down,
					autoHeight: options.autoHeight || options.fillSpace
				};
			} else {
				animOptions = {
					toShow: toShow,
					toHide: toHide,
					complete: complete,
					down: down,
					autoHeight: options.autoHeight || options.fillSpace
				};
			}

			if ( !options.proxied ) {
				options.proxied = options.animated;
			}

			if ( !options.proxiedDuration ) {
				options.proxiedDuration = options.duration;
			}

			options.animated = $.isFunction( options.proxied ) ?
				options.proxied( animOptions ) :
				options.proxied;

			options.duration = $.isFunction( options.proxiedDuration ) ?
				options.proxiedDuration( animOptions ) :
				options.proxiedDuration;

			var animations = $.ui.accordion.animations,
				duration = options.duration,
				easing = options.animated;

			if ( easing && !animations[ easing ] && !$.easing[ easing ] ) {
				easing = "slide";
			}
			if ( !animations[ easing ] ) {
				animations[ easing ] = function( options ) {
					this.slide( options, {
						easing: easing,
						duration: duration || 700
					});
				};
			}

			animations[ easing ]( animOptions );
		} else {
			if ( options.collapsible && clickedIsActive ) {
				toShow.toggle();
			} else {
				toHide.hide();
				toShow.show();
			}

			complete( true );
		}

		// TODO assert that the blur and focus triggers are really necessary, remove otherwise
		toHide.prev()
			.attr({
				"aria-expanded": "false",
				"aria-selected": "false",
				tabIndex: -1
			})
			.blur();
		toShow.prev()
			.attr({
				"aria-expanded": "true",
				"aria-selected": "true",
				tabIndex: 0
			})
			.focus();
	},

	_completed: function( cancel ) {
		this.running = cancel ? 0 : --this.running;
		if ( this.running ) {
			return;
		}

		if ( this.options.clearStyle ) {
			this.toShow.add( this.toHide ).css({
				height: "",
				overflow: ""
			});
		}

		// other classes are removed before the animation; this one needs to stay until completed
		this.toHide.removeClass( "ui-accordion-content-active" );
		// Work around for rendering bug in IE (#5421)
		if ( this.toHide.length ) {
			this.toHide.parent()[0].className = this.toHide.parent()[0].className;
		}

		this._trigger( "change", null, this.data );
	}
});

$.extend( $.ui.accordion, {
	version: "1.8.12",
	animations: {
		slide: function( options, additions ) {
			options = $.extend({
				easing: "swing",
				duration: 300
			}, options, additions );
			if ( !options.toHide.size() ) {
				options.toShow.animate({
					height: "show",
					paddingTop: "show",
					paddingBottom: "show"
				}, options );
				return;
			}
			if ( !options.toShow.size() ) {
				options.toHide.animate({
					height: "hide",
					paddingTop: "hide",
					paddingBottom: "hide"
				}, options );
				return;
			}
			var overflow = options.toShow.css( "overflow" ),
				percentDone = 0,
				showProps = {},
				hideProps = {},
				fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
				originalWidth;
			// fix width before calculating height of hidden element
			var s = options.toShow;
			originalWidth = s[0].style.width;
			s.width( parseInt( s.parent().width(), 10 )
				- parseInt( s.css( "paddingLeft" ), 10 )
				- parseInt( s.css( "paddingRight" ), 10 )
				- ( parseInt( s.css( "borderLeftWidth" ), 10 ) || 0 )
				- ( parseInt( s.css( "borderRightWidth" ), 10) || 0 ) );

			$.each( fxAttrs, function( i, prop ) {
				hideProps[ prop ] = "hide";

				var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ );
				showProps[ prop ] = {
					value: parts[ 1 ],
					unit: parts[ 2 ] || "px"
				};
			});
			options.toShow.css({ height: 0, overflow: "hidden" }).show();
			options.toHide
				.filter( ":hidden" )
					.each( options.complete )
				.end()
				.filter( ":visible" )
				.animate( hideProps, {
				step: function( now, settings ) {
					// only calculate the percent when animating height
					// IE gets very inconsistent results when animating elements
					// with small values, which is common for padding
					if ( settings.prop == "height" ) {
						percentDone = ( settings.end - settings.start === 0 ) ? 0 :
							( settings.now - settings.start ) / ( settings.end - settings.start );
					}

					options.toShow[ 0 ].style[ settings.prop ] =
						( percentDone * showProps[ settings.prop ].value )
						+ showProps[ settings.prop ].unit;
				},
				duration: options.duration,
				easing: options.easing,
				complete: function() {
					if ( !options.autoHeight ) {
						options.toShow.css( "height", "" );
					}
					options.toShow.css({
						width: originalWidth,
						overflow: overflow
					});
					options.complete();
				}
			});
		},
		bounceslide: function( options ) {
			this.slide( options, {
				easing: options.down ? "easeOutBounce" : "swing",
				duration: options.down ? 1000 : 200
			});
		}
	}
});

})( jQuery );
/*
 * jQuery UI Autocomplete 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Autocomplete
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *	jquery.ui.position.js
 */
(function( $, undefined ) {

// used to prevent race conditions with remote data sources
var requestIndex = 0;

$.widget( "ui.autocomplete", {
	options: {
		appendTo: "body",
		autoFocus: false,
		delay: 300,
		minLength: 1,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},
		source: null
	},

	pending: 0,

	_create: function() {
		var self = this,
			doc = this.element[ 0 ].ownerDocument,
			suppressKeyPress;

		this.element
			.addClass( "ui-autocomplete-input" )
			.attr( "autocomplete", "off" )
			// TODO verify these actually work as intended
			.attr({
				role: "textbox",
				"aria-autocomplete": "list",
				"aria-haspopup": "true"
			})
			.bind( "keydown.autocomplete", function( event ) {
				if ( self.options.disabled || self.element.attr( "readonly" ) ) {
					return;
				}

				suppressKeyPress = false;
				var keyCode = $.ui.keyCode;
				switch( event.keyCode ) {
				case keyCode.PAGE_UP:
					self._move( "previousPage", event );
					break;
				case keyCode.PAGE_DOWN:
					self._move( "nextPage", event );
					break;
				case keyCode.UP:
					self._move( "previous", event );
					// prevent moving cursor to beginning of text field in some browsers
					event.preventDefault();
					break;
				case keyCode.DOWN:
					self._move( "next", event );
					// prevent moving cursor to end of text field in some browsers
					event.preventDefault();
					break;
				case keyCode.ENTER:
				case keyCode.NUMPAD_ENTER:
					// when menu is open and has focus
					if ( self.menu.active ) {
						// #6055 - Opera still allows the keypress to occur
						// which causes forms to submit
						suppressKeyPress = true;
						event.preventDefault();
					}
					//passthrough - ENTER and TAB both select the current element
				case keyCode.TAB:
					if ( !self.menu.active ) {
						return;
					}
					self.menu.select( event );
					break;
				case keyCode.ESCAPE:
					self.element.val( self.term );
					self.close( event );
					break;
				default:
					// keypress is triggered before the input value is changed
					clearTimeout( self.searching );
					self.searching = setTimeout(function() {
						// only search if the value has changed
						if ( self.term != self.element.val() ) {
							self.selectedItem = null;
							self.search( null, event );
						}
					}, self.options.delay );
					break;
				}
			})
			.bind( "keypress.autocomplete", function( event ) {
				if ( suppressKeyPress ) {
					suppressKeyPress = false;
					event.preventDefault();
				}
			})
			.bind( "focus.autocomplete", function() {
				if ( self.options.disabled ) {
					return;
				}

				self.selectedItem = null;
				self.previous = self.element.val();
			})
			.bind( "blur.autocomplete", function( event ) {
				if ( self.options.disabled ) {
					return;
				}

				clearTimeout( self.searching );
				// clicks on the menu (or a button to trigger a search) will cause a blur event
				self.closing = setTimeout(function() {
					self.close( event );
					self._change( event );
				}, 150 );
			});
		this._initSource();
		this.response = function() {
			return self._response.apply( self, arguments );
		};
		this.menu = $( "<ul></ul>" )
			.addClass( "ui-autocomplete" )
			.appendTo( $( this.options.appendTo || "body", doc )[0] )
			// prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
			.mousedown(function( event ) {
				// clicking on the scrollbar causes focus to shift to the body
				// but we can't detect a mouseup or a click immediately afterward
				// so we have to track the next mousedown and close the menu if
				// the user clicks somewhere outside of the autocomplete
				var menuElement = self.menu.element[ 0 ];
				if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
					setTimeout(function() {
						$( document ).one( 'mousedown', function( event ) {
							if ( event.target !== self.element[ 0 ] &&
								event.target !== menuElement &&
								!$.ui.contains( menuElement, event.target ) ) {
								self.close();
							}
						});
					}, 1 );
				}

				// use another timeout to make sure the blur-event-handler on the input was already triggered
				setTimeout(function() {
					clearTimeout( self.closing );
				}, 13);
			})
			.menu({
				focus: function( event, ui ) {
					var item = ui.item.data( "item.autocomplete" );
					if ( false !== self._trigger( "focus", event, { item: item } ) ) {
						// use value to match what will end up in the input, if it was a key event
						if ( /^key/.test(event.originalEvent.type) ) {
							self.element.val( item.value );
						}
					}
				},
				selected: function( event, ui ) {
					var item = ui.item.data( "item.autocomplete" ),
						previous = self.previous;

					// only trigger when focus was lost (click on menu)
					if ( self.element[0] !== doc.activeElement ) {
						self.element.focus();
						self.previous = previous;
						// #6109 - IE triggers two focus events and the second
						// is asynchronous, so we need to reset the previous
						// term synchronously and asynchronously :-(
						setTimeout(function() {
							self.previous = previous;
							self.selectedItem = item;
						}, 1);
					}

					if ( false !== self._trigger( "select", event, { item: item } ) ) {
						self.element.val( item.value );
					}
					// reset the term after the select event
					// this allows custom select handling to work properly
					self.term = self.element.val();

					self.close( event );
					self.selectedItem = item;
				},
				blur: function( event, ui ) {
					// don't set the value of the text field if it's already correct
					// this prevents moving the cursor unnecessarily
					if ( self.menu.element.is(":visible") &&
						( self.element.val() !== self.term ) ) {
						self.element.val( self.term );
					}
				}
			})
			.zIndex( this.element.zIndex() + 1 )
			// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
			.css({ top: 0, left: 0 })
			.hide()
			.data( "menu" );
		if ( $.fn.bgiframe ) {
			 this.menu.element.bgiframe();
		}
	},

	destroy: function() {
		this.element
			.removeClass( "ui-autocomplete-input" )
			.removeAttr( "autocomplete" )
			.removeAttr( "role" )
			.removeAttr( "aria-autocomplete" )
			.removeAttr( "aria-haspopup" );
		this.menu.element.remove();
		$.Widget.prototype.destroy.call( this );
	},

	_setOption: function( key, value ) {
		$.Widget.prototype._setOption.apply( this, arguments );
		if ( key === "source" ) {
			this._initSource();
		}
		if ( key === "appendTo" ) {
			this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
		}
		if ( key === "disabled" && value && this.xhr ) {
			this.xhr.abort();
		}
	},

	_initSource: function() {
		var self = this,
			array,
			url;
		if ( $.isArray(this.options.source) ) {
			array = this.options.source;
			this.source = function( request, response ) {
				response( $.ui.autocomplete.filter(array, request.term) );
			};
		} else if ( typeof this.options.source === "string" ) {
			url = this.options.source;
			this.source = function( request, response ) {
				if ( self.xhr ) {
					self.xhr.abort();
				}
				self.xhr = $.ajax({
					url: url,
					data: request,
					dataType: "json",
					autocompleteRequest: ++requestIndex,
					success: function( data, status ) {
						if ( this.autocompleteRequest === requestIndex ) {
							response( data );
						}
					},
					error: function() {
						if ( this.autocompleteRequest === requestIndex ) {
							response( [] );
						}
					}
				});
			};
		} else {
			this.source = this.options.source;
		}
	},

	search: function( value, event ) {
		value = value != null ? value : this.element.val();

		// always save the actual value, not the one passed as an argument
		this.term = this.element.val();

		if ( value.length < this.options.minLength ) {
			return this.close( event );
		}

		clearTimeout( this.closing );
		if ( this._trigger( "search", event ) === false ) {
			return;
		}

		return this._search( value );
	},

	_search: function( value ) {
		this.pending++;
		this.element.addClass( "ui-autocomplete-loading" );

		this.source( { term: value }, this.response );
	},

	_response: function( content ) {
		if ( !this.options.disabled && content && content.length ) {
			content = this._normalize( content );
			this._suggest( content );
			this._trigger( "open" );
		} else {
			this.close();
		}
		this.pending--;
		if ( !this.pending ) {
			this.element.removeClass( "ui-autocomplete-loading" );
		}
	},

	close: function( event ) {
		clearTimeout( this.closing );
		if ( this.menu.element.is(":visible") ) {
			this.menu.element.hide();
			this.menu.deactivate();
			this._trigger( "close", event );
		}
	},
	
	_change: function( event ) {
		if ( this.previous !== this.element.val() ) {
			this._trigger( "change", event, { item: this.selectedItem } );
		}
	},

	_normalize: function( items ) {
		// assume all items have the right format when the first item is complete
		if ( items.length && items[0].label && items[0].value ) {
			return items;
		}
		return $.map( items, function(item) {
			if ( typeof item === "string" ) {
				return {
					label: item,
					value: item
				};
			}
			return $.extend({
				label: item.label || item.value,
				value: item.value || item.label
			}, item );
		});
	},

	_suggest: function( items ) {
		var ul = this.menu.element
			.empty()
			.zIndex( this.element.zIndex() + 1 );
		this._renderMenu( ul, items );
		// TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
		this.menu.deactivate();
		this.menu.refresh();

		// size and position menu
		ul.show();
		this._resizeMenu();
		ul.position( $.extend({
			of: this.element
		}, this.options.position ));

		if ( this.options.autoFocus ) {
			this.menu.next( new $.Event("mouseover") );
		}
	},

	_resizeMenu: function() {
		var ul = this.menu.element;
		ul.outerWidth( Math.max(
			ul.width( "" ).outerWidth(),
			this.element.outerWidth()
		) );
	},

	_renderMenu: function( ul, items ) {
		var self = this;
		$.each( items, function( index, item ) {
			self._renderItem( ul, item );
		});
	},

	_renderItem: function( ul, item) {
		return $( "<li></li>" )
			.data( "item.autocomplete", item )
			.append( $( "<a></a>" ).text( item.label ) )
			.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( !this.menu.element.is(":visible") ) {
			this.search( null, event );
			return;
		}
		if ( this.menu.first() && /^previous/.test(direction) ||
				this.menu.last() && /^next/.test(direction) ) {
			this.element.val( this.term );
			this.menu.deactivate();
			return;
		}
		this.menu[ direction ]( event );
	},

	widget: function() {
		return this.menu.element;
	}
});

$.extend( $.ui.autocomplete, {
	escapeRegex: function( value ) {
		return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
	},
	filter: function(array, term) {
		var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
		return $.grep( array, function(value) {
			return matcher.test( value.label || value.value || value );
		});
	}
});

}( jQuery ));

/*
 * jQuery UI Menu (not officially released)
 * 
 * This widget isn't yet finished and the API is subject to change. We plan to finish
 * it for the next release. You're welcome to give it a try anyway and give us feedback,
 * as long as you're okay with migrating your code later on. We can help with that, too.
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menu
 *
 * Depends:
 *	jquery.ui.core.js
 *  jquery.ui.widget.js
 */
(function($) {

$.widget("ui.menu", {
	_create: function() {
		var self = this;
		this.element
			.addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
			.attr({
				role: "listbox",
				"aria-activedescendant": "ui-active-menuitem"
			})
			.click(function( event ) {
				if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
					return;
				}
				// temporary
				event.preventDefault();
				self.select( event );
			});
		this.refresh();
	},
	
	refresh: function() {
		var self = this;

		// don't refresh list items that are already adapted
		var items = this.element.children("li:not(.ui-menu-item):has(a)")
			.addClass("ui-menu-item")
			.attr("role", "menuitem");
		
		items.children("a")
			.addClass("ui-corner-all")
			.attr("tabindex", -1)
			// mouseenter doesn't work with event delegation
			.mouseenter(function( event ) {
				self.activate( event, $(this).parent() );
			})
			.mouseleave(function() {
				self.deactivate();
			});
	},

	activate: function( event, item ) {
		this.deactivate();
		if (this.hasScroll()) {
			var offset = item.offset().top - this.element.offset().top,
				scroll = this.element.attr("scrollTop"),
				elementHeight = this.element.height();
			if (offset < 0) {
				this.element.attr("scrollTop", scroll + offset);
			} else if (offset >= elementHeight) {
				this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
			}
		}
		this.active = item.eq(0)
			.children("a")
				.addClass("ui-state-hover")
				.attr("id", "ui-active-menuitem")
			.end();
		this._trigger("focus", event, { item: item });
	},

	deactivate: function() {
		if (!this.active) { return; }

		this.active.children("a")
			.removeClass("ui-state-hover")
			.removeAttr("id");
		this._trigger("blur");
		this.active = null;
	},

	next: function(event) {
		this.move("next", ".ui-menu-item:first", event);
	},

	previous: function(event) {
		this.move("prev", ".ui-menu-item:last", event);
	},

	first: function() {
		return this.active && !this.active.prevAll(".ui-menu-item").length;
	},

	last: function() {
		return this.active && !this.active.nextAll(".ui-menu-item").length;
	},

	move: function(direction, edge, event) {
		if (!this.active) {
			this.activate(event, this.element.children(edge));
			return;
		}
		var next = this.active[direction + "All"](".ui-menu-item").eq(0);
		if (next.length) {
			this.activate(event, next);
		} else {
			this.activate(event, this.element.children(edge));
		}
	},

	// TODO merge with previousPage
	nextPage: function(event) {
		if (this.hasScroll()) {
			// TODO merge with no-scroll-else
			if (!this.active || this.last()) {
				this.activate(event, this.element.children(".ui-menu-item:first"));
				return;
			}
			var base = this.active.offset().top,
				height = this.element.height(),
				result = this.element.children(".ui-menu-item").filter(function() {
					var close = $(this).offset().top - base - height + $(this).height();
					// TODO improve approximation
					return close < 10 && close > -10;
				});

			// TODO try to catch this earlier when scrollTop indicates the last page anyway
			if (!result.length) {
				result = this.element.children(".ui-menu-item:last");
			}
			this.activate(event, result);
		} else {
			this.activate(event, this.element.children(".ui-menu-item")
				.filter(!this.active || this.last() ? ":first" : ":last"));
		}
	},

	// TODO merge with nextPage
	previousPage: function(event) {
		if (this.hasScroll()) {
			// TODO merge with no-scroll-else
			if (!this.active || this.first()) {
				this.activate(event, this.element.children(".ui-menu-item:last"));
				return;
			}

			var base = this.active.offset().top,
				height = this.element.height();
				result = this.element.children(".ui-menu-item").filter(function() {
					var close = $(this).offset().top - base + height - $(this).height();
					// TODO improve approximation
					return close < 10 && close > -10;
				});

			// TODO try to catch this earlier when scrollTop indicates the last page anyway
			if (!result.length) {
				result = this.element.children(".ui-menu-item:first");
			}
			this.activate(event, result);
		} else {
			this.activate(event, this.element.children(".ui-menu-item")
				.filter(!this.active || this.first() ? ":last" : ":first"));
		}
	},

	hasScroll: function() {
		return this.element.height() < this.element.attr("scrollHeight");
	},

	select: function( event ) {
		this._trigger("selected", event, { item: this.active });
	}
});

}(jQuery));
/*
 * jQuery UI Button 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

var lastActive,
	baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
	stateClasses = "ui-state-hover ui-state-active ",
	typeClasses = "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",
	formResetHandler = function( event ) {
		$( ":ui-button", event.target.form ).each(function() {
			var inst = $( this ).data( "button" );
			setTimeout(function() {
				inst.refresh();
			}, 1 );
		});
	},
	radioGroup = function( radio ) {
		var name = radio.name,
			form = radio.form,
			radios = $( [] );
		if ( name ) {
			if ( form ) {
				radios = $( form ).find( "[name='" + name + "']" );
			} else {
				radios = $( "[name='" + name + "']", radio.ownerDocument )
					.filter(function() {
						return !this.form;
					});
			}
		}
		return radios;
	};

$.widget( "ui.button", {
	options: {
		disabled: null,
		text: true,
		label: null,
		icons: {
			primary: null,
			secondary: null
		}
	},
	_create: function() {
		this.element.closest( "form" )
			.unbind( "reset.button" )
			.bind( "reset.button", formResetHandler );

		if ( typeof this.options.disabled !== "boolean" ) {
			this.options.disabled = this.element.attr( "disabled" );
		}

		this._determineButtonType();
		this.hasTitle = !!this.buttonElement.attr( "title" );

		var self = this,
			options = this.options,
			toggleButton = this.type === "checkbox" || this.type === "radio",
			hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
			focusClass = "ui-state-focus";

		if ( options.label === null ) {
			options.label = this.buttonElement.html();
		}

		if ( this.element.is( ":disabled" ) ) {
			options.disabled = true;
		}

		this.buttonElement
			.addClass( baseClasses )
			.attr( "role", "button" )
			.bind( "mouseenter.button", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).addClass( "ui-state-hover" );
				if ( this === lastActive ) {
					$( this ).addClass( "ui-state-active" );
				}
			})
			.bind( "mouseleave.button", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).removeClass( hoverClass );
			})
			.bind( "focus.button", function() {
				// no need to check disabled, focus won't be triggered anyway
				$( this ).addClass( focusClass );
			})
			.bind( "blur.button", function() {
				$( this ).removeClass( focusClass );
			});

		if ( toggleButton ) {
			this.element.bind( "change.button", function() {
				self.refresh();
			});
		}

		if ( this.type === "checkbox" ) {
			this.buttonElement.bind( "click.button", function() {
				if ( options.disabled ) {
					return false;
				}
				$( this ).toggleClass( "ui-state-active" );
				self.buttonElement.attr( "aria-pressed", self.element[0].checked );
			});
		} else if ( this.type === "radio" ) {
			this.buttonElement.bind( "click.button", function() {
				if ( options.disabled ) {
					return false;
				}
				$( this ).addClass( "ui-state-active" );
				self.buttonElement.attr( "aria-pressed", true );

				var radio = self.element[ 0 ];
				radioGroup( radio )
					.not( radio )
					.map(function() {
						return $( this ).button( "widget" )[ 0 ];
					})
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", false );
			});
		} else {
			this.buttonElement
				.bind( "mousedown.button", function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).addClass( "ui-state-active" );
					lastActive = this;
					$( document ).one( "mouseup", function() {
						lastActive = null;
					});
				})
				.bind( "mouseup.button", function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).removeClass( "ui-state-active" );
				})
				.bind( "keydown.button", function(event) {
					if ( options.disabled ) {
						return false;
					}
					if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
						$( this ).addClass( "ui-state-active" );
					}
				})
				.bind( "keyup.button", function() {
					$( this ).removeClass( "ui-state-active" );
				});

			if ( this.buttonElement.is("a") ) {
				this.buttonElement.keyup(function(event) {
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
						// TODO pass through original event correctly (just as 2nd argument doesn't work)
						$( this ).click();
					}
				});
			}
		}

		// TODO: pull out $.Widget's handling for the disabled option into
		// $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
		// be overridden by individual plugins
		this._setOption( "disabled", options.disabled );
	},

	_determineButtonType: function() {

		if ( this.element.is(":checkbox") ) {
			this.type = "checkbox";
		} else if ( this.element.is(":radio") ) {
			this.type = "radio";
		} else if ( this.element.is("input") ) {
			this.type = "input";
		} else {
			this.type = "button";
		}

		if ( this.type === "checkbox" || this.type === "radio" ) {
			// we don't search against the document in case the element
			// is disconnected from the DOM
			var ancestor = this.element.parents().filter(":last"),
				labelSelector = "label[for=" + this.element.attr("id") + "]";
			this.buttonElement = ancestor.find( labelSelector );
			if ( !this.buttonElement.length ) {
				ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
				this.buttonElement = ancestor.filter( labelSelector );
				if ( !this.buttonElement.length ) {
					this.buttonElement = ancestor.find( labelSelector );
				}
			}
			this.element.addClass( "ui-helper-hidden-accessible" );

			var checked = this.element.is( ":checked" );
			if ( checked ) {
				this.buttonElement.addClass( "ui-state-active" );
			}
			this.buttonElement.attr( "aria-pressed", checked );
		} else {
			this.buttonElement = this.element;
		}
	},

	widget: function() {
		return this.buttonElement;
	},

	destroy: function() {
		this.element
			.removeClass( "ui-helper-hidden-accessible" );
		this.buttonElement
			.removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
			.removeAttr( "role" )
			.removeAttr( "aria-pressed" )
			.html( this.buttonElement.find(".ui-button-text").html() );

		if ( !this.hasTitle ) {
			this.buttonElement.removeAttr( "title" );
		}

		$.Widget.prototype.destroy.call( this );
	},

	_setOption: function( key, value ) {
		$.Widget.prototype._setOption.apply( this, arguments );
		if ( key === "disabled" ) {
			if ( value ) {
				this.element.attr( "disabled", true );
			} else {
				this.element.removeAttr( "disabled" );
			}
		}
		this._resetButton();
	},

	refresh: function() {
		var isDisabled = this.element.is( ":disabled" );
		if ( isDisabled !== this.options.disabled ) {
			this._setOption( "disabled", isDisabled );
		}
		if ( this.type === "radio" ) {
			radioGroup( this.element[0] ).each(function() {
				if ( $( this ).is( ":checked" ) ) {
					$( this ).button( "widget" )
						.addClass( "ui-state-active" )
						.attr( "aria-pressed", true );
				} else {
					$( this ).button( "widget" )
						.removeClass( "ui-state-active" )
						.attr( "aria-pressed", false );
				}
			});
		} else if ( this.type === "checkbox" ) {
			if ( this.element.is( ":checked" ) ) {
				this.buttonElement
					.addClass( "ui-state-active" )
					.attr( "aria-pressed", true );
			} else {
				this.buttonElement
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", false );
			}
		}
	},

	_resetButton: function() {
		if ( this.type === "input" ) {
			if ( this.options.label ) {
				this.element.val( this.options.label );
			}
			return;
		}
		var buttonElement = this.buttonElement.removeClass( typeClasses ),
			buttonText = $( "<span></span>" )
				.addClass( "ui-button-text" )
				.html( this.options.label )
				.appendTo( buttonElement.empty() )
				.text(),
			icons = this.options.icons,
			multipleIcons = icons.primary && icons.secondary,
			buttonClasses = [];  

		if ( icons.primary || icons.secondary ) {
			if ( this.options.text ) {
				buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
			}

			if ( icons.primary ) {
				buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
			}

			if ( icons.secondary ) {
				buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
			}

			if ( !this.options.text ) {
				buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );

				if ( !this.hasTitle ) {
					buttonElement.attr( "title", buttonText );
				}
			}
		} else {
			buttonClasses.push( "ui-button-text-only" );
		}
		buttonElement.addClass( buttonClasses.join( " " ) );
	}
});

$.widget( "ui.buttonset", {
	options: {
		items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)"
	},

	_create: function() {
		this.element.addClass( "ui-buttonset" );
	},
	
	_init: function() {
		this.refresh();
	},

	_setOption: function( key, value ) {
		if ( key === "disabled" ) {
			this.buttons.button( "option", key, value );
		}

		$.Widget.prototype._setOption.apply( this, arguments );
	},
	
	refresh: function() {
		this.buttons = this.element.find( this.options.items )
			.filter( ":ui-button" )
				.button( "refresh" )
			.end()
			.not( ":ui-button" )
				.button()
			.end()
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
				.filter( ":first" )
					.addClass( "ui-corner-left" )
				.end()
				.filter( ":last" )
					.addClass( "ui-corner-right" )
				.end()
			.end();
	},

	destroy: function() {
		this.element.removeClass( "ui-buttonset" );
		this.buttons
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-left ui-corner-right" )
			.end()
			.button( "destroy" );

		$.Widget.prototype.destroy.call( this );
	}
});

}( jQuery ) );
/*
 * jQuery UI Datepicker 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Datepicker
 *
 * Depends:
 *	jquery.ui.core.js
 */
(function( $, undefined ) {

$.extend($.ui, { datepicker: { version: "1.8.12" } });

var PROP_NAME = 'datepicker';
var dpuuid = new Date().getTime();

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this.debug = false; // Change this to true to start debugging
	this._curInst = null; // The current instance in use
	this._keyEvent = false; // If the last event was a key event
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
	this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
	this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
	this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
	this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
	this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
	this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
	this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
	this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		closeText: 'Done', // Display text for close link
		prevText: 'Prev', // Display text for previous month link
		nextText: 'Next', // Display text for next month link
		currentText: 'Today', // Display text for current month link
		monthNames: ['January','February','March','April','May','June',
			'July','August','September','October','November','December'], // Names of months for drop-down and formatting
		monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
		dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
		dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
		dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
		weekHeader: 'Wk', // Column header for week of the year
		dateFormat: 'mm/dd/yy', // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		isRTL: false, // True if right-to-left language, false if left-to-right
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
		yearSuffix: '' // Additional text to append to the year in the month headers
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: 'focus', // 'focus' for popup on focus,
			// 'button' for trigger button, or 'both' for either
		showAnim: 'fadeIn', // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: false, // True if month can be selected directly, false if only prev/next
		changeYear: false, // True if year can be selected directly, false if only prev/next
		yearRange: 'c-10:c+10', // Range of years to display in drop-down,
			// either relative to today's year (-nn:+nn), relative to currently displayed year
			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
		showWeek: false, // True to show week of the year, false to not show it
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: '+10', // Short year values < this are in the current century,
			// > this are in the previous century,
			// string value starting with '+' for current year + value
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: 'fast', // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		numberOfMonths: 1, // Number of months to show at a time
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
		stepMonths: 1, // Number of months to step back/forward
		stepBigMonths: 12, // Number of months to step back/forward for the big links
		altField: '', // Selector for an alternate field to store selected dates into
		altFormat: '', // The date format to use for the alternate field
		constrainInput: true, // The input is constrained by the current date format
		showButtonPanel: false, // True to show button panel, false to not show it
		autoSize: false // True to size the input for the date format, false to leave as is
	};
	$.extend(this._defaults, this.regional['']);
	this.dpDiv = $('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>');
}

$.extend(Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: 'hasDatepicker',

	/* Debug logging (if enabled). */
	log: function () {
		if (this.debug)
			console.log.apply('', arguments);
	},
	
	// TODO rename to "widget" when switching to widget factory
	_widgetDatepicker: function() {
		return this.dpDiv;
	},

	/* Override the default settings for all instances of the date picker.
	   @param  settings  object - the new settings to use as defaults (anonymous object)
	   @return the manager object */
	setDefaults: function(settings) {
		extendRemove(this._defaults, settings || {});
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span
	   @param  settings  object - the new settings to use for this date picker instance (anonymous) */
	_attachDatepicker: function(target, settings) {
		// check for settings on the control itself - in namespace 'date:'
		var inlineSettings = null;
		for (var attrName in this._defaults) {
			var attrValue = target.getAttribute('date:' + attrName);
			if (attrValue) {
				inlineSettings = inlineSettings || {};
				try {
					inlineSettings[attrName] = eval(attrValue);
				} catch (err) {
					inlineSettings[attrName] = attrValue;
				}
			}
		}
		var nodeName = target.nodeName.toLowerCase();
		var inline = (nodeName == 'div' || nodeName == 'span');
		if (!target.id) {
			this.uuid += 1;
			target.id = 'dp' + this.uuid;
		}
		var inst = this._newInst($(target), inline);
		inst.settings = $.extend({}, settings || {}, inlineSettings || {});
		if (nodeName == 'input') {
			this._connectDatepicker(target, inst);
		} else if (inline) {
			this._inlineDatepicker(target, inst);
		}
	},

	/* Create a new instance object. */
	_newInst: function(target, inline) {
		var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
		return {id: id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: (!inline ? this.dpDiv : // presentation div
			$('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))};
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function(target, inst) {
		var input = $(target);
		inst.append = $([]);
		inst.trigger = $([]);
		if (input.hasClass(this.markerClassName))
			return;
		this._attachments(input, inst);
		input.addClass(this.markerClassName).keydown(this._doKeyDown).
			keypress(this._doKeyPress).keyup(this._doKeyUp).
			bind("setData.datepicker", function(event, key, value) {
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key) {
				return this._get(inst, key);
			});
		this._autoSize(inst);
		$.data(target, PROP_NAME, inst);
	},

	/* Make attachments based on settings. */
	_attachments: function(input, inst) {
		var appendText = this._get(inst, 'appendText');
		var isRTL = this._get(inst, 'isRTL');
		if (inst.append)
			inst.append.remove();
		if (appendText) {
			inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
			input[isRTL ? 'before' : 'after'](inst.append);
		}
		input.unbind('focus', this._showDatepicker);
		if (inst.trigger)
			inst.trigger.remove();
		var showOn = this._get(inst, 'showOn');
		if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
			input.focus(this._showDatepicker);
		if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
			var buttonText = this._get(inst, 'buttonText');
			var buttonImage = this._get(inst, 'buttonImage');
			inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
				$('<img/>').addClass(this._triggerClass).
					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
				$('<button type="button"></button>').addClass(this._triggerClass).
					html(buttonImage == '' ? buttonText : $('<img/>').attr(
					{ src:buttonImage, alt:buttonText, title:buttonText })));
			input[isRTL ? 'before' : 'after'](inst.trigger);
			inst.trigger.click(function() {
				if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
					$.datepicker._hideDatepicker();
				else
					$.datepicker._showDatepicker(input[0]);
				return false;
			});
		}
	},

	/* Apply the maximum length for the date format. */
	_autoSize: function(inst) {
		if (this._get(inst, 'autoSize') && !inst.inline) {
			var date = new Date(2009, 12 - 1, 20); // Ensure double digits
			var dateFormat = this._get(inst, 'dateFormat');
			if (dateFormat.match(/[DM]/)) {
				var findMax = function(names) {
					var max = 0;
					var maxI = 0;
					for (var i = 0; i < names.length; i++) {
						if (names[i].length > max) {
							max = names[i].length;
							maxI = i;
						}
					}
					return maxI;
				};
				date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
					'monthNames' : 'monthNamesShort'))));
				date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
					'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
			}
			inst.input.attr('size', this._formatDate(inst, date).length);
		}
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function(target, inst) {
		var divSpan = $(target);
		if (divSpan.hasClass(this.markerClassName))
			return;
		divSpan.addClass(this.markerClassName).append(inst.dpDiv).
			bind("setData.datepicker", function(event, key, value){
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key){
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
		this._setDate(inst, this._getDefaultDate(inst), true);
		this._updateDatepicker(inst);
		this._updateAlternate(inst);
		inst.dpDiv.show();
	},

	/* Pop-up the date picker in a "dialog" box.
	   @param  input     element - ignored
	   @param  date      string or Date - the initial date to display
	   @param  onSelect  function - the function to call when a date is selected
	   @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	   @param  pos       int[2] - coordinates for the dialog's position within the screen or
	                     event - with x/y coordinates or
	                     leave empty for default (screen centre)
	   @return the manager object */
	_dialogDatepicker: function(input, date, onSelect, settings, pos) {
		var inst = this._dialogInst; // internal instance
		if (!inst) {
			this.uuid += 1;
			var id = 'dp' + this.uuid;
			this._dialogInput = $('<input type="text" id="' + id +
				'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');
			this._dialogInput.keydown(this._doKeyDown);
			$('body').append(this._dialogInput);
			inst = this._dialogInst = this._newInst(this._dialogInput, false);
			inst.settings = {};
			$.data(this._dialogInput[0], PROP_NAME, inst);
		}
		extendRemove(inst.settings, settings || {});
		date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
		this._dialogInput.val(date);

		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
		if (!this._pos) {
			var browserWidth = document.documentElement.clientWidth;
			var browserHeight = document.documentElement.clientHeight;
			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
		}

		// move input on screen for focus, but hidden behind dialog
		this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass(this._dialogClass);
		this._showDatepicker(this._dialogInput[0]);
		if ($.blockUI)
			$.blockUI(this.dpDiv);
		$.data(this._dialogInput[0], PROP_NAME, inst);
		return this;
	},

	/* Detach a datepicker from its control.
	   @param  target    element - the target input field or division or span */
	_destroyDatepicker: function(target) {
		var $target = $(target);
		var inst = $.data(target, PROP_NAME);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		var nodeName = target.nodeName.toLowerCase();
		$.removeData(target, PROP_NAME);
		if (nodeName == 'input') {
			inst.append.remove();
			inst.trigger.remove();
			$target.removeClass(this.markerClassName).
				unbind('focus', this._showDatepicker).
				unbind('keydown', this._doKeyDown).
				unbind('keypress', this._doKeyPress).
				unbind('keyup', this._doKeyUp);
		} else if (nodeName == 'div' || nodeName == 'span')
			$target.removeClass(this.markerClassName).empty();
	},

	/* Enable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_enableDatepicker: function(target) {
		var $target = $(target);
		var inst = $.data(target, PROP_NAME);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		var nodeName = target.nodeName.toLowerCase();
		if (nodeName == 'input') {
			target.disabled = false;
			inst.trigger.filter('button').
				each(function() { this.disabled = false; }).end().
				filter('img').css({opacity: '1.0', cursor: ''});
		}
		else if (nodeName == 'div' || nodeName == 'span') {
			var inline = $target.children('.' + this._inlineClass);
			inline.children().removeClass('ui-state-disabled');
		}
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
	},

	/* Disable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_disableDatepicker: function(target) {
		var $target = $(target);
		var inst = $.data(target, PROP_NAME);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		var nodeName = target.nodeName.toLowerCase();
		if (nodeName == 'input') {
			target.disabled = true;
			inst.trigger.filter('button').
				each(function() { this.disabled = true; }).end().
				filter('img').css({opacity: '0.5', cursor: 'default'});
		}
		else if (nodeName == 'div' || nodeName == 'span') {
			var inline = $target.children('.' + this._inlineClass);
			inline.children().addClass('ui-state-disabled');
		}
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
		this._disabledInputs[this._disabledInputs.length] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	   @param  target    element - the target input field or division or span
	   @return boolean - true if disabled, false if enabled */
	_isDisabledDatepicker: function(target) {
		if (!target) {
			return false;
		}
		for (var i = 0; i < this._disabledInputs.length; i++) {
			if (this._disabledInputs[i] == target)
				return true;
		}
		return false;
	},

	/* Retrieve the instance data for the target control.
	   @param  target  element - the target input field or division or span
	   @return  object - the associated instance data
	   @throws  error if a jQuery problem getting data */
	_getInst: function(target) {
		try {
			return $.data(target, PROP_NAME);
		}
		catch (err) {
			throw 'Missing instance data for this datepicker';
		}
	},

	/* Update or retrieve the settings for a date picker attached to an input field or division.
	   @param  target  element - the target input field or division or span
	   @param  name    object - the new settings to update or
	                   string - the name of the setting to change or retrieve,
	                   when retrieving also 'all' for all instance settings or
	                   'defaults' for all global defaults
	   @param  value   any - the new value for the setting
	                   (omit if above is an object or to retrieve a value) */
	_optionDatepicker: function(target, name, value) {
		var inst = this._getInst(target);
		if (arguments.length == 2 && typeof name == 'string') {
			return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
				(inst ? (name == 'all' ? $.extend({}, inst.settings) :
				this._get(inst, name)) : null));
		}
		var settings = name || {};
		if (typeof name == 'string') {
			settings = {};
			settings[name] = value;
		}
		if (inst) {
			if (this._curInst == inst) {
				this._hideDatepicker();
			}
			var date = this._getDateDatepicker(target, true);
			var minDate = this._getMinMaxDate(inst, 'min');
			var maxDate = this._getMinMaxDate(inst, 'max');
			extendRemove(inst.settings, settings);
			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
			if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined)
				inst.settings.minDate = this._formatDate(inst, minDate);
			if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined)
				inst.settings.maxDate = this._formatDate(inst, maxDate);
			this._attachments($(target), inst);
			this._autoSize(inst);
			this._setDateDatepicker(target, date);
			this._updateDatepicker(inst);
		}
	},

	// change method deprecated
	_changeDatepicker: function(target, name, value) {
		this._optionDatepicker(target, name, value);
	},

	/* Redraw the date picker attached to an input field or division.
	   @param  target  element - the target input field or division or span */
	_refreshDatepicker: function(target) {
		var inst = this._getInst(target);
		if (inst) {
			this._updateDatepicker(inst);
		}
	},

	/* Set the dates for a jQuery selection.
	   @param  target   element - the target input field or division or span
	   @param  date     Date - the new date */
	_setDateDatepicker: function(target, date) {
		var inst = this._getInst(target);
		if (inst) {
			this._setDate(inst, date);
			this._updateDatepicker(inst);
			this._updateAlternate(inst);
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	   @param  target     element - the target input field or division or span
	   @param  noDefault  boolean - true if no default date is to be used
	   @return Date - the current date */
	_getDateDatepicker: function(target, noDefault) {
		var inst = this._getInst(target);
		if (inst && !inst.inline)
			this._setDateFromField(inst, noDefault);
		return (inst ? this._getDate(inst) : null);
	},

	/* Handle keystrokes. */
	_doKeyDown: function(event) {
		var inst = $.datepicker._getInst(event.target);
		var handled = true;
		var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
		inst._keyEvent = true;
		if ($.datepicker._datepickerShowing)
			switch (event.keyCode) {
				case 9: $.datepicker._hideDatepicker();
						handled = false;
						break; // hide on tab out
				case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + 
									$.datepicker._currentClass + ')', inst.dpDiv);
						if (sel[0])
							$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
						else
							$.datepicker._hideDatepicker();
						return false; // don't submit the form
						break; // select the value on enter
				case 27: $.datepicker._hideDatepicker();
						break; // hide on escape
				case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
							-$.datepicker._get(inst, 'stepBigMonths') :
							-$.datepicker._get(inst, 'stepMonths')), 'M');
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
							+$.datepicker._get(inst, 'stepBigMonths') :
							+$.datepicker._get(inst, 'stepMonths')), 'M');
						break; // next month/year on page down/+ ctrl
				case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
						handled = event.ctrlKey || event.metaKey;
						break; // clear on ctrl or command +end
				case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
						handled = event.ctrlKey || event.metaKey;
						break; // current on ctrl or command +home
				case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
						handled = event.ctrlKey || event.metaKey;
						// -1 day on ctrl or command +left
						if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
									-$.datepicker._get(inst, 'stepBigMonths') :
									-$.datepicker._get(inst, 'stepMonths')), 'M');
						// next month/year on alt +left on Mac
						break;
				case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
						handled = event.ctrlKey || event.metaKey;
						break; // -1 week on ctrl or command +up
				case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
						handled = event.ctrlKey || event.metaKey;
						// +1 day on ctrl or command +right
						if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
									+$.datepicker._get(inst, 'stepBigMonths') :
									+$.datepicker._get(inst, 'stepMonths')), 'M');
						// next month/year on alt +right
						break;
				case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
						handled = event.ctrlKey || event.metaKey;
						break; // +1 week on ctrl or command +down
				default: handled = false;
			}
		else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
			$.datepicker._showDatepicker(this);
		else {
			handled = false;
		}
		if (handled) {
			event.preventDefault();
			event.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function(event) {
		var inst = $.datepicker._getInst(event.target);
		if ($.datepicker._get(inst, 'constrainInput')) {
			var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
			var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
			return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
		}
	},

	/* Synchronise manual entry and field/alternate field. */
	_doKeyUp: function(event) {
		var inst = $.datepicker._getInst(event.target);
		if (inst.input.val() != inst.lastVal) {
			try {
				var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
					(inst.input ? inst.input.val() : null),
					$.datepicker._getFormatConfig(inst));
				if (date) { // only if valid
					$.datepicker._setDateFromField(inst);
					$.datepicker._updateAlternate(inst);
					$.datepicker._updateDatepicker(inst);
				}
			}
			catch (event) {
				$.datepicker.log(event);
			}
		}
		return true;
	},

	/* Pop-up the date picker for a given input field.
	   @param  input  element - the input field attached to the date picker or
	                  event - if triggered by focus */
	_showDatepicker: function(input) {
		input = input.target || input;
		if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
			input = $('input', input.parentNode)[0];
		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
			return;
		var inst = $.datepicker._getInst(input);
		if ($.datepicker._curInst && $.datepicker._curInst != inst) {
			$.datepicker._curInst.dpDiv.stop(true, true);
		}
		var beforeShow = $.datepicker._get(inst, 'beforeShow');
		extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
		inst.lastVal = null;
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField(inst);
		if ($.datepicker._inDialog) // hide cursor
			input.value = '';
		if (!$.datepicker._pos) { // position below input
			$.datepicker._pos = $.datepicker._findPos(input);
			$.datepicker._pos[1] += input.offsetHeight; // add the height
		}
		var isFixed = false;
		$(input).parents().each(function() {
			isFixed |= $(this).css('position') == 'fixed';
			return !isFixed;
		});
		if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
			$.datepicker._pos[0] -= document.documentElement.scrollLeft;
			$.datepicker._pos[1] -= document.documentElement.scrollTop;
		}
		var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
		$.datepicker._pos = null;
		//to avoid flashes on Firefox
		inst.dpDiv.empty();
		// determine sizing offscreen
		inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
		$.datepicker._updateDatepicker(inst);
		// fix width for dynamic number of date pickers
		// and adjust position before showing
		offset = $.datepicker._checkOffset(inst, offset, isFixed);
		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
			'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
			left: offset.left + 'px', top: offset.top + 'px'});
		if (!inst.inline) {
			var showAnim = $.datepicker._get(inst, 'showAnim');
			var duration = $.datepicker._get(inst, 'duration');
			var postProcess = function() {
				$.datepicker._datepickerShowing = true;
				var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
				if( !! cover.length ){
					var borders = $.datepicker._getBorders(inst.dpDiv);
					cover.css({left: -borders[0], top: -borders[1],
						width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
				}
			};
			inst.dpDiv.zIndex($(input).zIndex()+1);
			if ($.effects && $.effects[showAnim])
				inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
			else
				inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
			if (!showAnim || !duration)
				postProcess();
			if (inst.input.is(':visible') && !inst.input.is(':disabled'))
				inst.input.focus();
			$.datepicker._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function(inst) {
		var self = this;
		var borders = $.datepicker._getBorders(inst.dpDiv);
		inst.dpDiv.empty().append(this._generateHTML(inst));
		var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
		if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
			cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
		}
		inst.dpDiv.find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')
				.bind('mouseout', function(){
					$(this).removeClass('ui-state-hover');
					if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
					if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
				})
				.bind('mouseover', function(){
					if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {
						$(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
						$(this).addClass('ui-state-hover');
						if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
						if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
					}
				})
			.end()
			.find('.' + this._dayOverClass + ' a')
				.trigger('mouseover')
			.end();
		var numMonths = this._getNumberOfMonths(inst);
		var cols = numMonths[1];
		var width = 17;
		if (cols > 1)
			inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
		else
			inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
		inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
			'Class']('ui-datepicker-multi');
		inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
			'Class']('ui-datepicker-rtl');
		if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
				// #6694 - don't focus the input if it's already focused
				// this breaks the change event in IE
				inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
			inst.input.focus();
		// deffered render of the years select (to avoid flashes on Firefox) 
		if( inst.yearshtml ){
			var origyearshtml = inst.yearshtml;
			setTimeout(function(){
				//assure that inst.yearshtml didn't change.
				if( origyearshtml === inst.yearshtml ){
					inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml);
				}
				origyearshtml = inst.yearshtml = null;
			}, 0);
		}
	},

	/* Retrieve the size of left and top borders for an element.
	   @param  elem  (jQuery object) the element of interest
	   @return  (number[2]) the left and top borders */
	_getBorders: function(elem) {
		var convert = function(value) {
			return {thin: 1, medium: 2, thick: 3}[value] || value;
		};
		return [parseFloat(convert(elem.css('border-left-width'))),
			parseFloat(convert(elem.css('border-top-width')))];
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function(inst, offset, isFixed) {
		var dpWidth = inst.dpDiv.outerWidth();
		var dpHeight = inst.dpDiv.outerHeight();
		var inputWidth = inst.input ? inst.input.outerWidth() : 0;
		var inputHeight = inst.input ? inst.input.outerHeight() : 0;
		var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
		var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();

		offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
		offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
		offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;

		// now check if datepicker is showing outside window viewport - move to a better place if so.
		offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
			Math.abs(offset.left + dpWidth - viewWidth) : 0);
		offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
			Math.abs(dpHeight + inputHeight) : 0);

		return offset;
	},

	/* Find an object's position on the screen. */
	_findPos: function(obj) {
		var inst = this._getInst(obj);
		var isRTL = this._get(inst, 'isRTL');
        while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
            obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
        }
        var position = $(obj).offset();
	    return [position.left, position.top];
	},

	/* Hide the date picker from view.
	   @param  input  element - the input field attached to the date picker */
	_hideDatepicker: function(input) {
		var inst = this._curInst;
		if (!inst || (input && inst != $.data(input, PROP_NAME)))
			return;
		if (this._datepickerShowing) {
			var showAnim = this._get(inst, 'showAnim');
			var duration = this._get(inst, 'duration');
			var postProcess = function() {
				$.datepicker._tidyDialog(inst);
				this._curInst = null;
			};
			if ($.effects && $.effects[showAnim])
				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
			else
				inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
					(showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
			if (!showAnim)
				postProcess();
			var onClose = this._get(inst, 'onClose');
			if (onClose)
				onClose.apply((inst.input ? inst.input[0] : null),
					[(inst.input ? inst.input.val() : ''), inst]);  // trigger custom callback
			this._datepickerShowing = false;
			this._lastInput = null;
			if (this._inDialog) {
				this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
				if ($.blockUI) {
					$.unblockUI();
					$('body').append(this.dpDiv);
				}
			}
			this._inDialog = false;
		}
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function(event) {
		if (!$.datepicker._curInst)
			return;
		var $target = $(event.target);
		if ($target[0].id != $.datepicker._mainDivId &&
				$target.parents('#' + $.datepicker._mainDivId).length == 0 &&
				!$target.hasClass($.datepicker.markerClassName) &&
				!$target.hasClass($.datepicker._triggerClass) &&
				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
			$.datepicker._hideDatepicker();
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var target = $(id);
		var inst = this._getInst(target[0]);
		if (this._isDisabledDatepicker(target[0])) {
			return;
		}
		this._adjustInstDate(inst, offset +
			(period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
			period);
		this._updateDatepicker(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var target = $(id);
		var inst = this._getInst(target[0]);
		if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		}
		else {
			var date = new Date();
			inst.selectedDay = date.getDate();
			inst.drawMonth = inst.selectedMonth = date.getMonth();
			inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._notifyChange(inst);
		this._adjustDate(target);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var target = $(id);
		var inst = this._getInst(target[0]);
		inst._selectingMonthYear = false;
		inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
		inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
			parseInt(select.options[select.selectedIndex].value,10);
		this._notifyChange(inst);
		this._adjustDate(target);
	},

	/* Restore input focus after not changing month/year. */
	_clickMonthYear: function(id) {
		var target = $(id);
		var inst = this._getInst(target[0]);
		if (inst.input && inst._selectingMonthYear) {
			setTimeout(function() {
				inst.input.focus();
			}, 0);
		}
		inst._selectingMonthYear = !inst._selectingMonthYear;
	},

	/* Action for selecting a day. */
	_selectDay: function(id, month, year, td) {
		var target = $(id);
		if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
			return;
		}
		var inst = this._getInst(target[0]);
		inst.selectedDay = inst.currentDay = $('a', td).html();
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		this._selectDate(id, this._formatDate(inst,
			inst.currentDay, inst.currentMonth, inst.currentYear));
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function(id) {
		var target = $(id);
		var inst = this._getInst(target[0]);
		this._selectDate(target, '');
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var target = $(id);
		var inst = this._getInst(target[0]);
		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
		if (inst.input)
			inst.input.val(dateStr);
		this._updateAlternate(inst);
		var onSelect = this._get(inst, 'onSelect');
		if (onSelect)
			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
		else if (inst.input)
			inst.input.trigger('change'); // fire the change event
		if (inst.inline)
			this._updateDatepicker(inst);
		else {
			this._hideDatepicker();
			this._lastInput = inst.input[0];
			if (typeof(inst.input[0]) != 'object')
				inst.input.focus(); // restore focus
			this._lastInput = null;
		}
	},

	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function(inst) {
		var altField = this._get(inst, 'altField');
		if (altField) { // update alternate field too
			var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
			var date = this._getDate(inst);
			var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
			$(altField).each(function() { $(this).val(dateStr); });
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	   @param  date  Date - the date to customise
	   @return [boolean, string] - is this date selectable?, what is its CSS class? */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ''];
	},

	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	   @param  date  Date - the date to get the week for
	   @return  number - the number of the week within the year that contains this date */
	iso8601Week: function(date) {
		var checkDate = new Date(date.getTime());
		// Find Thursday of this week starting on Monday
		checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
		var time = checkDate.getTime();
		checkDate.setMonth(0); // Compare with Jan 1
		checkDate.setDate(1);
		return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
	},

	/* Parse a string value into a date object.
	   See formatDate below for the possible formats.

	   @param  format    string - the expected format of the date
	   @param  value     string - the date in the above format
	   @param  settings  Object - attributes include:
	                     shortYearCutoff  number - the cutoff year for determining the century (optional)
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  Date - the extracted date value or null if value is blank */
	parseDate: function (format, value, settings) {
		if (format == null || value == null)
			throw 'Invalid arguments';
		value = (typeof value == 'object' ? value.toString() : value + '');
		if (value == '')
			return null;
		var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
				new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		var year = -1;
		var month = -1;
		var day = -1;
		var doy = -1;
		var literal = false;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;
		};
		// Extract a number from the string value
		var getNumber = function(match) {
			var isDoubled = lookAhead(match);
			var size = (match == '@' ? 14 : (match == '!' ? 20 :
				(match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
			var digits = new RegExp('^\\d{1,' + size + '}');
			var num = value.substring(iValue).match(digits);
			if (!num)
				throw 'Missing number at position ' + iValue;
			iValue += num[0].length;
			return parseInt(num[0], 10);
		};
		// Extract a name from the string value and convert to an index
		var getName = function(match, shortNames, longNames) {
			var names = (lookAhead(match) ? longNames : shortNames);
			for (var i = 0; i < names.length; i++) {
				if (value.substr(iValue, names[i].length).toLowerCase() == names[i].toLowerCase()) {
					iValue += names[i].length;
					return i + 1;
				}
			}
			throw 'Unknown name at position ' + iValue;
		};
		// Confirm that a literal character matches the string value
		var checkLiteral = function() {
			if (value.charAt(iValue) != format.charAt(iFormat))
				throw 'Unexpected literal at position ' + iValue;
			iValue++;
		};
		var iValue = 0;
		for (var iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					checkLiteral();
			else
				switch (format.charAt(iFormat)) {
					case 'd':
						day = getNumber('d');
						break;
					case 'D':
						getName('D', dayNamesShort, dayNames);
						break;
					case 'o':
						doy = getNumber('o');
						break;
					case 'm':
						month = getNumber('m');
						break;
					case 'M':
						month = getName('M', monthNamesShort, monthNames);
						break;
					case 'y':
						year = getNumber('y');
						break;
					case '@':
						var date = new Date(getNumber('@'));
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case '!':
						var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if (lookAhead("'"))
							checkLiteral();
						else
							literal = true;
						break;
					default:
						checkLiteral();
				}
		}
		if (year == -1)
			year = new Date().getFullYear();
		else if (year < 100)
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				(year <= shortYearCutoff ? 0 : -100);
		if (doy > -1) {
			month = 1;
			day = doy;
			do {
				var dim = this._getDaysInMonth(year, month - 1);
				if (day <= dim)
					break;
				month++;
				day -= dim;
			} while (true);
		}
		var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
		if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
			throw 'Invalid date'; // E.g. 31/02/00
		return date;
	},

	/* Standard date formats. */
	ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
	COOKIE: 'D, dd M yy',
	ISO_8601: 'yy-mm-dd',
	RFC_822: 'D, d M y',
	RFC_850: 'DD, dd-M-y',
	RFC_1036: 'D, d M y',
	RFC_1123: 'D, d M yy',
	RFC_2822: 'D, d M yy',
	RSS: 'D, d M y', // RFC 822
	TICKS: '!',
	TIMESTAMP: '@',
	W3C: 'yy-mm-dd', // ISO 8601

	_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
		Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),

	/* Format a date object into a string value.
	   The format can be combinations of the following:
	   d  - day of month (no leading zero)
	   dd - day of month (two digit)
	   o  - day of year (no leading zeros)
	   oo - day of year (three digit)
	   D  - day name short
	   DD - day name long
	   m  - month of year (no leading zero)
	   mm - month of year (two digit)
	   M  - month name short
	   MM - month name long
	   y  - year (two digit)
	   yy - year (four digit)
	   @ - Unix timestamp (ms since 01/01/1970)
	   ! - Windows ticks (100ns since 01/01/0001)
	   '...' - literal text
	   '' - single quote

	   @param  format    string - the desired format of the date
	   @param  date      Date - the date value to format
	   @param  settings  Object - attributes include:
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  string - the date in the above format */
	formatDate: function (format, date, settings) {
		if (!date)
			return '';
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;
		};
		// Format a number, with leading zero if necessary
		var formatNumber = function(match, value, len) {
			var num = '' + value;
			if (lookAhead(match))
				while (num.length < len)
					num = '0' + num;
			return num;
		};
		// Format a name, short or long as requested
		var formatName = function(match, value, shortNames, longNames) {
			return (lookAhead(match) ? longNames[value] : shortNames[value]);
		};
		var output = '';
		var literal = false;
		if (date)
			for (var iFormat = 0; iFormat < format.length; iFormat++) {
				if (literal)
					if (format.charAt(iFormat) == "'" && !lookAhead("'"))
						literal = false;
					else
						output += format.charAt(iFormat);
				else
					switch (format.charAt(iFormat)) {
						case 'd':
							output += formatNumber('d', date.getDate(), 2);
							break;
						case 'D':
							output += formatName('D', date.getDay(), dayNamesShort, dayNames);
							break;
						case 'o':
							output += formatNumber('o',
								(date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3);
							break;
						case 'm':
							output += formatNumber('m', date.getMonth() + 1, 2);
							break;
						case 'M':
							output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
							break;
						case 'y':
							output += (lookAhead('y') ? date.getFullYear() :
								(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
							break;
						case '@':
							output += date.getTime();
							break;
						case '!':
							output += date.getTime() * 10000 + this._ticksTo1970;
							break;
						case "'":
							if (lookAhead("'"))
								output += "'";
							else
								literal = true;
							break;
						default:
							output += format.charAt(iFormat);
					}
			}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function (format) {
		var chars = '';
		var literal = false;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;
		};
		for (var iFormat = 0; iFormat < format.length; iFormat++)
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					chars += format.charAt(iFormat);
			else
				switch (format.charAt(iFormat)) {
					case 'd': case 'm': case 'y': case '@':
						chars += '0123456789';
						break;
					case 'D': case 'M':
						return null; // Accept anything
					case "'":
						if (lookAhead("'"))
							chars += "'";
						else
							literal = true;
						break;
					default:
						chars += format.charAt(iFormat);
				}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function(inst, name) {
		return inst.settings[name] !== undefined ?
			inst.settings[name] : this._defaults[name];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function(inst, noDefault) {
		if (inst.input.val() == inst.lastVal) {
			return;
		}
		var dateFormat = this._get(inst, 'dateFormat');
		var dates = inst.lastVal = inst.input ? inst.input.val() : null;
		var date, defaultDate;
		date = defaultDate = this._getDefaultDate(inst);
		var settings = this._getFormatConfig(inst);
		try {
			date = this.parseDate(dateFormat, dates, settings) || defaultDate;
		} catch (event) {
			this.log(event);
			dates = (noDefault ? '' : dates);
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = (dates ? date.getDate() : 0);
		inst.currentMonth = (dates ? date.getMonth() : 0);
		inst.currentYear = (dates ? date.getFullYear() : 0);
		this._adjustInstDate(inst);
	},

	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function(inst) {
		return this._restrictMinMax(inst,
			this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function(inst, date, defaultDate) {
		var offsetNumeric = function(offset) {
			var date = new Date();
			date.setDate(date.getDate() + offset);
			return date;
		};
		var offsetString = function(offset) {
			try {
				return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
					offset, $.datepicker._getFormatConfig(inst));
			}
			catch (e) {
				// Ignore
			}
			var date = (offset.toLowerCase().match(/^c/) ?
				$.datepicker._getDate(inst) : null) || new Date();
			var year = date.getFullYear();
			var month = date.getMonth();
			var day = date.getDate();
			var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
			var matches = pattern.exec(offset);
			while (matches) {
				switch (matches[2] || 'd') {
					case 'd' : case 'D' :
						day += parseInt(matches[1],10); break;
					case 'w' : case 'W' :
						day += parseInt(matches[1],10) * 7; break;
					case 'm' : case 'M' :
						month += parseInt(matches[1],10);
						day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
						break;
					case 'y': case 'Y' :
						year += parseInt(matches[1],10);
						day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
						break;
				}
				matches = pattern.exec(offset);
			}
			return new Date(year, month, day);
		};
		var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
			(typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
		newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
		if (newDate) {
			newDate.setHours(0);
			newDate.setMinutes(0);
			newDate.setSeconds(0);
			newDate.setMilliseconds(0);
		}
		return this._daylightSavingAdjust(newDate);
	},

	/* Handle switch to/from daylight saving.
	   Hours may be non-zero on daylight saving cut-over:
	   > 12 when midnight changeover, but then cannot generate
	   midnight datetime, so jump to 1AM, otherwise reset.
	   @param  date  (Date) the date to check
	   @return  (Date) the corrected date */
	_daylightSavingAdjust: function(date) {
		if (!date) return null;
		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
		return date;
	},

	/* Set the date(s) directly. */
	_setDate: function(inst, date, noChange) {
		var clear = !date;
		var origMonth = inst.selectedMonth;
		var origYear = inst.selectedYear;
		var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
		inst.selectedDay = inst.currentDay = newDate.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
		if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
			this._notifyChange(inst);
		this._adjustInstDate(inst);
		if (inst.input) {
			inst.input.val(clear ? '' : this._formatDate(inst));
		}
	},

	/* Retrieve the date(s) directly. */
	_getDate: function(inst) {
		var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
			this._daylightSavingAdjust(new Date(
			inst.currentYear, inst.currentMonth, inst.currentDay)));
			return startDate;
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateHTML: function(inst) {
		var today = new Date();
		today = this._daylightSavingAdjust(
			new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
		var isRTL = this._get(inst, 'isRTL');
		var showButtonPanel = this._get(inst, 'showButtonPanel');
		var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
		var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
		var numMonths = this._getNumberOfMonths(inst);
		var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
		var stepMonths = this._get(inst, 'stepMonths');
		var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
		var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
			new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		var minDate = this._getMinMaxDate(inst, 'min');
		var maxDate = this._getMinMaxDate(inst, 'max');
		var drawMonth = inst.drawMonth - showCurrentAtPos;
		var drawYear = inst.drawYear;
		if (drawMonth < 0) {
			drawMonth += 12;
			drawYear--;
		}
		if (maxDate) {
			var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
				maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
				drawMonth--;
				if (drawMonth < 0) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
		inst.drawMonth = drawMonth;
		inst.drawYear = drawYear;
		var prevText = this._get(inst, 'prevText');
		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
			this._getFormatConfig(inst)));
		var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
			'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_' + dpuuid +
			'.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
			' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
			(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>'));
		var nextText = this._get(inst, 'nextText');
		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
			this._getFormatConfig(inst)));
		var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
			'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_' + dpuuid +
			'.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
			' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
			(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>'));
		var currentText = this._get(inst, 'currentText');
		var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
		currentText = (!navigationAsDateFormat ? currentText :
			this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
		var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
			'.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
		var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
			(this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
			'.datepicker._gotoToday(\'#' + inst.id + '\');"' +
			'>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
		var firstDay = parseInt(this._get(inst, 'firstDay'),10);
		firstDay = (isNaN(firstDay) ? 0 : firstDay);
		var showWeek = this._get(inst, 'showWeek');
		var dayNames = this._get(inst, 'dayNames');
		var dayNamesShort = this._get(inst, 'dayNamesShort');
		var dayNamesMin = this._get(inst, 'dayNamesMin');
		var monthNames = this._get(inst, 'monthNames');
		var monthNamesShort = this._get(inst, 'monthNamesShort');
		var beforeShowDay = this._get(inst, 'beforeShowDay');
		var showOtherMonths = this._get(inst, 'showOtherMonths');
		var selectOtherMonths = this._get(inst, 'selectOtherMonths');
		var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
		var defaultDate = this._getDefaultDate(inst);
		var html = '';
		for (var row = 0; row < numMonths[0]; row++) {
			var group = '';
			for (var col = 0; col < numMonths[1]; col++) {
				var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
				var cornerClass = ' ui-corner-all';
				var calender = '';
				if (isMultiMonth) {
					calender += '<div class="ui-datepicker-group';
					if (numMonths[1] > 1)
						switch (col) {
							case 0: calender += ' ui-datepicker-group-first';
								cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
							case numMonths[1]-1: calender += ' ui-datepicker-group-last';
								cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
							default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
						}
					calender += '">';
				}
				calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
					(/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
					(/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
					row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
					'</div><table class="ui-datepicker-calendar"><thead>' +
					'<tr>';
				var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
				for (var dow = 0; dow < 7; dow++) { // days of the week
					var day = (dow + firstDay) % 7;
					thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
						'<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
				}
				calender += thead + '</tr></thead><tbody>';
				var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
				if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
				var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
				var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
				var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
				for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
					calender += '<tr>';
					var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
						this._get(inst, 'calculateWeek')(printDate) + '</td>');
					for (var dow = 0; dow < 7; dow++) { // create date picker days
						var daySettings = (beforeShowDay ?
							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
						var otherMonth = (printDate.getMonth() != drawMonth);
						var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
						tbody += '<td class="' +
							((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
							(otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
							((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
							(defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
							// or defaultDate is current printedDate and defaultDate is selectedDate
							' ' + this._dayOverClass : '') + // highlight selected day
							(unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') +  // highlight unselectable days
							(otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
							(printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
							(printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
							((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
							(unselectable ? '' : ' onclick="DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
							inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;"') + '>' + // actions
							(otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
							(unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
							(printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
							(printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
							(otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
							'" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
						printDate.setDate(printDate.getDate() + 1);
						printDate = this._daylightSavingAdjust(printDate);
					}
					calender += tbody + '</tr>';
				}
				drawMonth++;
				if (drawMonth > 11) {
					drawMonth = 0;
					drawYear++;
				}
				calender += '</tbody></table>' + (isMultiMonth ? '</div>' + 
							((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
				group += calender;
			}
			html += group;
		}
		html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
			'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
		inst._keyEvent = false;
		return html;
	},

	/* Generate the month and year header. */
	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
			secondary, monthNames, monthNamesShort) {
		var changeMonth = this._get(inst, 'changeMonth');
		var changeYear = this._get(inst, 'changeYear');
		var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
		var html = '<div class="ui-datepicker-title">';
		var monthHtml = '';
		// month selection
		if (secondary || !changeMonth)
			monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
		else {
			var inMinYear = (minDate && minDate.getFullYear() == drawYear);
			var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
			monthHtml += '<select class="ui-datepicker-month" ' +
				'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
				'onclick="DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
			 	'>';
			for (var month = 0; month < 12; month++) {
				if ((!inMinYear || month >= minDate.getMonth()) &&
						(!inMaxYear || month <= maxDate.getMonth()))
					monthHtml += '<option value="' + month + '"' +
						(month == drawMonth ? ' selected="selected"' : '') +
						'>' + monthNamesShort[month] + '</option>';
			}
			monthHtml += '</select>';
		}
		if (!showMonthAfterYear)
			html += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');
		// year selection
		if ( !inst.yearshtml ) {
			inst.yearshtml = '';
			if (secondary || !changeYear)
				html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
			else {
				// determine range of years to display
				var years = this._get(inst, 'yearRange').split(':');
				var thisYear = new Date().getFullYear();
				var determineYear = function(value) {
					var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
						(value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
						parseInt(value, 10)));
					return (isNaN(year) ? thisYear : year);
				};
				var year = determineYear(years[0]);
				var endYear = Math.max(year, determineYear(years[1] || ''));
				year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
				endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
				inst.yearshtml += '<select class="ui-datepicker-year" ' +
					'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
					'onclick="DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
					'>';
				for (; year <= endYear; year++) {
					inst.yearshtml += '<option value="' + year + '"' +
						(year == drawYear ? ' selected="selected"' : '') +
						'>' + year + '</option>';
				}
				inst.yearshtml += '</select>';
				//when showing there is no need for later update
				if( ! $.browser.mozilla ){
					html += inst.yearshtml;
					inst.yearshtml = null;
				} else {
					// will be replaced later with inst.yearshtml
					html += '<select class="ui-datepicker-year"><option value="' + drawYear + '" selected="selected">' + drawYear + '</option></select>';
				}
			}
		}
		html += this._get(inst, 'yearSuffix');
		if (showMonthAfterYear)
			html += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;
		html += '</div>'; // Close datepicker_header
		return html;
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function(inst, offset, period) {
		var year = inst.drawYear + (period == 'Y' ? offset : 0);
		var month = inst.drawMonth + (period == 'M' ? offset : 0);
		var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
			(period == 'D' ? offset : 0);
		var date = this._restrictMinMax(inst,
			this._daylightSavingAdjust(new Date(year, month, day)));
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if (period == 'M' || period == 'Y')
			this._notifyChange(inst);
	},

	/* Ensure a date is within any min/max bounds. */
	_restrictMinMax: function(inst, date) {
		var minDate = this._getMinMaxDate(inst, 'min');
		var maxDate = this._getMinMaxDate(inst, 'max');
		var newDate = (minDate && date < minDate ? minDate : date);
		newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
		return newDate;
	},

	/* Notify change of month/year. */
	_notifyChange: function(inst) {
		var onChange = this._get(inst, 'onChangeMonthYear');
		if (onChange)
			onChange.apply((inst.input ? inst.input[0] : null),
				[inst.selectedYear, inst.selectedMonth + 1, inst]);
	},

	/* Determine the number of months to show. */
	_getNumberOfMonths: function(inst) {
		var numMonths = this._get(inst, 'numberOfMonths');
		return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
	},

	/* Determine the current maximum date - ensure no time components are set. */
	_getMinMaxDate: function(inst, minMax) {
		return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
		var numMonths = this._getNumberOfMonths(inst);
		var date = this._daylightSavingAdjust(new Date(curYear,
			curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
		if (offset < 0)
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		return this._isInRange(inst, date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(inst, date) {
		var minDate = this._getMinMaxDate(inst, 'min');
		var maxDate = this._getMinMaxDate(inst, 'max');
		return ((!minDate || date.getTime() >= minDate.getTime()) &&
			(!maxDate || date.getTime() <= maxDate.getTime()));
	},

	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function(inst) {
		var shortYearCutoff = this._get(inst, 'shortYearCutoff');
		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		return {shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
			monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
	},

	/* Format the given date for display. */
	_formatDate: function(inst, day, month, year) {
		if (!day) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = (day ? (typeof day == 'object' ? day :
			this._daylightSavingAdjust(new Date(year, month, day))) :
			this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
	}
});

/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props)
		if (props[name] == null || props[name] == undefined)
			target[name] = props[name];
	return target;
};

/* Determine whether an object is an array. */
function isArray(a) {
	return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
		(a.constructor && a.constructor.toString().match(/\Array\(\)/))));
};

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
                    Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function(options){
	
	/* Verify an empty collection wasn't passed - Fixes #6976 */
	if ( !this.length ) {
		return this;
	}
	
	/* Initialise the date picker. */
	if (!$.datepicker.initialized) {
		$(document).mousedown($.datepicker._checkExternalClick).
			find('body').append($.datepicker.dpDiv);
		$.datepicker.initialized = true;
	}

	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
		return $.datepicker['_' + options + 'Datepicker'].
			apply($.datepicker, [this[0]].concat(otherArgs));
	if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
		return $.datepicker['_' + options + 'Datepicker'].
			apply($.datepicker, [this[0]].concat(otherArgs));
	return this.each(function() {
		typeof options == 'string' ?
			$.datepicker['_' + options + 'Datepicker'].
				apply($.datepicker, [this].concat(otherArgs)) :
			$.datepicker._attachDatepicker(this, options);
	});
};

$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;
$.datepicker.uuid = new Date().getTime();
$.datepicker.version = "1.8.12";

// Workaround for #4055
// Add another global to avoid noConflict issues with inline event handlers
window['DP_jQuery_' + dpuuid] = $;

})(jQuery);
/*
 * jQuery UI Dialog 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Dialog
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *  jquery.ui.button.js
 *	jquery.ui.draggable.js
 *	jquery.ui.mouse.js
 *	jquery.ui.position.js
 *	jquery.ui.resizable.js
 */
(function( $, undefined ) {

var uiDialogClasses =
		'ui-dialog ' +
		'ui-widget ' +
		'ui-widget-content ' +
		'ui-corner-all ',
	sizeRelatedOptions = {
		buttons: true,
		height: true,
		maxHeight: true,
		maxWidth: true,
		minHeight: true,
		minWidth: true,
		width: true
	},
	resizableRelatedOptions = {
		maxHeight: true,
		maxWidth: true,
		minHeight: true,
		minWidth: true
	},
	// support for jQuery 1.3.2 - handle common attrFn methods for dialog
	attrFn = $.attrFn || {
		val: true,
		css: true,
		html: true,
		text: true,
		data: true,
		width: true,
		height: true,
		offset: true,
		click: true
	};

$.widget("ui.dialog", {
	options: {
		autoOpen: true,
		buttons: {},
		closeOnEscape: true,
		closeText: 'close',
		dialogClass: '',
		draggable: true,
		hide: null,
		height: 'auto',
		maxHeight: false,
		maxWidth: false,
		minHeight: 150,
		minWidth: 150,
		modal: false,
		position: {
			my: 'center',
			at: 'center',
			collision: 'fit',
			// ensure that the titlebar is never outside the document
			using: function(pos) {
				var topOffset = $(this).css(pos).offset().top;
				if (topOffset < 0) {
					$(this).css('top', pos.top - topOffset);
				}
			}
		},
		resizable: true,
		show: null,
		stack: true,
		title: '',
		width: 300,
		zIndex: 1000
	},

	_create: function() {
		this.originalTitle = this.element.attr('title');
		// #5742 - .attr() might return a DOMElement
		if ( typeof this.originalTitle !== "string" ) {
			this.originalTitle = "";
		}

		this.options.title = this.options.title || this.originalTitle;
		var self = this,
			options = self.options,

			title = options.title || '&#160;',
			titleId = $.ui.dialog.getTitleId(self.element),

			uiDialog = (self.uiDialog = $('<div></div>'))
				.appendTo(document.body)
				.hide()
				.addClass(uiDialogClasses + options.dialogClass)
				.css({
					zIndex: options.zIndex
				})
				// setting tabIndex makes the div focusable
				// setting outline to 0 prevents a border on focus in Mozilla
				.attr('tabIndex', -1).css('outline', 0).keydown(function(event) {
					if (options.closeOnEscape && event.keyCode &&
						event.keyCode === $.ui.keyCode.ESCAPE) {
						
						self.close(event);
						event.preventDefault();
					}
				})
				.attr({
					role: 'dialog',
					'aria-labelledby': titleId
				})
				.mousedown(function(event) {
					self.moveToTop(false, event);
				}),

			uiDialogContent = self.element
				.show()
				.removeAttr('title')
				.addClass(
					'ui-dialog-content ' +
					'ui-widget-content')
				.appendTo(uiDialog),

			uiDialogTitlebar = (self.uiDialogTitlebar = $('<div></div>'))
				.addClass(
					'ui-dialog-titlebar ' +
					'ui-widget-header ' +
					'ui-corner-top ' +
					'ui-helper-clearfix'
				)
				.prependTo(uiDialog),

			uiDialogTitlebarClose = $('<a href="#"></a>')
				.addClass(
					'ui-dialog-titlebar-close ' +
					'ui-corner-all'
				)
				.attr('role', 'button')
				.hover(
					function() {
						uiDialogTitlebarClose.addClass('ui-state-hover');
					},
					function() {
						uiDialogTitlebarClose.removeClass('ui-state-hover');
					}
				)
				.focus(function() {
					uiDialogTitlebarClose.addClass('ui-state-focus');
				})
				.blur(function() {
					uiDialogTitlebarClose.removeClass('ui-state-focus');
				})
				.click(function(event) {
					self.close(event);
					return false;
				})
				.appendTo(uiDialogTitlebar),

			uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('<span></span>'))
				.addClass(
					'ui-icon ' +
					'ui-icon-closethick'
				)
				.text(options.closeText)
				.appendTo(uiDialogTitlebarClose),

			uiDialogTitle = $('<span></span>')
				.addClass('ui-dialog-title')
				.attr('id', titleId)
				.html(title)
				.prependTo(uiDialogTitlebar);

		//handling of deprecated beforeclose (vs beforeClose) option
		//Ticket #4669 http://dev.jqueryui.com/ticket/4669
		//TODO: remove in 1.9pre
		if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) {
			options.beforeClose = options.beforeclose;
		}

		uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();

		if (options.draggable && $.fn.draggable) {
			self._makeDraggable();
		}
		if (options.resizable && $.fn.resizable) {
			self._makeResizable();
		}

		self._createButtons(options.buttons);
		self._isOpen = false;

		if ($.fn.bgiframe) {
			uiDialog.bgiframe();
		}
	},

	_init: function() {
		if ( this.options.autoOpen ) {
			this.open();
		}
	},

	destroy: function() {
		var self = this;
		
		if (self.overlay) {
			self.overlay.destroy();
		}
		self.uiDialog.hide();
		self.element
			.unbind('.dialog')
			.removeData('dialog')
			.removeClass('ui-dialog-content ui-widget-content')
			.hide().appendTo('body');
		self.uiDialog.remove();

		if (self.originalTitle) {
			self.element.attr('title', self.originalTitle);
		}

		return self;
	},

	widget: function() {
		return this.uiDialog;
	},

	close: function(event) {
		var self = this,
			maxZ, thisZ;
		
		if (false === self._trigger('beforeClose', event)) {
			return;
		}

		if (self.overlay) {
			self.overlay.destroy();
		}
		self.uiDialog.unbind('keypress.ui-dialog');

		self._isOpen = false;

		if (self.options.hide) {
			self.uiDialog.hide(self.options.hide, function() {
				self._trigger('close', event);
			});
		} else {
			self.uiDialog.hide();
			self._trigger('close', event);
		}

		$.ui.dialog.overlay.resize();

		// adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
		if (self.options.modal) {
			maxZ = 0;
			$('.ui-dialog').each(function() {
				if (this !== self.uiDialog[0]) {
					thisZ = $(this).css('z-index');
					if(!isNaN(thisZ)) {
						maxZ = Math.max(maxZ, thisZ);
					}
				}
			});
			$.ui.dialog.maxZ = maxZ;
		}

		return self;
	},

	isOpen: function() {
		return this._isOpen;
	},

	// the force parameter allows us to move modal dialogs to their correct
	// position on open
	moveToTop: function(force, event) {
		var self = this,
			options = self.options,
			saveScroll;

		if ((options.modal && !force) ||
			(!options.stack && !options.modal)) {
			return self._trigger('focus', event);
		}

		if (options.zIndex > $.ui.dialog.maxZ) {
			$.ui.dialog.maxZ = options.zIndex;
		}
		if (self.overlay) {
			$.ui.dialog.maxZ += 1;
			self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ);
		}

		//Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.
		//  http://ui.jquery.com/bugs/ticket/3193
		saveScroll = { scrollTop: self.element.attr('scrollTop'), scrollLeft: self.element.attr('scrollLeft') };
		$.ui.dialog.maxZ += 1;
		self.uiDialog.css('z-index', $.ui.dialog.maxZ);
		self.element.attr(saveScroll);
		self._trigger('focus', event);

		return self;
	},

	open: function() {
		if (this._isOpen) { return; }

		var self = this,
			options = self.options,
			uiDialog = self.uiDialog;

		self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
		self._size();
		self._position(options.position);
		uiDialog.show(options.show);
		self.moveToTop(true);

		// prevent tabbing out of modal dialogs
		if (options.modal) {
			uiDialog.bind('keypress.ui-dialog', function(event) {
				if (event.keyCode !== $.ui.keyCode.TAB) {
					return;
				}

				var tabbables = $(':tabbable', this),
					first = tabbables.filter(':first'),
					last  = tabbables.filter(':last');

				if (event.target === last[0] && !event.shiftKey) {
					first.focus(1);
					return false;
				} else if (event.target === first[0] && event.shiftKey) {
					last.focus(1);
					return false;
				}
			});
		}

		// set focus to the first tabbable element in the content area or the first button
		// if there are no tabbable elements, set focus on the dialog itself
		$(self.element.find(':tabbable').get().concat(
			uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
				uiDialog.get()))).eq(0).focus();

		self._isOpen = true;
		self._trigger('open');

		return self;
	},

	_createButtons: function(buttons) {
		var self = this,
			hasButtons = false,
			uiDialogButtonPane = $('<div></div>')
				.addClass(
					'ui-dialog-buttonpane ' +
					'ui-widget-content ' +
					'ui-helper-clearfix'
				),
			uiButtonSet = $( "<div></div>" )
				.addClass( "ui-dialog-buttonset" )
				.appendTo( uiDialogButtonPane );

		// if we already have a button pane, remove it
		self.uiDialog.find('.ui-dialog-buttonpane').remove();

		if (typeof buttons === 'object' && buttons !== null) {
			$.each(buttons, function() {
				return !(hasButtons = true);
			});
		}
		if (hasButtons) {
			$.each(buttons, function(name, props) {
				props = $.isFunction( props ) ?
					{ click: props, text: name } :
					props;
				var button = $('<button type="button"></button>')
					.click(function() {
						props.click.apply(self.element[0], arguments);
					})
					.appendTo(uiButtonSet);
				// can't use .attr( props, true ) with jQuery 1.3.2.
				$.each( props, function( key, value ) {
					if ( key === "click" ) {
						return;
					}
					if ( key in attrFn ) {
						button[ key ]( value );
					} else {
						button.attr( key, value );
					}
				});
				if ($.fn.button) {
					button.button();
				}
			});
			uiDialogButtonPane.appendTo(self.uiDialog);
		}
	},

	_makeDraggable: function() {
		var self = this,
			options = self.options,
			doc = $(document),
			heightBeforeDrag;

		function filteredUi(ui) {
			return {
				position: ui.position,
				offset: ui.offset
			};
		}

		self.uiDialog.draggable({
			cancel: '.ui-dialog-content, .ui-dialog-titlebar-close',
			handle: '.ui-dialog-titlebar',
			containment: 'document',
			start: function(event, ui) {
				heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height();
				$(this).height($(this).height()).addClass("ui-dialog-dragging");
				self._trigger('dragStart', event, filteredUi(ui));
			},
			drag: function(event, ui) {
				self._trigger('drag', event, filteredUi(ui));
			},
			stop: function(event, ui) {
				options.position = [ui.position.left - doc.scrollLeft(),
					ui.position.top - doc.scrollTop()];
				$(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
				self._trigger('dragStop', event, filteredUi(ui));
				$.ui.dialog.overlay.resize();
			}
		});
	},

	_makeResizable: function(handles) {
		handles = (handles === undefined ? this.options.resizable : handles);
		var self = this,
			options = self.options,
			// .ui-resizable has position: relative defined in the stylesheet
			// but dialogs have to use absolute or fixed positioning
			position = self.uiDialog.css('position'),
			resizeHandles = (typeof handles === 'string' ?
				handles	:
				'n,e,s,w,se,sw,ne,nw'
			);

		function filteredUi(ui) {
			return {
				originalPosition: ui.originalPosition,
				originalSize: ui.originalSize,
				position: ui.position,
				size: ui.size
			};
		}

		self.uiDialog.resizable({
			cancel: '.ui-dialog-content',
			containment: 'document',
			alsoResize: self.element,
			maxWidth: options.maxWidth,
			maxHeight: options.maxHeight,
			minWidth: options.minWidth,
			minHeight: self._minHeight(),
			handles: resizeHandles,
			start: function(event, ui) {
				$(this).addClass("ui-dialog-resizing");
				self._trigger('resizeStart', event, filteredUi(ui));
			},
			resize: function(event, ui) {
				self._trigger('resize', event, filteredUi(ui));
			},
			stop: function(event, ui) {
				$(this).removeClass("ui-dialog-resizing");
				options.height = $(this).height();
				options.width = $(this).width();
				self._trigger('resizeStop', event, filteredUi(ui));
				$.ui.dialog.overlay.resize();
			}
		})
		.css('position', position)
		.find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
	},

	_minHeight: function() {
		var options = this.options;

		if (options.height === 'auto') {
			return options.minHeight;
		} else {
			return Math.min(options.minHeight, options.height);
		}
	},

	_position: function(position) {
		var myAt = [],
			offset = [0, 0],
			isVisible;

		if (position) {
			// deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
	//		if (typeof position == 'string' || $.isArray(position)) {
	//			myAt = $.isArray(position) ? position : position.split(' ');

			if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) {
				myAt = position.split ? position.split(' ') : [position[0], position[1]];
				if (myAt.length === 1) {
					myAt[1] = myAt[0];
				}

				$.each(['left', 'top'], function(i, offsetPosition) {
					if (+myAt[i] === myAt[i]) {
						offset[i] = myAt[i];
						myAt[i] = offsetPosition;
					}
				});

				position = {
					my: myAt.join(" "),
					at: myAt.join(" "),
					offset: offset.join(" ")
				};
			} 

			position = $.extend({}, $.ui.dialog.prototype.options.position, position);
		} else {
			position = $.ui.dialog.prototype.options.position;
		}

		// need to show the dialog to get the actual offset in the position plugin
		isVisible = this.uiDialog.is(':visible');
		if (!isVisible) {
			this.uiDialog.show();
		}
		this.uiDialog
			// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
			.css({ top: 0, left: 0 })
			.position($.extend({ of: window }, position));
		if (!isVisible) {
			this.uiDialog.hide();
		}
	},

	_setOptions: function( options ) {
		var self = this,
			resizableOptions = {},
			resize = false;

		$.each( options, function( key, value ) {
			self._setOption( key, value );
			
			if ( key in sizeRelatedOptions ) {
				resize = true;
			}
			if ( key in resizableRelatedOptions ) {
				resizableOptions[ key ] = value;
			}
		});

		if ( resize ) {
			this._size();
		}
		if ( this.uiDialog.is( ":data(resizable)" ) ) {
			this.uiDialog.resizable( "option", resizableOptions );
		}
	},

	_setOption: function(key, value){
		var self = this,
			uiDialog = self.uiDialog;

		switch (key) {
			//handling of deprecated beforeclose (vs beforeClose) option
			//Ticket #4669 http://dev.jqueryui.com/ticket/4669
			//TODO: remove in 1.9pre
			case "beforeclose":
				key = "beforeClose";
				break;
			case "buttons":
				self._createButtons(value);
				break;
			case "closeText":
				// ensure that we always pass a string
				self.uiDialogTitlebarCloseText.text("" + value);
				break;
			case "dialogClass":
				uiDialog
					.removeClass(self.options.dialogClass)
					.addClass(uiDialogClasses + value);
				break;
			case "disabled":
				if (value) {
					uiDialog.addClass('ui-dialog-disabled');
				} else {
					uiDialog.removeClass('ui-dialog-disabled');
				}
				break;
			case "draggable":
				var isDraggable = uiDialog.is( ":data(draggable)" );
				if ( isDraggable && !value ) {
					uiDialog.draggable( "destroy" );
				}
				
				if ( !isDraggable && value ) {
					self._makeDraggable();
				}
				break;
			case "position":
				self._position(value);
				break;
			case "resizable":
				// currently resizable, becoming non-resizable
				var isResizable = uiDialog.is( ":data(resizable)" );
				if (isResizable && !value) {
					uiDialog.resizable('destroy');
				}

				// currently resizable, changing handles
				if (isResizable && typeof value === 'string') {
					uiDialog.resizable('option', 'handles', value);
				}

				// currently non-resizable, becoming resizable
				if (!isResizable && value !== false) {
					self._makeResizable(value);
				}
				break;
			case "title":
				// convert whatever was passed in o a string, for html() to not throw up
				$(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || '&#160;'));
				break;
		}

		$.Widget.prototype._setOption.apply(self, arguments);
	},

	_size: function() {
		/* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
		 * divs will both have width and height set, so we need to reset them
		 */
		var options = this.options,
			nonContentHeight,
			minContentHeight,
			isVisible = this.uiDialog.is( ":visible" );

		// reset content sizing
		this.element.show().css({
			width: 'auto',
			minHeight: 0,
			height: 0
		});

		if (options.minWidth > options.width) {
			options.width = options.minWidth;
		}

		// reset wrapper sizing
		// determine the height of all the non-content elements
		nonContentHeight = this.uiDialog.css({
				height: 'auto',
				width: options.width
			})
			.height();
		minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
		
		if ( options.height === "auto" ) {
			// only needed for IE6 support
			if ( $.support.minHeight ) {
				this.element.css({
					minHeight: minContentHeight,
					height: "auto"
				});
			} else {
				this.uiDialog.show();
				var autoHeight = this.element.css( "height", "auto" ).height();
				if ( !isVisible ) {
					this.uiDialog.hide();
				}
				this.element.height( Math.max( autoHeight, minContentHeight ) );
			}
		} else {
			this.element.height( Math.max( options.height - nonContentHeight, 0 ) );
		}

		if (this.uiDialog.is(':data(resizable)')) {
			this.uiDialog.resizable('option', 'minHeight', this._minHeight());
		}
	}
});

$.extend($.ui.dialog, {
	version: "1.8.12",

	uuid: 0,
	maxZ: 0,

	getTitleId: function($el) {
		var id = $el.attr('id');
		if (!id) {
			this.uuid += 1;
			id = this.uuid;
		}
		return 'ui-dialog-title-' + id;
	},

	overlay: function(dialog) {
		this.$el = $.ui.dialog.overlay.create(dialog);
	}
});

$.extend($.ui.dialog.overlay, {
	instances: [],
	// reuse old instances due to IE memory leak with alpha transparency (see #5185)
	oldInstances: [],
	maxZ: 0,
	events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
		function(event) { return event + '.dialog-overlay'; }).join(' '),
	create: function(dialog) {
		if (this.instances.length === 0) {
			// prevent use of anchors and inputs
			// we use a setTimeout in case the overlay is created from an
			// event that we're going to be cancelling (see #2804)
			setTimeout(function() {
				// handle $(el).dialog().dialog('close') (see #4065)
				if ($.ui.dialog.overlay.instances.length) {
					$(document).bind($.ui.dialog.overlay.events, function(event) {
						// stop events if the z-index of the target is < the z-index of the overlay
						// we cannot return true when we don't want to cancel the event (#3523)
						if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) {
							return false;
						}
					});
				}
			}, 1);

			// allow closing by pressing the escape key
			$(document).bind('keydown.dialog-overlay', function(event) {
				if (dialog.options.closeOnEscape && event.keyCode &&
					event.keyCode === $.ui.keyCode.ESCAPE) {
					
					dialog.close(event);
					event.preventDefault();
				}
			});

			// handle window resize
			$(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
		}

		var $el = (this.oldInstances.pop() || $('<div></div>').addClass('ui-widget-overlay'))
			.appendTo(document.body)
			.css({
				width: this.width(),
				height: this.height()
			});

		if ($.fn.bgiframe) {
			$el.bgiframe();
		}

		this.instances.push($el);
		return $el;
	},

	destroy: function($el) {
		var indexOf = $.inArray($el, this.instances);
		if (indexOf != -1){
			this.oldInstances.push(this.instances.splice(indexOf, 1)[0]);
		}

		if (this.instances.length === 0) {
			$([document, window]).unbind('.dialog-overlay');
		}

		$el.remove();
		
		// adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
		var maxZ = 0;
		$.each(this.instances, function() {
			maxZ = Math.max(maxZ, this.css('z-index'));
		});
		this.maxZ = maxZ;
	},

	height: function() {
		var scrollHeight,
			offsetHeight;
		// handle IE 6
		if ($.browser.msie && $.browser.version < 7) {
			scrollHeight = Math.max(
				document.documentElement.scrollHeight,
				document.body.scrollHeight
			);
			offsetHeight = Math.max(
				document.documentElement.offsetHeight,
				document.body.offsetHeight
			);

			if (scrollHeight < offsetHeight) {
				return $(window).height() + 'px';
			} else {
				return scrollHeight + 'px';
			}
		// handle "good" browsers
		} else {
			return $(document).height() + 'px';
		}
	},

	width: function() {
		var scrollWidth,
			offsetWidth;
		// handle IE 6
		if ($.browser.msie && $.browser.version < 7) {
			scrollWidth = Math.max(
				document.documentElement.scrollWidth,
				document.body.scrollWidth
			);
			offsetWidth = Math.max(
				document.documentElement.offsetWidth,
				document.body.offsetWidth
			);

			if (scrollWidth < offsetWidth) {
				return $(window).width() + 'px';
			} else {
				return scrollWidth + 'px';
			}
		// handle "good" browsers
		} else {
			return $(document).width() + 'px';
		}
	},

	resize: function() {
		/* If the dialog is draggable and the user drags it past the
		 * right edge of the window, the document becomes wider so we
		 * need to stretch the overlay. If the user then drags the
		 * dialog back to the left, the document will become narrower,
		 * so we need to shrink the overlay to the appropriate size.
		 * This is handled by shrinking the overlay before setting it
		 * to the full document size.
		 */
		var $overlays = $([]);
		$.each($.ui.dialog.overlay.instances, function() {
			$overlays = $overlays.add(this);
		});

		$overlays.css({
			width: 0,
			height: 0
		}).css({
			width: $.ui.dialog.overlay.width(),
			height: $.ui.dialog.overlay.height()
		});
	}
});

$.extend($.ui.dialog.overlay.prototype, {
	destroy: function() {
		$.ui.dialog.overlay.destroy(this.$el);
	}
});

}(jQuery));
/*
 * jQuery UI Position 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Position
 */
(function( $, undefined ) {

$.ui = $.ui || {};

var horizontalPositions = /left|center|right/,
	verticalPositions = /top|center|bottom/,
	center = "center",
	_position = $.fn.position,
	_offset = $.fn.offset;

$.fn.position = function( options ) {
	if ( !options || !options.of ) {
		return _position.apply( this, arguments );
	}

	// make a copy, we don't want to modify arguments
	options = $.extend( {}, options );

	var target = $( options.of ),
		targetElem = target[0],
		collision = ( options.collision || "flip" ).split( " " ),
		offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
		targetWidth,
		targetHeight,
		basePosition;

	if ( targetElem.nodeType === 9 ) {
		targetWidth = target.width();
		targetHeight = target.height();
		basePosition = { top: 0, left: 0 };
	// TODO: use $.isWindow() in 1.9
	} else if ( targetElem.setTimeout ) {
		targetWidth = target.width();
		targetHeight = target.height();
		basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
	} else if ( targetElem.preventDefault ) {
		// force left top to allow flipping
		options.at = "left top";
		targetWidth = targetHeight = 0;
		basePosition = { top: options.of.pageY, left: options.of.pageX };
	} else {
		targetWidth = target.outerWidth();
		targetHeight = target.outerHeight();
		basePosition = target.offset();
	}

	// force my and at to have valid horizontal and veritcal positions
	// if a value is missing or invalid, it will be converted to center 
	$.each( [ "my", "at" ], function() {
		var pos = ( options[this] || "" ).split( " " );
		if ( pos.length === 1) {
			pos = horizontalPositions.test( pos[0] ) ?
				pos.concat( [center] ) :
				verticalPositions.test( pos[0] ) ?
					[ center ].concat( pos ) :
					[ center, center ];
		}
		pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
		pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
		options[ this ] = pos;
	});

	// normalize collision option
	if ( collision.length === 1 ) {
		collision[ 1 ] = collision[ 0 ];
	}

	// normalize offset option
	offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
	if ( offset.length === 1 ) {
		offset[ 1 ] = offset[ 0 ];
	}
	offset[ 1 ] = parseInt( offset[1], 10 ) || 0;

	if ( options.at[0] === "right" ) {
		basePosition.left += targetWidth;
	} else if ( options.at[0] === center ) {
		basePosition.left += targetWidth / 2;
	}

	if ( options.at[1] === "bottom" ) {
		basePosition.top += targetHeight;
	} else if ( options.at[1] === center ) {
		basePosition.top += targetHeight / 2;
	}

	basePosition.left += offset[ 0 ];
	basePosition.top += offset[ 1 ];

	return this.each(function() {
		var elem = $( this ),
			elemWidth = elem.outerWidth(),
			elemHeight = elem.outerHeight(),
			marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
			marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
			collisionWidth = elemWidth + marginLeft +
				( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ),
			collisionHeight = elemHeight + marginTop +
				( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
			position = $.extend( {}, basePosition ),
			collisionPosition;

		if ( options.my[0] === "right" ) {
			position.left -= elemWidth;
		} else if ( options.my[0] === center ) {
			position.left -= elemWidth / 2;
		}

		if ( options.my[1] === "bottom" ) {
			position.top -= elemHeight;
		} else if ( options.my[1] === center ) {
			position.top -= elemHeight / 2;
		}

		// prevent fractions (see #5280)
		position.left = Math.round( position.left );
		position.top = Math.round( position.top );

		collisionPosition = {
			left: position.left - marginLeft,
			top: position.top - marginTop
		};

		$.each( [ "left", "top" ], function( i, dir ) {
			if ( $.ui.position[ collision[i] ] ) {
				$.ui.position[ collision[i] ][ dir ]( position, {
					targetWidth: targetWidth,
					targetHeight: targetHeight,
					elemWidth: elemWidth,
					elemHeight: elemHeight,
					collisionPosition: collisionPosition,
					collisionWidth: collisionWidth,
					collisionHeight: collisionHeight,
					offset: offset,
					my: options.my,
					at: options.at
				});
			}
		});

		if ( $.fn.bgiframe ) {
			elem.bgiframe();
		}
		elem.offset( $.extend( position, { using: options.using } ) );
	});
};

$.ui.position = {
	fit: {
		left: function( position, data ) {
			var win = $( window ),
				over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
			position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );
		},
		top: function( position, data ) {
			var win = $( window ),
				over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
			position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );
		}
	},

	flip: {
		left: function( position, data ) {
			if ( data.at[0] === center ) {
				return;
			}
			var win = $( window ),
				over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),
				myOffset = data.my[ 0 ] === "left" ?
					-data.elemWidth :
					data.my[ 0 ] === "right" ?
						data.elemWidth :
						0,
				atOffset = data.at[ 0 ] === "left" ?
					data.targetWidth :
					-data.targetWidth,
				offset = -2 * data.offset[ 0 ];
			position.left += data.collisionPosition.left < 0 ?
				myOffset + atOffset + offset :
				over > 0 ?
					myOffset + atOffset + offset :
					0;
		},
		top: function( position, data ) {
			if ( data.at[1] === center ) {
				return;
			}
			var win = $( window ),
				over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),
				myOffset = data.my[ 1 ] === "top" ?
					-data.elemHeight :
					data.my[ 1 ] === "bottom" ?
						data.elemHeight :
						0,
				atOffset = data.at[ 1 ] === "top" ?
					data.targetHeight :
					-data.targetHeight,
				offset = -2 * data.offset[ 1 ];
			position.top += data.collisionPosition.top < 0 ?
				myOffset + atOffset + offset :
				over > 0 ?
					myOffset + atOffset + offset :
					0;
		}
	}
};

// offset setter from jQuery 1.4
if ( !$.offset.setOffset ) {
	$.offset.setOffset = function( elem, options ) {
		// set position first, in-case top/left are set even on static elem
		if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
			elem.style.position = "relative";
		}
		var curElem   = $( elem ),
			curOffset = curElem.offset(),
			curTop    = parseInt( $.curCSS( elem, "top",  true ), 10 ) || 0,
			curLeft   = parseInt( $.curCSS( elem, "left", true ), 10)  || 0,
			props     = {
				top:  (options.top  - curOffset.top)  + curTop,
				left: (options.left - curOffset.left) + curLeft
			};
		
		if ( 'using' in options ) {
			options.using.call( elem, props );
		} else {
			curElem.css( props );
		}
	};

	$.fn.offset = function( options ) {
		var elem = this[ 0 ];
		if ( !elem || !elem.ownerDocument ) { return null; }
		if ( options ) { 
			return this.each(function() {
				$.offset.setOffset( this, options );
			});
		}
		return _offset.call( this );
	};
}

}( jQuery ));
/*
 * jQuery UI Progressbar 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Progressbar
 *
 * Depends:
 *   jquery.ui.core.js
 *   jquery.ui.widget.js
 */
(function( $, undefined ) {

$.widget( "ui.progressbar", {
	options: {
		value: 0,
		max: 100
	},

	min: 0,

	_create: function() {
		this.element
			.addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
			.attr({
				role: "progressbar",
				"aria-valuemin": this.min,
				"aria-valuemax": this.options.max,
				"aria-valuenow": this._value()
			});

		this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
			.appendTo( this.element );

		this.oldValue = this._value();
		this._refreshValue();
	},

	destroy: function() {
		this.element
			.removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
			.removeAttr( "role" )
			.removeAttr( "aria-valuemin" )
			.removeAttr( "aria-valuemax" )
			.removeAttr( "aria-valuenow" );

		this.valueDiv.remove();

		$.Widget.prototype.destroy.apply( this, arguments );
	},

	value: function( newValue ) {
		if ( newValue === undefined ) {
			return this._value();
		}

		this._setOption( "value", newValue );
		return this;
	},

	_setOption: function( key, value ) {
		if ( key === "value" ) {
			this.options.value = value;
			this._refreshValue();
			if ( this._value() === this.options.max ) {
				this._trigger( "complete" );
			}
		}

		$.Widget.prototype._setOption.apply( this, arguments );
	},

	_value: function() {
		var val = this.options.value;
		// normalize invalid value
		if ( typeof val !== "number" ) {
			val = 0;
		}
		return Math.min( this.options.max, Math.max( this.min, val ) );
	},

	_percentage: function() {
		return 100 * this._value() / this.options.max;
	},

	_refreshValue: function() {
		var value = this.value();
		var percentage = this._percentage();

		if ( this.oldValue !== value ) {
			this.oldValue = value;
			this._trigger( "change" );
		}

		this.valueDiv
			.toggle( value > this.min )
			.toggleClass( "ui-corner-right", value === this.options.max )
			.width( percentage.toFixed(0) + "%" );
		this.element.attr( "aria-valuenow", value );
	}
});

$.extend( $.ui.progressbar, {
	version: "1.8.12"
});

})( jQuery );
/*
 * jQuery UI Slider 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Slider
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.mouse.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

// number of pages in a slider
// (how many times can you page up/down to go through the whole range)
var numPages = 5;

$.widget( "ui.slider", $.ui.mouse, {

	widgetEventPrefix: "slide",

	options: {
		animate: false,
		distance: 0,
		max: 100,
		min: 0,
		orientation: "horizontal",
		range: false,
		step: 1,
		value: 0,
		values: null
	},

	_create: function() {
		var self = this,
			o = this.options;

		this._keySliding = false;
		this._mouseSliding = false;
		this._animateOff = true;
		this._handleIndex = null;
		this._detectOrientation();
		this._mouseInit();

		this.element
			.addClass( "ui-slider" +
				" ui-slider-" + this.orientation +
				" ui-widget" +
				" ui-widget-content" +
				" ui-corner-all" );
		
		if ( o.disabled ) {
			this.element.addClass( "ui-slider-disabled ui-disabled" );
		}

		this.range = $([]);

		if ( o.range ) {
			if ( o.range === true ) {
				this.range = $( "<div></div>" );
				if ( !o.values ) {
					o.values = [ this._valueMin(), this._valueMin() ];
				}
				if ( o.values.length && o.values.length !== 2 ) {
					o.values = [ o.values[0], o.values[0] ];
				}
			} else {
				this.range = $( "<div></div>" );
			}

			this.range
				.appendTo( this.element )
				.addClass( "ui-slider-range" );

			if ( o.range === "min" || o.range === "max" ) {
				this.range.addClass( "ui-slider-range-" + o.range );
			}

			// note: this isn't the most fittingly semantic framework class for this element,
			// but worked best visually with a variety of themes
			this.range.addClass( "ui-widget-header" );
		}

		if ( $( ".ui-slider-handle", this.element ).length === 0 ) {
			$( "<a href='#'></a>" )
				.appendTo( this.element )
				.addClass( "ui-slider-handle" );
		}

		if ( o.values && o.values.length ) {
			while ( $(".ui-slider-handle", this.element).length < o.values.length ) {
				$( "<a href='#'></a>" )
					.appendTo( this.element )
					.addClass( "ui-slider-handle" );
			}
		}

		this.handles = $( ".ui-slider-handle", this.element )
			.addClass( "ui-state-default" +
				" ui-corner-all" );

		this.handle = this.handles.eq( 0 );

		this.handles.add( this.range ).filter( "a" )
			.click(function( event ) {
				event.preventDefault();
			})
			.hover(function() {
				if ( !o.disabled ) {
					$( this ).addClass( "ui-state-hover" );
				}
			}, function() {
				$( this ).removeClass( "ui-state-hover" );
			})
			.focus(function() {
				if ( !o.disabled ) {
					$( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
					$( this ).addClass( "ui-state-focus" );
				} else {
					$( this ).blur();
				}
			})
			.blur(function() {
				$( this ).removeClass( "ui-state-focus" );
			});

		this.handles.each(function( i ) {
			$( this ).data( "index.ui-slider-handle", i );
		});

		this.handles
			.keydown(function( event ) {
				var ret = true,
					index = $( this ).data( "index.ui-slider-handle" ),
					allowed,
					curVal,
					newVal,
					step;
	
				if ( self.options.disabled ) {
					return;
				}
	
				switch ( event.keyCode ) {
					case $.ui.keyCode.HOME:
					case $.ui.keyCode.END:
					case $.ui.keyCode.PAGE_UP:
					case $.ui.keyCode.PAGE_DOWN:
					case $.ui.keyCode.UP:
					case $.ui.keyCode.RIGHT:
					case $.ui.keyCode.DOWN:
					case $.ui.keyCode.LEFT:
						ret = false;
						if ( !self._keySliding ) {
							self._keySliding = true;
							$( this ).addClass( "ui-state-active" );
							allowed = self._start( event, index );
							if ( allowed === false ) {
								return;
							}
						}
						break;
				}
	
				step = self.options.step;
				if ( self.options.values && self.options.values.length ) {
					curVal = newVal = self.values( index );
				} else {
					curVal = newVal = self.value();
				}
	
				switch ( event.keyCode ) {
					case $.ui.keyCode.HOME:
						newVal = self._valueMin();
						break;
					case $.ui.keyCode.END:
						newVal = self._valueMax();
						break;
					case $.ui.keyCode.PAGE_UP:
						newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
						break;
					case $.ui.keyCode.PAGE_DOWN:
						newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
						break;
					case $.ui.keyCode.UP:
					case $.ui.keyCode.RIGHT:
						if ( curVal === self._valueMax() ) {
							return;
						}
						newVal = self._trimAlignValue( curVal + step );
						break;
					case $.ui.keyCode.DOWN:
					case $.ui.keyCode.LEFT:
						if ( curVal === self._valueMin() ) {
							return;
						}
						newVal = self._trimAlignValue( curVal - step );
						break;
				}
	
				self._slide( event, index, newVal );
	
				return ret;
	
			})
			.keyup(function( event ) {
				var index = $( this ).data( "index.ui-slider-handle" );
	
				if ( self._keySliding ) {
					self._keySliding = false;
					self._stop( event, index );
					self._change( event, index );
					$( this ).removeClass( "ui-state-active" );
				}
	
			});

		this._refreshValue();

		this._animateOff = false;
	},

	destroy: function() {
		this.handles.remove();
		this.range.remove();

		this.element
			.removeClass( "ui-slider" +
				" ui-slider-horizontal" +
				" ui-slider-vertical" +
				" ui-slider-disabled" +
				" ui-widget" +
				" ui-widget-content" +
				" ui-corner-all" )
			.removeData( "slider" )
			.unbind( ".slider" );

		this._mouseDestroy();

		return this;
	},

	_mouseCapture: function( event ) {
		var o = this.options,
			position,
			normValue,
			distance,
			closestHandle,
			self,
			index,
			allowed,
			offset,
			mouseOverHandle;

		if ( o.disabled ) {
			return false;
		}

		this.elementSize = {
			width: this.element.outerWidth(),
			height: this.element.outerHeight()
		};
		this.elementOffset = this.element.offset();

		position = { x: event.pageX, y: event.pageY };
		normValue = this._normValueFromMouse( position );
		distance = this._valueMax() - this._valueMin() + 1;
		self = this;
		this.handles.each(function( i ) {
			var thisDistance = Math.abs( normValue - self.values(i) );
			if ( distance > thisDistance ) {
				distance = thisDistance;
				closestHandle = $( this );
				index = i;
			}
		});

		// workaround for bug #3736 (if both handles of a range are at 0,
		// the first is always used as the one with least distance,
		// and moving it is obviously prevented by preventing negative ranges)
		if( o.range === true && this.values(1) === o.min ) {
			index += 1;
			closestHandle = $( this.handles[index] );
		}

		allowed = this._start( event, index );
		if ( allowed === false ) {
			return false;
		}
		this._mouseSliding = true;

		self._handleIndex = index;

		closestHandle
			.addClass( "ui-state-active" )
			.focus();
		
		offset = closestHandle.offset();
		mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
			top: event.pageY - offset.top -
				( closestHandle.height() / 2 ) -
				( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
				( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
				( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
		};

		if ( !this.handles.hasClass( "ui-state-hover" ) ) {
			this._slide( event, index, normValue );
		}
		this._animateOff = true;
		return true;
	},

	_mouseStart: function( event ) {
		return true;
	},

	_mouseDrag: function( event ) {
		var position = { x: event.pageX, y: event.pageY },
			normValue = this._normValueFromMouse( position );
		
		this._slide( event, this._handleIndex, normValue );

		return false;
	},

	_mouseStop: function( event ) {
		this.handles.removeClass( "ui-state-active" );
		this._mouseSliding = false;

		this._stop( event, this._handleIndex );
		this._change( event, this._handleIndex );

		this._handleIndex = null;
		this._clickOffset = null;
		this._animateOff = false;

		return false;
	},
	
	_detectOrientation: function() {
		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
	},

	_normValueFromMouse: function( position ) {
		var pixelTotal,
			pixelMouse,
			percentMouse,
			valueTotal,
			valueMouse;

		if ( this.orientation === "horizontal" ) {
			pixelTotal = this.elementSize.width;
			pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
		} else {
			pixelTotal = this.elementSize.height;
			pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
		}

		percentMouse = ( pixelMouse / pixelTotal );
		if ( percentMouse > 1 ) {
			percentMouse = 1;
		}
		if ( percentMouse < 0 ) {
			percentMouse = 0;
		}
		if ( this.orientation === "vertical" ) {
			percentMouse = 1 - percentMouse;
		}

		valueTotal = this._valueMax() - this._valueMin();
		valueMouse = this._valueMin() + percentMouse * valueTotal;

		return this._trimAlignValue( valueMouse );
	},

	_start: function( event, index ) {
		var uiHash = {
			handle: this.handles[ index ],
			value: this.value()
		};
		if ( this.options.values && this.options.values.length ) {
			uiHash.value = this.values( index );
			uiHash.values = this.values();
		}
		return this._trigger( "start", event, uiHash );
	},

	_slide: function( event, index, newVal ) {
		var otherVal,
			newValues,
			allowed;

		if ( this.options.values && this.options.values.length ) {
			otherVal = this.values( index ? 0 : 1 );

			if ( ( this.options.values.length === 2 && this.options.range === true ) && 
					( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
				) {
				newVal = otherVal;
			}

			if ( newVal !== this.values( index ) ) {
				newValues = this.values();
				newValues[ index ] = newVal;
				// A slide can be canceled by returning false from the slide callback
				allowed = this._trigger( "slide", event, {
					handle: this.handles[ index ],
					value: newVal,
					values: newValues
				} );
				otherVal = this.values( index ? 0 : 1 );
				if ( allowed !== false ) {
					this.values( index, newVal, true );
				}
			}
		} else {
			if ( newVal !== this.value() ) {
				// A slide can be canceled by returning false from the slide callback
				allowed = this._trigger( "slide", event, {
					handle: this.handles[ index ],
					value: newVal
				} );
				if ( allowed !== false ) {
					this.value( newVal );
				}
			}
		}
	},

	_stop: function( event, index ) {
		var uiHash = {
			handle: this.handles[ index ],
			value: this.value()
		};
		if ( this.options.values && this.options.values.length ) {
			uiHash.value = this.values( index );
			uiHash.values = this.values();
		}

		this._trigger( "stop", event, uiHash );
	},

	_change: function( event, index ) {
		if ( !this._keySliding && !this._mouseSliding ) {
			var uiHash = {
				handle: this.handles[ index ],
				value: this.value()
			};
			if ( this.options.values && this.options.values.length ) {
				uiHash.value = this.values( index );
				uiHash.values = this.values();
			}

			this._trigger( "change", event, uiHash );
		}
	},

	value: function( newValue ) {
		if ( arguments.length ) {
			this.options.value = this._trimAlignValue( newValue );
			this._refreshValue();
			this._change( null, 0 );
			return;
		}

		return this._value();
	},

	values: function( index, newValue ) {
		var vals,
			newValues,
			i;

		if ( arguments.length > 1 ) {
			this.options.values[ index ] = this._trimAlignValue( newValue );
			this._refreshValue();
			this._change( null, index );
			return;
		}

		if ( arguments.length ) {
			if ( $.isArray( arguments[ 0 ] ) ) {
				vals = this.options.values;
				newValues = arguments[ 0 ];
				for ( i = 0; i < vals.length; i += 1 ) {
					vals[ i ] = this._trimAlignValue( newValues[ i ] );
					this._change( null, i );
				}
				this._refreshValue();
			} else {
				if ( this.options.values && this.options.values.length ) {
					return this._values( index );
				} else {
					return this.value();
				}
			}
		} else {
			return this._values();
		}
	},

	_setOption: function( key, value ) {
		var i,
			valsLength = 0;

		if ( $.isArray( this.options.values ) ) {
			valsLength = this.options.values.length;
		}

		$.Widget.prototype._setOption.apply( this, arguments );

		switch ( key ) {
			case "disabled":
				if ( value ) {
					this.handles.filter( ".ui-state-focus" ).blur();
					this.handles.removeClass( "ui-state-hover" );
					this.handles.attr( "disabled", "disabled" );
					this.element.addClass( "ui-disabled" );
				} else {
					this.handles.removeAttr( "disabled" );
					this.element.removeClass( "ui-disabled" );
				}
				break;
			case "orientation":
				this._detectOrientation();
				this.element
					.removeClass( "ui-slider-horizontal ui-slider-vertical" )
					.addClass( "ui-slider-" + this.orientation );
				this._refreshValue();
				break;
			case "value":
				this._animateOff = true;
				this._refreshValue();
				this._change( null, 0 );
				this._animateOff = false;
				break;
			case "values":
				this._animateOff = true;
				this._refreshValue();
				for ( i = 0; i < valsLength; i += 1 ) {
					this._change( null, i );
				}
				this._animateOff = false;
				break;
		}
	},

	//internal value getter
	// _value() returns value trimmed by min and max, aligned by step
	_value: function() {
		var val = this.options.value;
		val = this._trimAlignValue( val );

		return val;
	},

	//internal values getter
	// _values() returns array of values trimmed by min and max, aligned by step
	// _values( index ) returns single value trimmed by min and max, aligned by step
	_values: function( index ) {
		var val,
			vals,
			i;

		if ( arguments.length ) {
			val = this.options.values[ index ];
			val = this._trimAlignValue( val );

			return val;
		} else {
			// .slice() creates a copy of the array
			// this copy gets trimmed by min and max and then returned
			vals = this.options.values.slice();
			for ( i = 0; i < vals.length; i+= 1) {
				vals[ i ] = this._trimAlignValue( vals[ i ] );
			}

			return vals;
		}
	},
	
	// returns the step-aligned value that val is closest to, between (inclusive) min and max
	_trimAlignValue: function( val ) {
		if ( val <= this._valueMin() ) {
			return this._valueMin();
		}
		if ( val >= this._valueMax() ) {
			return this._valueMax();
		}
		var step = ( this.options.step > 0 ) ? this.options.step : 1,
			valModStep = (val - this._valueMin()) % step;
			alignValue = val - valModStep;

		if ( Math.abs(valModStep) * 2 >= step ) {
			alignValue += ( valModStep > 0 ) ? step : ( -step );
		}

		// Since JavaScript has problems with large floats, round
		// the final value to 5 digits after the decimal point (see #4124)
		return parseFloat( alignValue.toFixed(5) );
	},

	_valueMin: function() {
		return this.options.min;
	},

	_valueMax: function() {
		return this.options.max;
	},
	
	_refreshValue: function() {
		var oRange = this.options.range,
			o = this.options,
			self = this,
			animate = ( !this._animateOff ) ? o.animate : false,
			valPercent,
			_set = {},
			lastValPercent,
			value,
			valueMin,
			valueMax;

		if ( this.options.values && this.options.values.length ) {
			this.handles.each(function( i, j ) {
				valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;
				_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
				if ( self.options.range === true ) {
					if ( self.orientation === "horizontal" ) {
						if ( i === 0 ) {
							self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
						}
						if ( i === 1 ) {
							self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
						}
					} else {
						if ( i === 0 ) {
							self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
						}
						if ( i === 1 ) {
							self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
						}
					}
				}
				lastValPercent = valPercent;
			});
		} else {
			value = this.value();
			valueMin = this._valueMin();
			valueMax = this._valueMax();
			valPercent = ( valueMax !== valueMin ) ?
					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
					0;
			_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );

			if ( oRange === "min" && this.orientation === "horizontal" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
			}
			if ( oRange === "max" && this.orientation === "horizontal" ) {
				this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
			}
			if ( oRange === "min" && this.orientation === "vertical" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
			}
			if ( oRange === "max" && this.orientation === "vertical" ) {
				this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
			}
		}
	}

});

$.extend( $.ui.slider, {
	version: "1.8.12"
});

}(jQuery));
/*
 * jQuery UI Tabs 1.8.12
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Tabs
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

var tabId = 0,
	listId = 0;

function getNextTabId() {
	return ++tabId;
}

function getNextListId() {
	return ++listId;
}

$.widget( "ui.tabs", {
	options: {
		add: null,
		ajaxOptions: null,
		cache: false,
		cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
		collapsible: false,
		disable: null,
		disabled: [],
		enable: null,
		event: "click",
		fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
		idPrefix: "ui-tabs-",
		load: null,
		panelTemplate: "<div></div>",
		remove: null,
		select: null,
		show: null,
		spinner: "<em>Loading&#8230;</em>",
		tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
	},

	_create: function() {
		this._tabify( true );
	},

	_setOption: function( key, value ) {
		if ( key == "selected" ) {
			if (this.options.collapsible && value == this.options.selected ) {
				return;
			}
			this.select( value );
		} else {
			this.options[ key ] = value;
			this._tabify();
		}
	},

	_tabId: function( a ) {
		return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) ||
			this.options.idPrefix + getNextTabId();
	},

	_sanitizeSelector: function( hash ) {
		// we need this because an id may contain a ":"
		return hash.replace( /:/g, "\\:" );
	},

	_cookie: function() {
		var cookie = this.cookie ||
			( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() );
		return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) );
	},

	_ui: function( tab, panel ) {
		return {
			tab: tab,
			panel: panel,
			index: this.anchors.index( tab )
		};
	},

	_cleanup: function() {
		// restore all former loading tabs labels
		this.lis.filter( ".ui-state-processing" )
			.removeClass( "ui-state-processing" )
			.find( "span:data(label.tabs)" )
				.each(function() {
					var el = $( this );
					el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" );
				});
	},

	_tabify: function( init ) {
		var self = this,
			o = this.options,
			fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash

		this.list = this.element.find( "ol,ul" ).eq( 0 );
		this.lis = $( " > li:has(a[href])", this.list );
		this.anchors = this.lis.map(function() {
			return $( "a", this )[ 0 ];
		});
		this.panels = $( [] );

		this.anchors.each(function( i, a ) {
			var href = $( a ).attr( "href" );
			// For dynamically created HTML that contains a hash as href IE < 8 expands
			// such href to the full page url with hash and then misinterprets tab as ajax.
			// Same consideration applies for an added tab with a fragment identifier
			// since a[href=#fragment-identifier] does unexpectedly not match.
			// Thus normalize href attribute...
			var hrefBase = href.split( "#" )[ 0 ],
				baseEl;
			if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] ||
					( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) {
				href = a.hash;
				a.href = href;
			}

			// inline tab
			if ( fragmentId.test( href ) ) {
				self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) );
			// remote tab
			// prevent loading the page itself if href is just "#"
			} else if ( href && href !== "#" ) {
				// required for restore on destroy
				$.data( a, "href.tabs", href );

				// TODO until #3808 is fixed strip fragment identifier from url
				// (IE fails to load from such url)
				$.data( a, "load.tabs", href.replace( /#.*$/, "" ) );

				var id = self._tabId( a );
				a.href = "#" + id;
				var $panel = self.element.find( "#" + id );
				if ( !$panel.length ) {
					$panel = $( o.panelTemplate )
						.attr( "id", id )
						.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
						.insertAfter( self.panels[ i - 1 ] || self.list );
					$panel.data( "destroy.tabs", true );
				}
				self.panels = self.panels.add( $panel );
			// invalid tab href
			} else {
				o.disabled.push( i );
			}
		});

		// initialization from scratch
		if ( init ) {
			// attach necessary classes for styling
			this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" );
			this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
			this.lis.addClass( "ui-state-default ui-corner-top" );
			this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" );

			// Selected tab
			// use "selected" option or try to retrieve:
			// 1. from fragment identifier in url
			// 2. from cookie
			// 3. from selected class attribute on <li>
			if ( o.selected === undefined ) {
				if ( location.hash ) {
					this.anchors.each(function( i, a ) {
						if ( a.hash == location.hash ) {
							o.selected = i;
							return false;
						}
					});
				}
				if ( typeof o.selected !== "number" && o.cookie ) {
					o.selected = parseInt( self._cookie(), 10 );
				}
				if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) {
					o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
				}
				o.selected = o.selected || ( this.lis.length ? 0 : -1 );
			} else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release
				o.selected = -1;
			}

			// sanity check - default to first tab...
			o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 )
				? o.selected
				: 0;

			// Take disabling tabs via class attribute from HTML
			// into account and update option properly.
			// A selected tab cannot become disabled.
			o.disabled = $.unique( o.disabled.concat(
				$.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) {
					return self.lis.index( n );
				})
			) ).sort();

			if ( $.inArray( o.selected, o.disabled ) != -1 ) {
				o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 );
			}

			// highlight selected tab
			this.panels.addClass( "ui-tabs-hide" );
			this.lis.removeClass( "ui-tabs-selected ui-state-active" );
			// check for length avoids error when initializing empty list
			if ( o.selected >= 0 && this.anchors.length ) {
				self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" );
				this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" );

				// seems to be expected behavior that the show callback is fired
				self.element.queue( "tabs", function() {
					self._trigger( "show", null,
						self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) );
				});

				this.load( o.selected );
			}

			// clean up to avoid memory leaks in certain versions of IE 6
			// TODO: namespace this event
			$( window ).bind( "unload", function() {
				self.lis.add( self.anchors ).unbind( ".tabs" );
				self.lis = self.anchors = self.panels = null;
			});
		// update selected after add/remove
		} else {
			o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
		}

		// update collapsible
		// TODO: use .toggleClass()
		this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" );

		// set or update cookie after init and add/remove respectively
		if ( o.cookie ) {
			this._cookie( o.selected, o.cookie );
		}

		// disable tabs
		for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
			$( li )[ $.inArray( i, o.disabled ) != -1 &&
				// TODO: use .toggleClass()
				!$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" );
		}

		// reset cache if switching from cached to not cached
		if ( o.cache === false ) {
			this.anchors.removeData( "cache.tabs" );
		}

		// remove all handlers before, tabify may run on existing tabs after add or option change
		this.lis.add( this.anchors ).unbind( ".tabs" );

		if ( o.event !== "mouseover" ) {
			var addState = function( state, el ) {
				if ( el.is( ":not(.ui-state-disabled)" ) ) {
					el.addClass( "ui-state-" + state );
				}
			};
			var removeState = function( state, el ) {
				el.removeClass( "ui-state-" + state );
			};
			this.lis.bind( "mouseover.tabs" , function() {
				addState( "hover", $( this ) );
			});
			this.lis.bind( "mouseout.tabs", function() {
				removeState( "hover", $( this ) );
			});
			this.anchors.bind( "focus.tabs", function() {
				addState( "focus", $( this ).closest( "li" ) );
			});
			this.anchors.bind( "blur.tabs", function() {
				removeState( "focus", $( this ).closest( "li" ) );
			});
		}

		// set up animations
		var hideFx, showFx;
		if ( o.fx ) {
			if ( $.isArray( o.fx ) ) {
				hideFx = o.fx[ 0 ];
				showFx = o.fx[ 1 ];
			} else {
				hideFx = showFx = o.fx;
			}
		}

		// Reset certain styles left over from animation
		// and prevent IE's ClearType bug...
		function resetStyle( $el, fx ) {
			$el.css( "display", "" );
			if ( !$.support.opacity && fx.opacity ) {
				$el[ 0 ].style.removeAttribute( "filter" );
			}
		}

		// Show a tab...
		var showTab = showFx
			? function( clicked, $show ) {
				$( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
				$show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way
					.animate( showFx, showFx.duration || "normal", function() {
						resetStyle( $show, showFx );
						self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
					});
			}
			: function( clicked, $show ) {
				$( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
				$show.removeClass( "ui-tabs-hide" );
				self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
			};

		// Hide a tab, $show is optional...
		var hideTab = hideFx
			? function( clicked, $hide ) {
				$hide.animate( hideFx, hideFx.duration || "normal", function() {
					self.lis.removeClass( "ui-tabs-selected ui-state-active" );
					$hide.addClass( "ui-tabs-hide" );
					resetStyle( $hide, hideFx );
					self.element.dequeue( "tabs" );
				});
			}
			: function( clicked, $hide, $show ) {
				self.lis.removeClass( "ui-tabs-selected ui-state-active" );
				$hide.addClass( "ui-tabs-hide" );
				self.element.dequeue( "tabs" );
			};

		// attach tab event handler, unbind to avoid duplicates from former tabifying...
		this.anchors.bind( o.event + ".tabs", function() {
			var el = this,
				$li = $(el).closest( "li" ),
				$hide = self.panels.filter( ":not(.ui-tabs-hide)" ),
				$show = self.element.find( self._sanitizeSelector( el.hash ) );

			// If tab is already selected and not collapsible or tab disabled or
			// or is already loading or click callback returns false stop here.
			// Check if click handler returns false last so that it is not executed
			// for a disabled or loading tab!
			if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) ||
				$li.hasClass( "ui-state-disabled" ) ||
				$li.hasClass( "ui-state-processing" ) ||
				self.panels.filter( ":animated" ).length ||
				self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) {
				this.blur();
				return false;
			}

			o.selected = self.anchors.index( this );

			self.abort();

			// if tab may be closed
			if ( o.collapsible ) {
				if ( $li.hasClass( "ui-tabs-selected" ) ) {
					o.selected = -1;

					if ( o.cookie ) {
						self._cookie( o.selected, o.cookie );
					}

					self.element.queue( "tabs", function() {
						hideTab( el, $hide );
					}).dequeue( "tabs" );

					this.blur();
					return false;
				} else if ( !$hide.length ) {
					if ( o.cookie ) {
						self._cookie( o.selected, o.cookie );
					}

					self.element.queue( "tabs", function() {
						showTab( el, $show );
					});

					// TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
					self.load( self.anchors.index( this ) );

					this.blur();
					return false;
				}
			}

			if ( o.cookie ) {
				self._cookie( o.selected, o.cookie );
			}

			// show new tab
			if ( $show.length ) {
				if ( $hide.length ) {
					self.element.queue( "tabs", function() {
						hideTab( el, $hide );
					});
				}
				self.element.queue( "tabs", function() {
					showTab( el, $show );
				});

				self.load( self.anchors.index( this ) );
			} else {
				throw "jQuery UI Tabs: Mismatching fragment identifier.";
			}

			// Prevent IE from keeping other link focussed when using the back button
			// and remove dotted border from clicked link. This is controlled via CSS
			// in modern browsers; blur() removes focus from address bar in Firefox
			// which can become a usability and annoying problem with tabs('rotate').
			if ( $.browser.msie ) {
				this.blur();
			}
		});

		// disable click in any case
		this.anchors.bind( "click.tabs", function(){
			return false;
		});
	},

    _getIndex: function( index ) {
		// meta-function to give users option to provide a href string instead of a numerical index.
		// also sanitizes numerical indexes to valid values.
		if ( typeof index == "string" ) {
			index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) );
		}

		return index;
	},

	destroy: function() {
		var o = this.options;

		this.abort();

		this.element
			.unbind( ".tabs" )
			.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" )
			.removeData( "tabs" );

		this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );

		this.anchors.each(function() {
			var href = $.data( this, "href.tabs" );
			if ( href ) {
				this.href = href;
			}
			var $this = $( this ).unbind( ".tabs" );
			$.each( [ "href", "load", "cache" ], function( i, prefix ) {
				$this.removeData( prefix + ".tabs" );
			});
		});

		this.lis.unbind( ".tabs" ).add( this.panels ).each(function() {
			if ( $.data( this, "destroy.tabs" ) ) {
				$( this ).remove();
			} else {
				$( this ).removeClass([
					"ui-state-default",
					"ui-corner-top",
					"ui-tabs-selected",
					"ui-state-active",
					"ui-state-hover",
					"ui-state-focus",
					"ui-state-disabled",
					"ui-tabs-panel",
					"ui-widget-content",
					"ui-corner-bottom",
					"ui-tabs-hide"
				].join( " " ) );
			}
		});

		if ( o.cookie ) {
			this._cookie( null, o.cookie );
		}

		return this;
	},

	add: function( url, label, index ) {
		if ( index === undefined ) {
			index = this.anchors.length;
		}

		var self = this,
			o = this.options,
			$li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ),
			id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] );

		$li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );

		// try to find an existing element before creating a new one
		var $panel = self.element.find( "#" + id );
		if ( !$panel.length ) {
			$panel = $( o.panelTemplate )
				.attr( "id", id )
				.data( "destroy.tabs", true );
		}
		$panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" );

		if ( index >= this.lis.length ) {
			$li.appendTo( this.list );
			$panel.appendTo( this.list[ 0 ].parentNode );
		} else {
			$li.insertBefore( this.lis[ index ] );
			$panel.insertBefore( this.panels[ index ] );
		}

		o.disabled = $.map( o.disabled, function( n, i ) {
			return n >= index ? ++n : n;
		});

		this._tabify();

		if ( this.anchors.length == 1 ) {
			o.selected = 0;
			$li.addClass( "ui-tabs-selected ui-state-active" );
			$panel.removeClass( "ui-tabs-hide" );
			this.element.queue( "tabs", function() {
				self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) );
			});

			this.load( 0 );
		}

		this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
		return this;
	},

	remove: function( index ) {
		index = this._getIndex( index );
		var o = this.options,
			$li = this.lis.eq( index ).remove(),
			$panel = this.panels.eq( index ).remove();

		// If selected tab was removed focus tab to the right or
		// in case the last tab was removed the tab to the left.
		if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
			this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
		}

		o.disabled = $.map(
			$.grep( o.disabled, function(n, i) {
				return n != index;
			}),
			function( n, i ) {
				return n >= index ? --n : n;
			});

		this._tabify();

		this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
		return this;
	},

	enable: function( index ) {
		index = this._getIndex( index );
		var o = this.options;
		if ( $.inArray( index, o.disabled ) == -1 ) {
			return;
		}

		this.lis.eq( index ).removeClass( "ui-state-disabled" );
		o.disabled = $.grep( o.disabled, function( n, i ) {
			return n != index;
		});

		this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
		return this;
	},

	disable: function( index ) {
		index = this._getIndex( index );
		var self = this, o = this.options;
		// cannot disable already selected tab
		if ( index != o.selected ) {
			this.lis.eq( index ).addClass( "ui-state-disabled" );

			o.disabled.push( index );
			o.disabled.sort();

			this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
		}

		return this;
	},

	select: function( index ) {
		index = this._getIndex( index );
		if ( index == -1 ) {
			if ( this.options.collapsible && this.options.selected != -1 ) {
				index = this.options.selected;
			} else {
				return this;
			}
		}
		this.anchors.eq( index ).trigger( this.options.event + ".tabs" );
		return this;
	},

	load: function( index ) {
		index = this._getIndex( index );
		var self = this,
			o = this.options,
			a = this.anchors.eq( index )[ 0 ],
			url = $.data( a, "load.tabs" );

		this.abort();

		// not remote or from cache
		if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) {
			this.element.dequeue( "tabs" );
			return;
		}

		// load remote from here on
		this.lis.eq( index ).addClass( "ui-state-processing" );

		if ( o.spinner ) {
			var span = $( "span", a );
			span.data( "label.tabs", span.html() ).html( o.spinner );
		}

		this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, {
			url: url,
			success: function( r, s ) {
				self.element.find( self._sanitizeSelector( a.hash ) ).html( r );

				// take care of tab labels
				self._cleanup();

				if ( o.cache ) {
					$.data( a, "cache.tabs", true );
				}

				self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
				try {
					o.ajaxOptions.success( r, s );
				}
				catch ( e ) {}
			},
			error: function( xhr, s, e ) {
				// take care of tab labels
				self._cleanup();

				self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
				try {
					// Passing index avoid a race condition when this method is
					// called after the user has selected another tab.
					// Pass the anchor that initiated this request allows
					// loadError to manipulate the tab content panel via $(a.hash)
					o.ajaxOptions.error( xhr, s, index, a );
				}
				catch ( e ) {}
			}
		} ) );

		// last, so that load event is fired before show...
		self.element.dequeue( "tabs" );

		return this;
	},

	abort: function() {
		// stop possibly running animations
		this.element.queue( [] );
		this.panels.stop( false, true );

		// "tabs" queue must not contain more than two elements,
		// which are the callbacks for the latest clicked tab...
		this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) );

		// terminate pending requests from other tabs
		if ( this.xhr ) {
			this.xhr.abort();
			delete this.xhr;
		}

		// take care of tab labels
		this._cleanup();
		return this;
	},

	url: function( index, url ) {
		this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url );
		return this;
	},

	length: function() {
		return this.anchors.length;
	}
});

$.extend( $.ui.tabs, {
	version: "1.8.12"
});

/*
 * Tabs Extensions
 */

/*
 * Rotate
 */
$.extend( $.ui.tabs.prototype, {
	rotation: null,
	rotate: function( ms, continuing ) {
		var self = this,
			o = this.options;

		var rotate = self._rotate || ( self._rotate = function( e ) {
			clearTimeout( self.rotation );
			self.rotation = setTimeout(function() {
				var t = o.selected;
				self.select( ++t < self.anchors.length ? t : 0 );
			}, ms );
			
			if ( e ) {
				e.stopPropagation();
			}
		});

		var stop = self._unrotate || ( self._unrotate = !continuing
			? function(e) {
				if (e.clientX) { // in case of a true click
					self.rotate(null);
				}
			}
			: function( e ) {
				t = o.selected;
				rotate();
			});

		// start rotation
		if ( ms ) {
			this.element.bind( "tabsshow", rotate );
			this.anchors.bind( o.event + ".tabs", stop );
			rotate();
		// stop rotation
		} else {
			clearTimeout( self.rotation );
			this.element.unbind( "tabsshow", rotate );
			this.anchors.unbind( o.event + ".tabs", stop );
			delete this._rotate;
			delete this._unrotate;
		}

		return this;
	}
});

})( jQuery );
/*
 * jQuery Tooltip plugin 1.3
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/
 * http://docs.jquery.com/Plugins/Tooltip
 *
 * Copyright (c) 2006 - 2008 Jörn Zaefferer
 *
 * $Id: jquery.tooltip.js 5741 2008-06-21 15:22:16Z joern.zaefferer $
 * 
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */
 
;(function($) {
	
		// the tooltip element
	var helper = {},
		// the current tooltipped element
		current,
		// the title of the current element, used for restoring
		title,
		// timeout id for delayed tooltips
		tID,
		// IE 5.5 or 6
		IE = $.browser.msie && /MSIE\s(5\.5|6\.)/.test(navigator.userAgent),
		// flag for mouse tracking
		track = false;
	
	$.tooltip = {
		blocked: false,
		defaults: {
			delay: 200,
			fade: false,
			showURL: true,
			extraClass: "",
			top: 15,
			left: 15,
			id: "tooltip"
		},
		block: function() {
			$.tooltip.blocked = !$.tooltip.blocked;
		}
	};
	
	$.fn.extend({
		tooltip: function(settings) {
			settings = $.extend({}, $.tooltip.defaults, settings);
			createHelper(settings);
			return this.each(function() {
					$.data(this, "tooltip", settings);
					this.tOpacity = helper.parent.css("opacity");
					// copy tooltip into its own expando and remove the title
					this.tooltipText = this.title;
					$(this).removeAttr("title");
					// also remove alt attribute to prevent default tooltip in IE
					this.alt = "";
				})
				.mouseover(save)
				.mouseout(hide)
				.click(hide);
		},
		fixPNG: IE ? function() {
			return this.each(function () {
				var image = $(this).css('backgroundImage');
				if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) {
					image = RegExp.$1;
					$(this).css({
						'backgroundImage': 'none',
						'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
					}).each(function () {
						var position = $(this).css('position');
						if (position != 'absolute' && position != 'relative')
							$(this).css('position', 'relative');
					});
				}
			});
		} : function() { return this; },
		unfixPNG: IE ? function() {
			return this.each(function () {
				$(this).css({'filter': '', backgroundImage: ''});
			});
		} : function() { return this; },
		hideWhenEmpty: function() {
			return this.each(function() {
				$(this)[ $(this).html() ? "show" : "hide" ]();
			});
		},
		url: function() {
			return this.attr('href') || this.attr('src');
		}
	});
	
	function createHelper(settings) {
		// there can be only one tooltip helper
		if( helper.parent )
			return;
		// create the helper, h3 for title, div for url
		helper.parent = $('<div id="' + settings.id + '"><h3></h3><div class="body"></div><div class="url"></div></div>')
			// add to document
			.appendTo(document.body)
			// hide it at first
			.hide();
			
		// apply bgiframe if available
		if ( $.fn.bgiframe )
			helper.parent.bgiframe();
		
		// save references to title and url elements
		helper.title = $('h3', helper.parent);
		helper.body = $('div.body', helper.parent);
		helper.url = $('div.url', helper.parent);
	}
	
	function settings(element) {
		return $.data(element, "tooltip");
	}
	
	// main event handler to start showing tooltips
	function handle(event) {
		// show helper, either with timeout or on instant
		if( settings(this).delay )
			tID = setTimeout(show, settings(this).delay);
		else
			show();
		
		// if selected, update the helper position when the mouse moves
		track = !!settings(this).track;
		$(document.body).bind('mousemove', update);
			
		// update at least once
		update(event);
	}
	
	// save elements title before the tooltip is displayed
	function save() {
		// if this is the current source, or it has no title (occurs with click event), stop
		if ( $.tooltip.blocked || this == current || (!this.tooltipText && !settings(this).bodyHandler) )
			return;

		// save current
		current = this;
		title = this.tooltipText;
		
		if ( settings(this).bodyHandler ) {
			helper.title.hide();
			var bodyContent = settings(this).bodyHandler.call(this);
			if (bodyContent.nodeType || bodyContent.jquery) {
				helper.body.empty().append(bodyContent)
			} else {
				helper.body.html( bodyContent );
			}
			helper.body.show();
		} else if ( settings(this).showBody ) {
			var parts = title.split(settings(this).showBody);
			helper.title.html(parts.shift()).show();
			helper.body.empty();
			for(var i = 0, part; (part = parts[i]); i++) {
				if(i > 0)
					helper.body.append("<br/>");
				helper.body.append(part);
			}
			helper.body.hideWhenEmpty();
		} else {
			helper.title.html(title).show();
			helper.body.hide();
		}
		
		// if element has href or src, add and show it, otherwise hide it
		if( settings(this).showURL && $(this).url() )
			helper.url.html( $(this).url().replace('http://', '') ).show();
		else 
			helper.url.hide();
		
		// add an optional class for this tip
		helper.parent.addClass(settings(this).extraClass);

		// fix PNG background for IE
		if (settings(this).fixPNG )
			helper.parent.fixPNG();
			
		handle.apply(this, arguments);
	}
	
	// delete timeout and show helper
	function show() {
		tID = null;
		if ((!IE || !$.fn.bgiframe) && settings(current).fade) {
			if (helper.parent.is(":animated"))
				helper.parent.stop().show().fadeTo(settings(current).fade, current.tOpacity);
			else
				helper.parent.is(':visible') ? helper.parent.fadeTo(settings(current).fade, current.tOpacity) : helper.parent.fadeIn(settings(current).fade);
		} else {
			helper.parent.show();
		}
		update();
	}
	
	/**
	 * callback for mousemove
	 * updates the helper position
	 * removes itself when no current element
	 */
	function update(event)	{
		if($.tooltip.blocked)
			return;
		
		if (event && event.target.tagName == "OPTION") {
			return;
		}
		
		// stop updating when tracking is disabled and the tooltip is visible
		if ( !track && helper.parent.is(":visible")) {
			$(document.body).unbind('mousemove', update)
		}
		
		// if no current element is available, remove this listener
		if( current == null ) {
			$(document.body).unbind('mousemove', update);
			return;	
		}
		
		// remove position helper classes
		helper.parent.removeClass("viewport-right").removeClass("viewport-bottom");
		
		var left = helper.parent[0].offsetLeft;
		var top = helper.parent[0].offsetTop;
		if (event) {
			// position the helper 15 pixel to bottom right, starting from mouse position
			left = event.pageX + settings(current).left;
			top = event.pageY + settings(current).top;
			var right='auto';
			if (settings(current).positionLeft) {
				right = $(window).width() - left;
				left = 'auto';
			}
			helper.parent.css({
				left: left,
				right: right,
				top: top
			});
		}
		
		var v = viewport(),
			h = helper.parent[0];
		// check horizontal position
		if (v.x + v.cx < h.offsetLeft + h.offsetWidth) {
			left -= h.offsetWidth + 20 + settings(current).left;
			helper.parent.css({left: left + 'px'}).addClass("viewport-right");
		}
		// check vertical position
		if (v.y + v.cy < h.offsetTop + h.offsetHeight) {
			top -= h.offsetHeight + 20 + settings(current).top;
			helper.parent.css({top: top + 'px'}).addClass("viewport-bottom");
		}
	}
	
	function viewport() {
		return {
			x: $(window).scrollLeft(),
			y: $(window).scrollTop(),
			cx: $(window).width(),
			cy: $(window).height()
		};
	}
	
	// hide helper and restore added classes and the title
	function hide(event) {
		if($.tooltip.blocked)
			return;
		// clear timeout if possible
		if(tID)
			clearTimeout(tID);
		// no more current element
		current = null;
		
		var tsettings = settings(this);
		function complete() {
			helper.parent.removeClass( tsettings.extraClass ).hide().css("opacity", "");
		}
		if ((!IE || !$.fn.bgiframe) && tsettings.fade) {
			if (helper.parent.is(':animated'))
				helper.parent.stop().fadeTo(tsettings.fade, 0, complete);
			else
				helper.parent.stop().fadeOut(tsettings.fade, complete);
		} else
			complete();
		
		if( settings(this).fixPNG )
			helper.parent.unfixPNG();
	}
	
})(jQuery);
/*!
Math.uuid.js (v1.4)
http://www.broofa.com
mailto:robert@broofa.com

Copyright (c) 2010 Robert Kieffer
Dual licensed under the MIT and GPL licenses.
*/

/*
 * Generate a random uuid.
 *
 * USAGE: Math.uuid(length, radix)
 *   length - the desired number of characters
 *   radix  - the number of allowable values for each character.
 *
 * EXAMPLES:
 *   // No arguments  - returns RFC4122, version 4 ID
 *   >>> Math.uuid()
 *   "92329D39-6F5C-4520-ABFC-AAB64544E172"
 *
 *   // One argument - returns ID of the specified length
 *   >>> Math.uuid(15)     // 15 character ID (default base=62)
 *   "VcydxgltxrVZSTV"
 *
 *   // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62)
 *   >>> Math.uuid(8, 2)  // 8 character ID (base=2)
 *   "01001010"
 *   >>> Math.uuid(8, 10) // 8 character ID (base=10)
 *   "47473046"
 *   >>> Math.uuid(8, 16) // 8 character ID (base=16)
 *   "098F4D35"
 */
(function() {
  // Private array of chars to use
  var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');

  Math.uuid = function (len, radix) {
    var chars = CHARS, uuid = [], i;
    radix = radix || chars.length;

    if (len) {
      // Compact form
      for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
    } else {
      // rfc4122, version 4 form
      var r;

      // rfc4122 requires these characters
      uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
      uuid[14] = '4';

      // Fill in random data.  At i==19 set the high bits of clock sequence as
      // per rfc4122, sec. 4.1.5
      for (i = 0; i < 36; i++) {
        if (!uuid[i]) {
          r = 0 | Math.random()*16;
          uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
        }
      }
    }

    return uuid.join('');
  };

  // A more performant, but slightly bulkier, RFC4122v4 solution.  We boost performance
  // by minimizing calls to random()
  Math.uuidFast = function() {
    var chars = CHARS, uuid = new Array(36), rnd=0, r;
    for (var i = 0; i < 36; i++) {
      if (i==8 || i==13 ||  i==18 || i==23) {
        uuid[i] = '-';
      } else if (i==14) {
        uuid[i] = '4';
      } else {
        if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
        r = rnd & 0xf;
        rnd = rnd >> 4;
        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
      }
    }
    return uuid.join('');
  };

  // A more compact, but less performant, RFC4122v4 solution:
  Math.uuidCompact = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
      return v.toString(16);
    });
  };
})();
// jXHR.js (JSON-P XHR)
// v0.1 (c) Kyle Simpson
// MIT License

(function(global){
	var SETTIMEOUT = global.setTimeout, // for better compression
		doc = global.document,
		callback_counter = 0;
		
	global.jXHR = function() {
		var script_url,
			script_loaded,
			jsonp_callback,
			scriptElem,
			publicAPI = null;
			
		function removeScript() { try { scriptElem.parentNode.removeChild(scriptElem); } catch (err) { } }
			
		function reset() {
			script_loaded = false;
			script_url = "";
			removeScript();
			scriptElem = null;
			fireReadyStateChange(0);
		}
		
		function ThrowError(msg) {
			try { publicAPI.onerror.call(publicAPI,msg,script_url); } catch (err) { throw new Error(msg); }
		}

		function handleScriptLoad() {
			if ((this.readyState && this.readyState!=="complete" && this.readyState!=="loaded") || script_loaded) { return; }
			this.onload = this.onreadystatechange = null; // prevent memory leak
			script_loaded = true;
			if (publicAPI.readyState !== 4) ThrowError("Script failed to load ["+script_url+"].");
			removeScript();
		}
		
		function fireReadyStateChange(rs,args) {
			args = args || [];
			publicAPI.readyState = rs;
			if (typeof publicAPI.onreadystatechange === "function") publicAPI.onreadystatechange.apply(publicAPI,args);
		}
				
		publicAPI = {
			onerror:null,
			onreadystatechange:null,
			readyState:0,
			open:function(method,url){
				reset();
				internal_callback = "cb"+(callback_counter++);
				(function(icb){
					global.jXHR[icb] = function() {
						try { fireReadyStateChange.call(publicAPI,4,arguments); } 
						catch(err) { 
							publicAPI.readyState = -1;
							ThrowError("Script failed to run ["+script_url+"]."); 
						}
						global.jXHR[icb] = null;
					};
				})(internal_callback);
				script_url = url.replace(/=\?/,"=jXHR."+internal_callback);
				fireReadyStateChange(1);
			},
			send:function(){
				SETTIMEOUT(function(){
					scriptElem = doc.createElement("script");
					scriptElem.setAttribute("type","text/javascript");
					scriptElem.onload = scriptElem.onreadystatechange = function(){handleScriptLoad.call(scriptElem);};
					scriptElem.setAttribute("src",script_url);
					doc.getElementsByTagName("head")[0].appendChild(scriptElem);
				},0);
				fireReadyStateChange(2);
			},
			setRequestHeader:function(){}, // noop
			getResponseHeader:function(){return "";}, // basically noop
			getAllResponseHeaders:function(){return [];} // ditto
		};

		reset();
		
		return publicAPI;
	};
})(window);//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Wii Opera SDK - 3D Math Class v2.7.22 2008-12-14                         //
// (c) 2007-2008 Daniel Gump. All Rights Reserved.                          //
// http://wiioperasdk.com, http://hullbreachonline.com                      //
// hullbreach@hullbreachonline.com                                          //
//                                                                          //
//  Wii is a trademark of Nintendo Co., Ltd.                                //
//  Opera is a trademark of Opera, ASA.                                     //
//  This software package is not associated with either company             //
//  but was created to support users of both.  Its alternative name         //
//  when supporting other products is the HULLBREACH SDK.                   //
//                                                                          //
//  Redistribution and use in source and binary forms, with or without      //
//  modification, are permitted provided that the following conditions      //
//  are met:                                                                //
//    * Redistributions of source code must retain the above copyright      //
//      notice, this list of conditions and the following disclaimer.       //
//    * Redistributions in binary form must reproduce the above copyright   //
//      notice, this list of conditions and the following disclaimer in     //
//      the documentation and/or other materials provided with the          //
//      distribution.                                                       //
//    * Neither the names HULLBREACH ONLINE nor WII OPERA SDK nor the names //
//      of its contributors may be used to endorse or promote products      //
//      derived from this software without specific prior written           //
//      permission.                                                         //
//    * If the explicit purpose of the software is not to support the       //
//      Nintendo Wii or the Opera Web browser, then the names of such must  //
//      not be used in any derived product. The name shall be the           //
//      HULLBREACH SDK with a reference link to http://hullbreachonline.    //
//                                                                          //
//  THIS SOFTWARE IS PROVIDED BY Daniel Gump ''AS IS'' AND ANY EXPRESS OR   //
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED          //
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  //
//  DISCLAIMED. IN NO EVENT SHALL Daniel Gump BE LIABLE FOR ANY DIRECT,     //
//  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES      //
//  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR      //
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      //
//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,     //
//  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING   //
//  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      //
//  POSSIBILITY OF SUCH DAMAGE.                                             //
//////////////////////////////////////////////////////////////////////////////

function ThreeD(){
	POLYMESH = new Array();

	CENTERX = 400; CENTERY = 240;
	LIGHTX = -1000; LIGHTY = -1000; LIGHTZ = -1000;
	ORIGINX = 0; ORIGINY = 0; ORIGINZ = 0;
	ANGLEX = 0; ANGLEY = 0; ANGLEZ = 0;
}

ThreeD.prototype.setPoints = function(Points){
	POLYMESH = [];
	for(var value=Points.length;--value>=0;) POLYMESH[value] = Points[value].slice();
}
ThreeD.prototype.loadMesh = function(array){
	if(POLYMESH = array.split(";")) for(i=POLYMESH.length;--i>=0;) POLYMESH[i] = POLYMESH[i].split(",");
}
ThreeD.prototype.getPoints = function(){ return POLYMESH; }

ThreeD.prototype.setCenter = function(x,y){ CENTERX = x|0; CENTERY = y|0; }
ThreeD.prototype.setLight = function(x,y,z){ LIGHTX = x|0; LIGHTY = y|0; LIGHTZ = z|0; }

ThreeD.prototype.explode = function(z){
	var x1, y1, z1, x2, y2, z2;
	var normali, normalj, normalk, magNormal;

	for(var value=POLYMESH.length;--value>=0;){
		x1 = POLYMESH[value][3]-POLYMESH[value][0]; y1 = POLYMESH[value][4]-POLYMESH[value][1]; z1 = POLYMESH[value][5]-POLYMESH[value][2]; 
		x2 = POLYMESH[value][6]-POLYMESH[value][0]; y2 = POLYMESH[value][7]-POLYMESH[value][1]; z2 = POLYMESH[value][8]-POLYMESH[value][2]; 

		normali = y2*z1-y1*z2; normalj = x1*z2-x2*z1; normalk = x2*y1-x1*y2;
		magNormal = z/Math.sqrt(normali*normali+normalj*normalj+normalk*normalk);

		var movex = -normali*magNormal|0;
		var movey = -normalj*magNormal|0;
		var movez = -normalk*magNormal|0;

		POLYMESH[value][0] += movex; POLYMESH[value][1] += movey; POLYMESH[value][2] += movez;
		POLYMESH[value][3] += movex; POLYMESH[value][4] += movey; POLYMESH[value][5] += movez;
		POLYMESH[value][6] += movex; POLYMESH[value][7] += movey; POLYMESH[value][8] += movez;
	}
}
ThreeD.prototype.normalMap = function(normalMap){
	var x1, y1, z1, x2, y2, z2;
	var normali, normalj, normalk, magNormal;

	for(var value=POLYMESH.length;--value>=0;){
		x1 = POLYMESH[value][3]-POLYMESH[value][0]; y1 = POLYMESH[value][4]-POLYMESH[value][1]; z1 = POLYMESH[value][5]-POLYMESH[value][2]; 
		x2 = POLYMESH[value][6]-POLYMESH[value][0]; y2 = POLYMESH[value][7]-POLYMESH[value][1]; z2 = POLYMESH[value][8]-POLYMESH[value][2]; 

		normali = y2*z1-y1*z2; normalj = x1*z2-x2*z1; normalk = x2*y1-x1*y2;
		normal = 1/Math.sqrt(normali*normali+normalj*normalj+normalk*normalk);
		
		for(index2=0; index2<4; index2++){
			for(index=0; index<=index2; index++){
				magNormal = normalMap[index][index2]*normal|0;

				var movex = -normali*magNormal;
				var movey = -normalj*magNormal;
				var movez = -normalk*magNormal;
				
				POLYMESH[POLYMESH.length] = new Array(POLYMESH[value][0]+movex,POLYMESH[value][1]+movey,POLYMESH[value][2]+movez,
							POLYMESH[value][3]+movex,POLYMESH[value][4]+movey,POLYMESH[value][7]+movez,
							POLYMESH[value][6]+movex,POLYMESH[value][7]+movey,POLYMESH[value][8]+movez,
							POLYMESH[value][9],POLYMESH[value][10],POLYMESH[value][11],
							POLYMESH[value][12],POLYMESH[value][13], true, index, index2);
			}
		}
	}
}
ThreeD.prototype.move = function(x,y,z){
	for(var value=POLYMESH.length;--value>=0;)
		for(var point=-1;++point<3;){
			POLYMESH[value][point*3+2] += z;
			POLYMESH[value][point*3+1] += y;
			POLYMESH[value][point*3] += x;
		}
}
ThreeD.prototype.rotate = function(anglex,angley,anglez){
	var cosx = Math.cos(anglex*0.01745329); var sinx = Math.sin(anglex*0.01745329);
	var cosy = Math.cos(angley*0.01745329); var siny = Math.sin(angley*0.01745329);
	var cosz = Math.cos(anglez*0.01745329); var sinz = Math.sin(anglez*0.01745329);

	for(var value=POLYMESH.length;--value>=0;)
		for(var point=-1;++point<3;){
			var tempz = sinx*POLYMESH[value][point*3+1]+cosx*POLYMESH[value][point*3+2];
			var tempy = cosx*POLYMESH[value][point*3+1]-sinx*POLYMESH[value][point*3+2];
			var tempx = cosy*POLYMESH[value][point*3]+siny*tempz;
			POLYMESH[value][point*3+2] = cosy*tempz-siny*POLYMESH[value][point*3];
			POLYMESH[value][point*3+1] = sinz*tempx+cosz*tempy;
			POLYMESH[value][point*3] = cosz*tempx-sinz*tempy;
		}
}
ThreeD.prototype.scale = function(scalex,scaley,scalez){
	for(var value=POLYMESH.length;--value>=0;)
		for(var point=-1;++point<3;){
			POLYMESH[value][point*3+2] *= scalex;
			POLYMESH[value][point*3+1] *= scaley;
			POLYMESH[value][point*3] *= scalez;
		}
}

ThreeD.prototype.backface = function(){
	for(var value=POLYMESH.length, newvalue=0, TempPOLYMESH = [];--value>=0;)
		if((POLYMESH[value][3]-POLYMESH[value][0])*(POLYMESH[value][7]-POLYMESH[value][1])-(POLYMESH[value][6]-POLYMESH[value][0])*(POLYMESH[value][4]-POLYMESH[value][1])>0){
			TempPOLYMESH[newvalue++] = POLYMESH[value].slice();
		}
	POLYMESH = TempPOLYMESH;
}
ThreeD.prototype.zSort = function(){ POLYMESH.sort(function(b,a){return b[2]+b[5]+b[8]-a[2]-a[5]-a[8]}); }

ThreeD.prototype.fade = function(bright){
	for(var value=POLYMESH.length;--value>=0;) POLYMESH[value][13] += bright;
}
ThreeD.prototype.shade = function(){
	var x1, y1, z1, x2, y2, z2;
	var normali, normalj, normalk, magNormal;
	var lighti, lightj, lightk, magLight;

	for(var value=POLYMESH.length;--value>=0;){
		x1 = POLYMESH[value][3]-POLYMESH[value][0]; y1 = POLYMESH[value][4]-POLYMESH[value][1]; z1 = POLYMESH[value][5]-POLYMESH[value][2]; 
		x2 = POLYMESH[value][6]-POLYMESH[value][0]; y2 = POLYMESH[value][7]-POLYMESH[value][1]; z2 = POLYMESH[value][8]-POLYMESH[value][2]; 

		normali = y1*z2-y2*z1; normalj = x2*z1-x1*z2; normalk = x1*y2-x2*y1;

		lighti = LIGHTX-(POLYMESH[value][0]+POLYMESH[value][3]+POLYMESH[value][6])*0.33333333333333333;
		lightj = LIGHTY-(POLYMESH[value][1]+POLYMESH[value][4]+POLYMESH[value][7])*0.33333333333333333;
		lightk = LIGHTZ-(POLYMESH[value][2]+POLYMESH[value][5]+POLYMESH[value][8])*0.33333333333333333;

		POLYMESH[value][13] = 2*(normali*lighti + normalj*lightj + normalk*lightk)/Math.sqrt((normali*normali+normalj*normalj+normalk*normalk)*(lighti*lighti+lightj*lightj+lightk*lightk))-1;
	}
}
ThreeD.prototype.reColor = function(r,g,b){
	r=r>255?255:(r<0?0:r|0);
	g=g>255?255:(g<0?0:g|0);
	b=b>255?255:(b<0?0:b|0);
	for(var value=POLYMESH.length;--value>=0;){
		POLYMESH[value][9]=r;
		POLYMESH[value][10]=g;
		POLYMESH[value][11]=b;
	}
}
ThreeD.prototype.shadow = function(){
	rayorigins = []; 
	raynormals = [];
	edge1 = [];
	edge2 = [];

	for(var value=0, normali, normalj, normalk, magNormal;value<POLYMESH.length;value++){
		edge1[value] = new Array(POLYMESH[value][3]-POLYMESH[value][0], POLYMESH[value][4]-POLYMESH[value][1], POLYMESH[value][5]-POLYMESH[value][2]);
		edge2[value] = new Array(POLYMESH[value][6]-POLYMESH[value][0], POLYMESH[value][7]-POLYMESH[value][1], POLYMESH[value][8]-POLYMESH[value][2]);

		rayorigins[value] = new Array((POLYMESH[value][0]+POLYMESH[value][3]+POLYMESH[value][6])*0.33333333333333333, (POLYMESH[value][1]+POLYMESH[value][4]+POLYMESH[value][7])*0.33333333333333333, (POLYMESH[value][2]+POLYMESH[value][5]+POLYMESH[value][8])*0.33333333333333333);

		normali = LIGHTX-rayorigins[value][0];
		normalj = LIGHTY-rayorigins[value][1];
		normalk = LIGHTZ-rayorigins[value][2];
		magNormal = 1/Math.sqrt(normali*normali+normalj*normalj+normalk*normalk);
		raynormals[value] = new Array(normali*magNormal, normalj*magNormal, normalk*magNormal);
	}

	for(var value=POLYMESH.length;--value>=0;){
		for(var value2=POLYMESH.length;--value2>=0;){
			if(value2!=value){
				var pvecti = raynormals[value][1]*edge2[value2][2]-edge2[value2][1]*raynormals[value][2];
				var pvectj = edge2[value2][0]*raynormals[value][2]-raynormals[value][0]*edge2[value2][2];
				var pvectk = raynormals[value][0]*edge2[value2][1]-edge2[value2][0]*raynormals[value][1];

				if((det = edge1[value2][0]*pvecti+edge1[value2][1]*pvectj+edge1[value2][2]*pvectk)<0){
					det=1/det;

					var tvecti = rayorigins[value][0]-POLYMESH[value2][0];
					var tvectj = rayorigins[value][1]-POLYMESH[value2][1];
					var tvectk = rayorigins[value][2]-POLYMESH[value2][2];

					if((u = (pvecti*tvecti+pvectj*tvectj+pvectk*tvectk) * det)>=0 && u<=1){
						if((v = (raynormals[value][0]*(tvectj*edge1[value2][2]-edge1[value2][1]*tvectk)+raynormals[value][1]*(edge1[value2][0]*tvectk-tvecti*edge1[value2][2])+raynormals[value][2]*(tvecti*edge1[value2][1]-edge1[value2][0]*tvectj)) * det)>=0 && u+v<=1){
							POLYMESH[value][13] -=.5;
							break;
						}
					}
				}
				
			}
		}
	}
}

ThreeD.prototype.getTranslation = function(){
	for(var value=POLYMESH.length,newvalue=0,TransPOLYMESH = [];--value>=0;){
		var POLYMESH2=5000/(5000-POLYMESH[value][2]), POLYMESH5=5000/(5000-POLYMESH[value][5]), POLYMESH8=5000/(5000-POLYMESH[value][8]);
		TransPOLYMESH[newvalue++] = new Array((CENTERX+POLYMESH[value][0]*POLYMESH2),(CENTERY+POLYMESH[value][1]*POLYMESH2),
									(CENTERX+POLYMESH[value][3]*POLYMESH5),(CENTERY+POLYMESH[value][4]*POLYMESH5),
									(CENTERX+POLYMESH[value][6]*POLYMESH8),(CENTERY+POLYMESH[value][7]*POLYMESH8),
									POLYMESH[value][9]|0,POLYMESH[value][10]|0,POLYMESH[value][11]|0,POLYMESH[value][12]|0,POLYMESH[value][13]);
	}
	return TransPOLYMESH;
}

ThreeDee = new ThreeD();/**
 * @author mrdoob / http://mrdoob.com/
 */

var THREE = THREE || { REVISION: '51' };

if ( self.console === undefined ) {

    self.console = {

        info: function () {},
        log: function () {},
        debug: function () {},
        warn: function () {},
        error: function () {}

    };

}

if ( self.Int32Array === undefined ) {

    self.Int32Array = Array;
    self.Float32Array = Array;

}

// Shims for "startsWith", "endsWith", and "trim" for browsers where this is not yet implemented
// not sure we should have this, or at least not have it here

// http://stackoverflow.com/questions/646628/javascript-startswith
// http://stackoverflow.com/questions/498970/how-do-i-trim-a-string-in-javascript
// http://wiki.ecmascript.org/doku.php?id=harmony%3astring_extras

if ( String.prototype.startsWith === undefined ) {

    String.prototype.startsWith = function ( str ) {

        return this.slice( 0, str.length ) === str;

    };

}

if ( String.prototype.endsWith === undefined ) {

    String.prototype.endsWith = function ( str ) {

        var t = String( str );
        var index = this.lastIndexOf( t );
        return index >= 0 && index === this.length - t.length;

    };

}

if ( ! String.prototype.trim === undefined ) {

    String.prototype.trim = function () {

        return this.replace( /^\s+|\s+$/g, '' );

    };

}

// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel

( function () {

    var lastTime = 0;
    var vendors = [ 'ms', 'moz', 'webkit', 'o' ];

    for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++ x ) {

        window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ];
        window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ];

    }

    if ( window.requestAnimationFrame === undefined ) {

        window.requestAnimationFrame = function ( callback, element ) {

            var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
            var id = window.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall );
            lastTime = currTime + timeToCall;
            return id;

        };

    }


    if ( window.cancelAnimationFrame === undefined ) {

        window.cancelAnimationFrame = function ( id ) { clearTimeout( id ); };

    }

}() );


// MATERIAL CONSTANTS

// side

THREE.FrontSide = 0;
THREE.BackSide = 1;
THREE.DoubleSide = 2;

// shading

THREE.NoShading = 0;
THREE.FlatShading = 1;
THREE.SmoothShading = 2;

// colors

THREE.NoColors = 0;
THREE.FaceColors = 1;
THREE.VertexColors = 2;

// blending modes

THREE.NoBlending = 0;
THREE.NormalBlending = 1;
THREE.AdditiveBlending = 2;
THREE.SubtractiveBlending = 3;
THREE.MultiplyBlending = 4;
THREE.CustomBlending = 5;

// custom blending equations
// (numbers start from 100 not to clash with other
//  mappings to OpenGL constants defined in Texture.js)

THREE.AddEquation = 100;
THREE.SubtractEquation = 101;
THREE.ReverseSubtractEquation = 102;

// custom blending destination factors

THREE.ZeroFactor = 200;
THREE.OneFactor = 201;
THREE.SrcColorFactor = 202;
THREE.OneMinusSrcColorFactor = 203;
THREE.SrcAlphaFactor = 204;
THREE.OneMinusSrcAlphaFactor = 205;
THREE.DstAlphaFactor = 206;
THREE.OneMinusDstAlphaFactor = 207;

// custom blending source factors

//THREE.ZeroFactor = 200;
//THREE.OneFactor = 201;
//THREE.SrcAlphaFactor = 204;
//THREE.OneMinusSrcAlphaFactor = 205;
//THREE.DstAlphaFactor = 206;
//THREE.OneMinusDstAlphaFactor = 207;
THREE.DstColorFactor = 208;
THREE.OneMinusDstColorFactor = 209;
THREE.SrcAlphaSaturateFactor = 210;


// TEXTURE CONSTANTS

THREE.MultiplyOperation = 0;
THREE.MixOperation = 1;

// Mapping modes

THREE.UVMapping = function () {};

THREE.CubeReflectionMapping = function () {};
THREE.CubeRefractionMapping = function () {};

THREE.SphericalReflectionMapping = function () {};
THREE.SphericalRefractionMapping = function () {};

// Wrapping modes

THREE.RepeatWrapping = 1000;
THREE.ClampToEdgeWrapping = 1001;
THREE.MirroredRepeatWrapping = 1002;

// Filters

THREE.NearestFilter = 1003;
THREE.NearestMipMapNearestFilter = 1004;
THREE.NearestMipMapLinearFilter = 1005;
THREE.LinearFilter = 1006;
THREE.LinearMipMapNearestFilter = 1007;
THREE.LinearMipMapLinearFilter = 1008;

// Data types

THREE.UnsignedByteType = 1009;
THREE.ByteType = 1010;
THREE.ShortType = 1011;
THREE.UnsignedShortType = 1012;
THREE.IntType = 1013;
THREE.UnsignedIntType = 1014;
THREE.FloatType = 1015;

// Pixel types

//THREE.UnsignedByteType = 1009;
THREE.UnsignedShort4444Type = 1016;
THREE.UnsignedShort5551Type = 1017;
THREE.UnsignedShort565Type = 1018;

// Pixel formats

THREE.AlphaFormat = 1019;
THREE.RGBFormat = 1020;
THREE.RGBAFormat = 1021;
THREE.LuminanceFormat = 1022;
THREE.LuminanceAlphaFormat = 1023;

// Compressed texture formats

THREE.RGB_S3TC_DXT1_Format = 2001;
THREE.RGBA_S3TC_DXT1_Format = 2002;
THREE.RGBA_S3TC_DXT3_Format = 2003;
THREE.RGBA_S3TC_DXT5_Format = 2004;

/*
// Potential future PVRTC compressed texture formats
THREE.RGB_PVRTC_4BPPV1_Format = 2100;
THREE.RGB_PVRTC_2BPPV1_Format = 2101;
THREE.RGBA_PVRTC_4BPPV1_Format = 2102;
THREE.RGBA_PVRTC_2BPPV1_Format = 2103;
*/
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Clock = function ( autoStart ) {

    this.autoStart = ( autoStart !== undefined ) ? autoStart : true;

    this.startTime = 0;
    this.oldTime = 0;
    this.elapsedTime = 0;

    this.running = false;

};

THREE.Clock.prototype.start = function () {

    this.startTime = Date.now();
    this.oldTime = this.startTime;

    this.running = true;

};

THREE.Clock.prototype.stop = function () {

    this.getElapsedTime();

    this.running = false;

};

THREE.Clock.prototype.getElapsedTime = function () {

    this.elapsedTime += this.getDelta();

    return this.elapsedTime;

};


THREE.Clock.prototype.getDelta = function () {

    var diff = 0;

    if ( this.autoStart && ! this.running ) {

        this.start();

    }

    if ( this.running ) {

        var newTime = Date.now();
        diff = 0.001 * ( newTime - this.oldTime );
        this.oldTime = newTime;

        this.elapsedTime += diff;

    }

    return diff;

};/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Color = function ( hex ) {

    if ( hex !== undefined ) this.setHex( hex );

    return this;

};

THREE.Color.prototype = {

    constructor: THREE.Color,

    r: 1, g: 1, b: 1,

    copy: function ( color ) {

        this.r = color.r;
        this.g = color.g;
        this.b = color.b;

        return this;

    },

    copyGammaToLinear: function ( color ) {

        this.r = color.r * color.r;
        this.g = color.g * color.g;
        this.b = color.b * color.b;

        return this;

    },

    copyLinearToGamma: function ( color ) {

        this.r = Math.sqrt( color.r );
        this.g = Math.sqrt( color.g );
        this.b = Math.sqrt( color.b );

        return this;

    },

    convertGammaToLinear: function () {

        var r = this.r, g = this.g, b = this.b;

        this.r = r * r;
        this.g = g * g;
        this.b = b * b;

        return this;

    },

    convertLinearToGamma: function () {

        this.r = Math.sqrt( this.r );
        this.g = Math.sqrt( this.g );
        this.b = Math.sqrt( this.b );

        return this;

    },

    setRGB: function ( r, g, b ) {

        this.r = r;
        this.g = g;
        this.b = b;

        return this;

    },

    setHSV: function ( h, s, v ) {

        // based on MochiKit implementation by Bob Ippolito
        // h,s,v ranges are < 0.0 - 1.0 >

        var i, f, p, q, t;

        if ( v === 0 ) {

            this.r = this.g = this.b = 0;

        } else {

            i = Math.floor( h * 6 );
            f = ( h * 6 ) - i;
            p = v * ( 1 - s );
            q = v * ( 1 - ( s * f ) );
            t = v * ( 1 - ( s * ( 1 - f ) ) );

            if ( i === 0 ) {

                this.r = v;
                this.g = t;
                this.b = p;

            } else if ( i === 1 ) {

                this.r = q;
                this.g = v;
                this.b = p;

            } else if ( i === 2 ) {

                this.r = p;
                this.g = v;
                this.b = t;

            } else if ( i === 3 ) {

                this.r = p;
                this.g = q;
                this.b = v;

            } else if ( i === 4 ) {

                this.r = t;
                this.g = p;
                this.b = v;

            } else if ( i === 5 ) {

                this.r = v;
                this.g = p;
                this.b = q;

            }

        }

        return this;

    },

    setHex: function ( hex ) {

        hex = Math.floor( hex );

        this.r = ( hex >> 16 & 255 ) / 255;
        this.g = ( hex >> 8 & 255 ) / 255;
        this.b = ( hex & 255 ) / 255;

        return this;

    },

    lerpSelf: function ( color, alpha ) {

        this.r += ( color.r - this.r ) * alpha;
        this.g += ( color.g - this.g ) * alpha;
        this.b += ( color.b - this.b ) * alpha;

        return this;

    },

    getHex: function () {

        return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;

    },

    getContextStyle: function () {

        return 'rgb(' + ( ( this.r * 255 ) | 0 )  + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';

    },

    clone: function () {

        return new THREE.Color().setRGB( this.r, this.g, this.b );

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author philogb / http://blog.thejit.org/
 * @author egraether / http://egraether.com/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 */

THREE.Vector2 = function ( x, y ) {

    this.x = x || 0;
    this.y = y || 0;

};

THREE.Vector2.prototype = {

    constructor: THREE.Vector2,

    set: function ( x, y ) {

        this.x = x;
        this.y = y;

        return this;

    },

    copy: function ( v ) {

        this.x = v.x;
        this.y = v.y;

        return this;

    },

    add: function ( a, b ) {

        this.x = a.x + b.x;
        this.y = a.y + b.y;

        return this;

    },

    addSelf: function ( v ) {

        this.x += v.x;
        this.y += v.y;

        return this;

    },

    sub: function ( a, b ) {

        this.x = a.x - b.x;
        this.y = a.y - b.y;

        return this;

    },

    subSelf: function ( v ) {

        this.x -= v.x;
        this.y -= v.y;

        return this;

    },

    multiplyScalar: function ( s ) {

        this.x *= s;
        this.y *= s;

        return this;

    },

    divideScalar: function ( s ) {

        if ( s ) {

            this.x /= s;
            this.y /= s;

        } else {

            this.set( 0, 0 );

        }

        return this;

    },

    negate: function() {

        return this.multiplyScalar( - 1 );

    },

    dot: function ( v ) {

        return this.x * v.x + this.y * v.y;

    },

    lengthSq: function () {

        return this.x * this.x + this.y * this.y;

    },

    length: function () {

        return Math.sqrt( this.lengthSq() );

    },

    normalize: function () {

        return this.divideScalar( this.length() );

    },

    distanceTo: function ( v ) {

        return Math.sqrt( this.distanceToSquared( v ) );

    },

    distanceToSquared: function ( v ) {

        var dx = this.x - v.x, dy = this.y - v.y;
        return dx * dx + dy * dy;

    },

    setLength: function ( l ) {

        return this.normalize().multiplyScalar( l );

    },

    lerpSelf: function ( v, alpha ) {

        this.x += ( v.x - this.x ) * alpha;
        this.y += ( v.y - this.y ) * alpha;

        return this;

    },

    equals: function( v ) {

        return ( ( v.x === this.x ) && ( v.y === this.y ) );

    },

    isZero: function () {

        return ( this.lengthSq() < 0.0001 /* almostZero */ );

    },

    clone: function () {

        return new THREE.Vector2( this.x, this.y );

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author kile / http://kile.stravaganza.org/
 * @author philogb / http://blog.thejit.org/
 * @author mikael emtinger / http://gomo.se/
 * @author egraether / http://egraether.com/
 * @author WestLangley / http://github.com/WestLangley
 */

THREE.Vector3 = function ( x, y, z ) {

    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;

};


THREE.Vector3.prototype = {

    constructor: THREE.Vector3,

    set: function ( x, y, z ) {

        this.x = x;
        this.y = y;
        this.z = z;

        return this;

    },

    setX: function ( x ) {

        this.x = x;

        return this;

    },

    setY: function ( y ) {

        this.y = y;

        return this;

    },

    setZ: function ( z ) {

        this.z = z;

        return this;

    },

    copy: function ( v ) {

        this.x = v.x;
        this.y = v.y;
        this.z = v.z;

        return this;

    },

    add: function ( a, b ) {

        this.x = a.x + b.x;
        this.y = a.y + b.y;
        this.z = a.z + b.z;

        return this;

    },

    addSelf: function ( v ) {

        this.x += v.x;
        this.y += v.y;
        this.z += v.z;

        return this;

    },

    addScalar: function ( s ) {

        this.x += s;
        this.y += s;
        this.z += s;

        return this;

    },

    sub: function ( a, b ) {

        this.x = a.x - b.x;
        this.y = a.y - b.y;
        this.z = a.z - b.z;

        return this;

    },

    subSelf: function ( v ) {

        this.x -= v.x;
        this.y -= v.y;
        this.z -= v.z;

        return this;

    },

    multiply: function ( a, b ) {

        this.x = a.x * b.x;
        this.y = a.y * b.y;
        this.z = a.z * b.z;

        return this;

    },

    multiplySelf: function ( v ) {

        this.x *= v.x;
        this.y *= v.y;
        this.z *= v.z;

        return this;

    },

    multiplyScalar: function ( s ) {

        this.x *= s;
        this.y *= s;
        this.z *= s;

        return this;

    },

    divideSelf: function ( v ) {

        this.x /= v.x;
        this.y /= v.y;
        this.z /= v.z;

        return this;

    },

    divideScalar: function ( s ) {

        if ( s ) {

            this.x /= s;
            this.y /= s;
            this.z /= s;

        } else {

            this.x = 0;
            this.y = 0;
            this.z = 0;

        }

        return this;

    },


    negate: function() {

        return this.multiplyScalar( - 1 );

    },

    dot: function ( v ) {

        return this.x * v.x + this.y * v.y + this.z * v.z;

    },

    lengthSq: function () {

        return this.x * this.x + this.y * this.y + this.z * this.z;

    },

    length: function () {

        return Math.sqrt( this.lengthSq() );

    },

    lengthManhattan: function () {

        return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );

    },

    normalize: function () {

        return this.divideScalar( this.length() );

    },

    setLength: function ( l ) {

        return this.normalize().multiplyScalar( l );

    },

    lerpSelf: function ( v, alpha ) {

        this.x += ( v.x - this.x ) * alpha;
        this.y += ( v.y - this.y ) * alpha;
        this.z += ( v.z - this.z ) * alpha;

        return this;

    },

    cross: function ( a, b ) {

        this.x = a.y * b.z - a.z * b.y;
        this.y = a.z * b.x - a.x * b.z;
        this.z = a.x * b.y - a.y * b.x;

        return this;

    },

    crossSelf: function ( v ) {

        var x = this.x, y = this.y, z = this.z;

        this.x = y * v.z - z * v.y;
        this.y = z * v.x - x * v.z;
        this.z = x * v.y - y * v.x;

        return this;

    },

    distanceTo: function ( v ) {

        return Math.sqrt( this.distanceToSquared( v ) );

    },

    distanceToSquared: function ( v ) {

        return new THREE.Vector3().sub( this, v ).lengthSq();

    },

    getPositionFromMatrix: function ( m ) {

        this.x = m.elements[12];
        this.y = m.elements[13];
        this.z = m.elements[14];

        return this;

    },

    setEulerFromRotationMatrix: function ( m, order ) {

        // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

        // clamp, to handle numerical problems

        function clamp( x ) {

            return Math.min( Math.max( x, -1 ), 1 );

        }

        var te = m.elements;
        var m11 = te[0], m12 = te[4], m13 = te[8];
        var m21 = te[1], m22 = te[5], m23 = te[9];
        var m31 = te[2], m32 = te[6], m33 = te[10];

        if ( order === undefined || order === 'XYZ' ) {

            this.y = Math.asin( clamp( m13 ) );

            if ( Math.abs( m13 ) < 0.99999 ) {

                this.x = Math.atan2( - m23, m33 );
                this.z = Math.atan2( - m12, m11 );

            } else {

                this.x = Math.atan2( m32, m22 );
                this.z = 0;

            }

        } else if ( order === 'YXZ' ) {

            this.x = Math.asin( - clamp( m23 ) );

            if ( Math.abs( m23 ) < 0.99999 ) {

                this.y = Math.atan2( m13, m33 );
                this.z = Math.atan2( m21, m22 );

            } else {

                this.y = Math.atan2( - m31, m11 );
                this.z = 0;

            }

        } else if ( order === 'ZXY' ) {

            this.x = Math.asin( clamp( m32 ) );

            if ( Math.abs( m32 ) < 0.99999 ) {

                this.y = Math.atan2( - m31, m33 );
                this.z = Math.atan2( - m12, m22 );

            } else {

                this.y = 0;
                this.z = Math.atan2( m21, m11 );

            }

        } else if ( order === 'ZYX' ) {

            this.y = Math.asin( - clamp( m31 ) );

            if ( Math.abs( m31 ) < 0.99999 ) {

                this.x = Math.atan2( m32, m33 );
                this.z = Math.atan2( m21, m11 );

            } else {

                this.x = 0;
                this.z = Math.atan2( - m12, m22 );

            }

        } else if ( order === 'YZX' ) {

            this.z = Math.asin( clamp( m21 ) );

            if ( Math.abs( m21 ) < 0.99999 ) {

                this.x = Math.atan2( - m23, m22 );
                this.y = Math.atan2( - m31, m11 );

            } else {

                this.x = 0;
                this.y = Math.atan2( m13, m33 );

            }

        } else if ( order === 'XZY' ) {

            this.z = Math.asin( - clamp( m12 ) );

            if ( Math.abs( m12 ) < 0.99999 ) {

                this.x = Math.atan2( m32, m22 );
                this.y = Math.atan2( m13, m11 );

            } else {

                this.x = Math.atan2( - m23, m33 );
                this.y = 0;

            }

        }

        return this;

    },

    setEulerFromQuaternion: function ( q, order ) {

        // q is assumed to be normalized

        // clamp, to handle numerical problems

        function clamp( x ) {

            return Math.min( Math.max( x, -1 ), 1 );

        }

        // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m

        var sqx = q.x * q.x;
        var sqy = q.y * q.y;
        var sqz = q.z * q.z;
        var sqw = q.w * q.w;

        if ( order === undefined || order === 'XYZ' ) {

            this.x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) );
            this.y = Math.asin(  clamp( 2 * ( q.x * q.z + q.y * q.w ) ) );
            this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) );

        } else if ( order ===  'YXZ' ) {

            this.x = Math.asin(  clamp( 2 * ( q.x * q.w - q.y * q.z ) ) );
            this.y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) );
            this.z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) );

        } else if ( order === 'ZXY' ) {

            this.x = Math.asin(  clamp( 2 * ( q.x * q.w + q.y * q.z ) ) );
            this.y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) );
            this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) );

        } else if ( order === 'ZYX' ) {

            this.x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) );
            this.y = Math.asin(  clamp( 2 * ( q.y * q.w - q.x * q.z ) ) );
            this.z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) );

        } else if ( order === 'YZX' ) {

            this.x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) );
            this.y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) );
            this.z = Math.asin(  clamp( 2 * ( q.x * q.y + q.z * q.w ) ) );

        } else if ( order === 'XZY' ) {

            this.x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) );
            this.y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) );
            this.z = Math.asin(  clamp( 2 * ( q.z * q.w - q.x * q.y ) ) );

        }

        return this;

    },

    getScaleFromMatrix: function ( m ) {

        var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length();
        var sy = this.set( m.elements[4], m.elements[5], m.elements[6] ).length();
        var sz = this.set( m.elements[8], m.elements[9], m.elements[10] ).length();

        this.x = sx;
        this.y = sy;
        this.z = sz;

        return this;
    },

    equals: function ( v ) {

        return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );

    },

    isZero: function () {

        return ( this.lengthSq() < 0.0001 /* almostZero */ );

    },

    clone: function () {

        return new THREE.Vector3( this.x, this.y, this.z );

    }

};

/**
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author philogb / http://blog.thejit.org/
 * @author mikael emtinger / http://gomo.se/
 * @author egraether / http://egraether.com/
 * @author WestLangley / http://github.com/WestLangley
 */

THREE.Vector4 = function ( x, y, z, w ) {

    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
    this.w = ( w !== undefined ) ? w : 1;

};

THREE.Vector4.prototype = {

    constructor: THREE.Vector4,

    set: function ( x, y, z, w ) {

        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;

        return this;

    },

    copy: function ( v ) {

        this.x = v.x;
        this.y = v.y;
        this.z = v.z;
        this.w = ( v.w !== undefined ) ? v.w : 1;

        return this;

    },

    add: function ( a, b ) {

        this.x = a.x + b.x;
        this.y = a.y + b.y;
        this.z = a.z + b.z;
        this.w = a.w + b.w;

        return this;

    },

    addSelf: function ( v ) {

        this.x += v.x;
        this.y += v.y;
        this.z += v.z;
        this.w += v.w;

        return this;

    },

    sub: function ( a, b ) {

        this.x = a.x - b.x;
        this.y = a.y - b.y;
        this.z = a.z - b.z;
        this.w = a.w - b.w;

        return this;

    },

    subSelf: function ( v ) {

        this.x -= v.x;
        this.y -= v.y;
        this.z -= v.z;
        this.w -= v.w;

        return this;

    },

    multiplyScalar: function ( s ) {

        this.x *= s;
        this.y *= s;
        this.z *= s;
        this.w *= s;

        return this;

    },

    divideScalar: function ( s ) {

        if ( s ) {

            this.x /= s;
            this.y /= s;
            this.z /= s;
            this.w /= s;

        } else {

            this.x = 0;
            this.y = 0;
            this.z = 0;
            this.w = 1;

        }

        return this;

    },


    negate: function() {

        return this.multiplyScalar( -1 );

    },

    dot: function ( v ) {

        return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;

    },

    lengthSq: function () {

        return this.dot( this );

    },

    length: function () {

        return Math.sqrt( this.lengthSq() );

    },

    lengthManhattan: function () {

        return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );

    },

    normalize: function () {

        return this.divideScalar( this.length() );

    },

    setLength: function ( l ) {

        return this.normalize().multiplyScalar( l );

    },

    lerpSelf: function ( v, alpha ) {

        this.x += ( v.x - this.x ) * alpha;
        this.y += ( v.y - this.y ) * alpha;
        this.z += ( v.z - this.z ) * alpha;
        this.w += ( v.w - this.w ) * alpha;

        return this;

    },

    clone: function () {

        return new THREE.Vector4( this.x, this.y, this.z, this.w );

    },

    setAxisAngleFromQuaternion: function ( q ) {

        // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm

        // q is assumed to be normalized

        this.w = 2 * Math.acos( q.w );

        var s = Math.sqrt( 1 - q.w * q.w );

        if ( s < 0.0001 ) {

             this.x = 1;
             this.y = 0;
             this.z = 0;

        } else {

             this.x = q.x / s;
             this.y = q.y / s;
             this.z = q.z / s;

        }

        return this;

    },

    setAxisAngleFromRotationMatrix: function ( m ) {

        // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm

        // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

        var angle, x, y, z,        // variables for result
            epsilon = 0.01,        // margin to allow for rounding errors
            epsilon2 = 0.1,        // margin to distinguish between 0 and 180 degrees

            te = m.elements,

            m11 = te[0], m12 = te[4], m13 = te[8],
            m21 = te[1], m22 = te[5], m23 = te[9],
            m31 = te[2], m32 = te[6], m33 = te[10];

        if ( ( Math.abs( m12 - m21 ) < epsilon )
          && ( Math.abs( m13 - m31 ) < epsilon )
          && ( Math.abs( m23 - m32 ) < epsilon ) ) {

            // singularity found
            // first check for identity matrix which must have +1 for all terms
            // in leading diagonal and zero in other terms

            if ( ( Math.abs( m12 + m21 ) < epsilon2 )
              && ( Math.abs( m13 + m31 ) < epsilon2 )
              && ( Math.abs( m23 + m32 ) < epsilon2 )
              && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {

                // this singularity is identity matrix so angle = 0

                this.set( 1, 0, 0, 0 );

                return this; // zero angle, arbitrary axis

            }

            // otherwise this singularity is angle = 180

            angle = Math.PI;

            var xx = ( m11 + 1 ) / 2;
            var yy = ( m22 + 1 ) / 2;
            var zz = ( m33 + 1 ) / 2;
            var xy = ( m12 + m21 ) / 4;
            var xz = ( m13 + m31 ) / 4;
            var yz = ( m23 + m32 ) / 4;

            if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term

                if ( xx < epsilon ) {

                    x = 0;
                    y = 0.707106781;
                    z = 0.707106781;

                } else {

                    x = Math.sqrt( xx );
                    y = xy / x;
                    z = xz / x;

                }

            } else if ( yy > zz ) { // m22 is the largest diagonal term

                if ( yy < epsilon ) {

                    x = 0.707106781;
                    y = 0;
                    z = 0.707106781;

                } else {

                    y = Math.sqrt( yy );
                    x = xy / y;
                    z = yz / y;

                }

            } else { // m33 is the largest diagonal term so base result on this

                if ( zz < epsilon ) {

                    x = 0.707106781;
                    y = 0.707106781;
                    z = 0;

                } else {

                    z = Math.sqrt( zz );
                    x = xz / z;
                    y = yz / z;

                }

            }

            this.set( x, y, z, angle );

            return this; // return 180 deg rotation

        }

        // as we have reached here there are no singularities so we can handle normally

        var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 )
                         + ( m13 - m31 ) * ( m13 - m31 )
                         + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize

        if ( Math.abs( s ) < 0.001 ) s = 1;

        // prevent divide by zero, should not happen if matrix is orthogonal and should be
        // caught by singularity test above, but I've left it in just in case

        this.x = ( m32 - m23 ) / s;
        this.y = ( m13 - m31 ) / s;
        this.z = ( m21 - m12 ) / s;
        this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );

        return this;

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Matrix3 = function () {

    this.elements = new Float32Array(9);

};

THREE.Matrix3.prototype = {

    constructor: THREE.Matrix3,

    getInverse: function ( matrix ) {

        // input: THREE.Matrix4
        // ( based on http://code.google.com/p/webgl-mjs/ )

        var me = matrix.elements;

        var a11 =   me[10] * me[5] - me[6] * me[9];
        var a21 = - me[10] * me[1] + me[2] * me[9];
        var a31 =   me[6] * me[1] - me[2] * me[5];
        var a12 = - me[10] * me[4] + me[6] * me[8];
        var a22 =   me[10] * me[0] - me[2] * me[8];
        var a32 = - me[6] * me[0] + me[2] * me[4];
        var a13 =   me[9] * me[4] - me[5] * me[8];
        var a23 = - me[9] * me[0] + me[1] * me[8];
        var a33 =   me[5] * me[0] - me[1] * me[4];

        var det = me[0] * a11 + me[1] * a12 + me[2] * a13;

        // no inverse

        if ( det === 0 ) {

            console.warn( "Matrix3.getInverse(): determinant == 0" );

        }

        var idet = 1.0 / det;

        var m = this.elements;

        m[ 0 ] = idet * a11; m[ 1 ] = idet * a21; m[ 2 ] = idet * a31;
        m[ 3 ] = idet * a12; m[ 4 ] = idet * a22; m[ 5 ] = idet * a32;
        m[ 6 ] = idet * a13; m[ 7 ] = idet * a23; m[ 8 ] = idet * a33;

        return this;

    },


    transpose: function () {

        var tmp, m = this.elements;

        tmp = m[1]; m[1] = m[3]; m[3] = tmp;
        tmp = m[2]; m[2] = m[6]; m[6] = tmp;
        tmp = m[5]; m[5] = m[7]; m[7] = tmp;

        return this;

    },


    transposeIntoArray: function ( r ) {

        var m = this.m;

        r[ 0 ] = m[ 0 ];
        r[ 1 ] = m[ 3 ];
        r[ 2 ] = m[ 6 ];
        r[ 3 ] = m[ 1 ];
        r[ 4 ] = m[ 4 ];
        r[ 5 ] = m[ 7 ];
        r[ 6 ] = m[ 2 ];
        r[ 7 ] = m[ 5 ];
        r[ 8 ] = m[ 8 ];

        return this;

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author philogb / http://blog.thejit.org/
 * @author jordi_ros / http://plattsoft.com
 * @author D1plo1d / http://github.com/D1plo1d
 * @author alteredq / http://alteredqualia.com/
 * @author mikael emtinger / http://gomo.se/
 * @author timknip / http://www.floorplanner.com/
 */


THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {

    this.elements = new Float32Array( 16 );

    this.set(

        ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, n14 || 0,
        n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, n24 || 0,
        n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1, n34 || 0,
        n41 || 0, n42 || 0, n43 || 0, ( n44 !== undefined ) ? n44 : 1

    );

};

THREE.Matrix4.prototype = {

    constructor: THREE.Matrix4,

    set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {

        var te = this.elements;

        te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14;
        te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24;
        te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34;
        te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44;

        return this;

    },

    identity: function () {

        this.set(

            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1

        );

        return this;

    },

    copy: function ( m ) {

        var me = m.elements;

        this.set(

            me[0], me[4], me[8], me[12],
            me[1], me[5], me[9], me[13],
            me[2], me[6], me[10], me[14],
            me[3], me[7], me[11], me[15]

        );

        return this;

    },

    lookAt: function ( eye, target, up ) {

        var te = this.elements;

        var x = THREE.Matrix4.__v1;
        var y = THREE.Matrix4.__v2;
        var z = THREE.Matrix4.__v3;

        z.sub( eye, target ).normalize();

        if ( z.length() === 0 ) {

            z.z = 1;

        }

        x.cross( up, z ).normalize();

        if ( x.length() === 0 ) {

            z.x += 0.0001;
            x.cross( up, z ).normalize();

        }

        y.cross( z, x );


        te[0] = x.x; te[4] = y.x; te[8] = z.x;
        te[1] = x.y; te[5] = y.y; te[9] = z.y;
        te[2] = x.z; te[6] = y.z; te[10] = z.z;

        return this;

    },

    multiply: function ( a, b ) {

        var ae = a.elements;
        var be = b.elements;
        var te = this.elements;

        var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
        var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
        var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
        var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];

        var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12];
        var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13];
        var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14];
        var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15];

        te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
        te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
        te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
        te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;

        te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
        te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
        te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
        te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;

        te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
        te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
        te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
        te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;

        te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
        te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
        te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
        te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;

        return this;

    },

    multiplySelf: function ( m ) {

        return this.multiply( this, m );

    },

    multiplyToArray: function ( a, b, r ) {

        var te = this.elements;

        this.multiply( a, b );

        r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3];
        r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7];
        r[ 8 ]  = te[8]; r[ 9 ]  = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11];
        r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15];

        return this;

    },

    multiplyScalar: function ( s ) {

        var te = this.elements;

        te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s;
        te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s;
        te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s;
        te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s;

        return this;

    },

    multiplyVector3: function ( v ) {

        var te = this.elements;

        var vx = v.x, vy = v.y, vz = v.z;
        var d = 1 / ( te[3] * vx + te[7] * vy + te[11] * vz + te[15] );

        v.x = ( te[0] * vx + te[4] * vy + te[8] * vz + te[12] ) * d;
        v.y = ( te[1] * vx + te[5] * vy + te[9] * vz + te[13] ) * d;
        v.z = ( te[2] * vx + te[6] * vy + te[10] * vz + te[14] ) * d;

        return v;

    },

    multiplyVector4: function ( v ) {

        var te = this.elements;
        var vx = v.x, vy = v.y, vz = v.z, vw = v.w;

        v.x = te[0] * vx + te[4] * vy + te[8] * vz + te[12] * vw;
        v.y = te[1] * vx + te[5] * vy + te[9] * vz + te[13] * vw;
        v.z = te[2] * vx + te[6] * vy + te[10] * vz + te[14] * vw;
        v.w = te[3] * vx + te[7] * vy + te[11] * vz + te[15] * vw;

        return v;

    },

    multiplyVector3Array: function ( a ) {

        var tmp = THREE.Matrix4.__v1;

        for ( var i = 0, il = a.length; i < il; i += 3 ) {

            tmp.x = a[ i ];
            tmp.y = a[ i + 1 ];
            tmp.z = a[ i + 2 ];

            this.multiplyVector3( tmp );

            a[ i ]     = tmp.x;
            a[ i + 1 ] = tmp.y;
            a[ i + 2 ] = tmp.z;

        }

        return a;

    },

    rotateAxis: function ( v ) {

        var te = this.elements;
        var vx = v.x, vy = v.y, vz = v.z;

        v.x = vx * te[0] + vy * te[4] + vz * te[8];
        v.y = vx * te[1] + vy * te[5] + vz * te[9];
        v.z = vx * te[2] + vy * te[6] + vz * te[10];

        v.normalize();

        return v;

    },

    crossVector: function ( a ) {

        var te = this.elements;
        var v = new THREE.Vector4();

        v.x = te[0] * a.x + te[4] * a.y + te[8] * a.z + te[12] * a.w;
        v.y = te[1] * a.x + te[5] * a.y + te[9] * a.z + te[13] * a.w;
        v.z = te[2] * a.x + te[6] * a.y + te[10] * a.z + te[14] * a.w;

        v.w = ( a.w ) ? te[3] * a.x + te[7] * a.y + te[11] * a.z + te[15] * a.w : 1;

        return v;

    },

    determinant: function () {

        var te = this.elements;

        var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12];
        var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13];
        var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14];
        var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15];

        //TODO: make this more efficient
        //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )

        return (
            n14 * n23 * n32 * n41-
            n13 * n24 * n32 * n41-
            n14 * n22 * n33 * n41+
            n12 * n24 * n33 * n41+

            n13 * n22 * n34 * n41-
            n12 * n23 * n34 * n41-
            n14 * n23 * n31 * n42+
            n13 * n24 * n31 * n42+

            n14 * n21 * n33 * n42-
            n11 * n24 * n33 * n42-
            n13 * n21 * n34 * n42+
            n11 * n23 * n34 * n42+

            n14 * n22 * n31 * n43-
            n12 * n24 * n31 * n43-
            n14 * n21 * n32 * n43+
            n11 * n24 * n32 * n43+

            n12 * n21 * n34 * n43-
            n11 * n22 * n34 * n43-
            n13 * n22 * n31 * n44+
            n12 * n23 * n31 * n44+

            n13 * n21 * n32 * n44-
            n11 * n23 * n32 * n44-
            n12 * n21 * n33 * n44+
            n11 * n22 * n33 * n44
        );

    },

    transpose: function () {

        var te = this.elements;
        var tmp;

        tmp = te[1]; te[1] = te[4]; te[4] = tmp;
        tmp = te[2]; te[2] = te[8]; te[8] = tmp;
        tmp = te[6]; te[6] = te[9]; te[9] = tmp;

        tmp = te[3]; te[3] = te[12]; te[12] = tmp;
        tmp = te[7]; te[7] = te[13]; te[13] = tmp;
        tmp = te[11]; te[11] = te[14]; te[14] = tmp;

        return this;

    },

    flattenToArray: function ( flat ) {

        var te = this.elements;
        flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3];
        flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7];
        flat[ 8 ]  = te[8]; flat[ 9 ]  = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11];
        flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15];

        return flat;

    },

    flattenToArrayOffset: function( flat, offset ) {

        var te = this.elements;
        flat[ offset ] = te[0];
        flat[ offset + 1 ] = te[1];
        flat[ offset + 2 ] = te[2];
        flat[ offset + 3 ] = te[3];

        flat[ offset + 4 ] = te[4];
        flat[ offset + 5 ] = te[5];
        flat[ offset + 6 ] = te[6];
        flat[ offset + 7 ] = te[7];

        flat[ offset + 8 ]  = te[8];
        flat[ offset + 9 ]  = te[9];
        flat[ offset + 10 ] = te[10];
        flat[ offset + 11 ] = te[11];

        flat[ offset + 12 ] = te[12];
        flat[ offset + 13 ] = te[13];
        flat[ offset + 14 ] = te[14];
        flat[ offset + 15 ] = te[15];

        return flat;

    },

    getPosition: function () {

        var te = this.elements;
        return THREE.Matrix4.__v1.set( te[12], te[13], te[14] );

    },

    setPosition: function ( v ) {

        var te = this.elements;

        te[12] = v.x;
        te[13] = v.y;
        te[14] = v.z;

        return this;

    },

    getColumnX: function () {

        var te = this.elements;
        return THREE.Matrix4.__v1.set( te[0], te[1], te[2] );

    },

    getColumnY: function () {

        var te = this.elements;
        return THREE.Matrix4.__v1.set( te[4], te[5], te[6] );

    },

    getColumnZ: function() {

        var te = this.elements;
        return THREE.Matrix4.__v1.set( te[8], te[9], te[10] );

    },

    getInverse: function ( m ) {

        // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
        var te = this.elements;
        var me = m.elements;

        var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12];
        var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13];
        var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14];
        var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15];

        te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44;
        te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44;
        te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44;
        te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34;
        te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44;
        te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44;
        te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44;
        te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34;
        te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44;
        te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44;
        te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44;
        te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34;
        te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43;
        te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43;
        te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43;
        te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33;
        this.multiplyScalar( 1 / m.determinant() );

        return this;

    },

    setRotationFromEuler: function ( v, order ) {

        var te = this.elements;

        var x = v.x, y = v.y, z = v.z;
        var a = Math.cos( x ), b = Math.sin( x );
        var c = Math.cos( y ), d = Math.sin( y );
        var e = Math.cos( z ), f = Math.sin( z );

        if ( order === undefined || order === 'XYZ' ) {

            var ae = a * e, af = a * f, be = b * e, bf = b * f;

            te[0] = c * e;
            te[4] = - c * f;
            te[8] = d;

            te[1] = af + be * d;
            te[5] = ae - bf * d;
            te[9] = - b * c;

            te[2] = bf - ae * d;
            te[6] = be + af * d;
            te[10] = a * c;

        } else if ( order === 'YXZ' ) {

            var ce = c * e, cf = c * f, de = d * e, df = d * f;

            te[0] = ce + df * b;
            te[4] = de * b - cf;
            te[8] = a * d;

            te[1] = a * f;
            te[5] = a * e;
            te[9] = - b;

            te[2] = cf * b - de;
            te[6] = df + ce * b;
            te[10] = a * c;

        } else if ( order === 'ZXY' ) {

            var ce = c * e, cf = c * f, de = d * e, df = d * f;

            te[0] = ce - df * b;
            te[4] = - a * f;
            te[8] = de + cf * b;

            te[1] = cf + de * b;
            te[5] = a * e;
            te[9] = df - ce * b;

            te[2] = - a * d;
            te[6] = b;
            te[10] = a * c;

        } else if ( order === 'ZYX' ) {

            var ae = a * e, af = a * f, be = b * e, bf = b * f;

            te[0] = c * e;
            te[4] = be * d - af;
            te[8] = ae * d + bf;

            te[1] = c * f;
            te[5] = bf * d + ae;
            te[9] = af * d - be;

            te[2] = - d;
            te[6] = b * c;
            te[10] = a * c;

        } else if ( order === 'YZX' ) {

            var ac = a * c, ad = a * d, bc = b * c, bd = b * d;

            te[0] = c * e;
            te[4] = bd - ac * f;
            te[8] = bc * f + ad;

            te[1] = f;
            te[5] = a * e;
            te[9] = - b * e;

            te[2] = - d * e;
            te[6] = ad * f + bc;
            te[10] = ac - bd * f;

        } else if ( order === 'XZY' ) {

            var ac = a * c, ad = a * d, bc = b * c, bd = b * d;

            te[0] = c * e;
            te[4] = - f;
            te[8] = d * e;

            te[1] = ac * f + bd;
            te[5] = a * e;
            te[9] = ad * f - bc;

            te[2] = bc * f - ad;
            te[6] = b * e;
            te[10] = bd * f + ac;

        }

        return this;

    },


    setRotationFromQuaternion: function ( q ) {

        var te = this.elements;

        var x = q.x, y = q.y, z = q.z, w = q.w;
        var x2 = x + x, y2 = y + y, z2 = z + z;
        var xx = x * x2, xy = x * y2, xz = x * z2;
        var yy = y * y2, yz = y * z2, zz = z * z2;
        var wx = w * x2, wy = w * y2, wz = w * z2;

        te[0] = 1 - ( yy + zz );
        te[4] = xy - wz;
        te[8] = xz + wy;

        te[1] = xy + wz;
        te[5] = 1 - ( xx + zz );
        te[9] = yz - wx;

        te[2] = xz - wy;
        te[6] = yz + wx;
        te[10] = 1 - ( xx + yy );

        return this;

    },

    compose: function ( translation, rotation, scale ) {

        var te = this.elements;
        var mRotation = THREE.Matrix4.__m1;
        var mScale = THREE.Matrix4.__m2;

        mRotation.identity();
        mRotation.setRotationFromQuaternion( rotation );

        mScale.makeScale( scale.x, scale.y, scale.z );

        this.multiply( mRotation, mScale );

        te[12] = translation.x;
        te[13] = translation.y;
        te[14] = translation.z;

        return this;

    },

    decompose: function ( translation, rotation, scale ) {

        var te = this.elements;

        // grab the axis vectors
        var x = THREE.Matrix4.__v1;
        var y = THREE.Matrix4.__v2;
        var z = THREE.Matrix4.__v3;

        x.set( te[0], te[1], te[2] );
        y.set( te[4], te[5], te[6] );
        z.set( te[8], te[9], te[10] );

        translation = ( translation instanceof THREE.Vector3 ) ? translation : new THREE.Vector3();
        rotation = ( rotation instanceof THREE.Quaternion ) ? rotation : new THREE.Quaternion();
        scale = ( scale instanceof THREE.Vector3 ) ? scale : new THREE.Vector3();

        scale.x = x.length();
        scale.y = y.length();
        scale.z = z.length();

        translation.x = te[12];
        translation.y = te[13];
        translation.z = te[14];

        // scale the rotation part

        var matrix = THREE.Matrix4.__m1;

        matrix.copy( this );

        matrix.elements[0] /= scale.x;
        matrix.elements[1] /= scale.x;
        matrix.elements[2] /= scale.x;

        matrix.elements[4] /= scale.y;
        matrix.elements[5] /= scale.y;
        matrix.elements[6] /= scale.y;

        matrix.elements[8] /= scale.z;
        matrix.elements[9] /= scale.z;
        matrix.elements[10] /= scale.z;

        rotation.setFromRotationMatrix( matrix );

        return [ translation, rotation, scale ];

    },

    extractPosition: function ( m ) {

        var te = this.elements;
        var me = m.elements;

        te[12] = me[12];
        te[13] = me[13];
        te[14] = me[14];

        return this;

    },

    extractRotation: function ( m ) {

        var te = this.elements;
        var me = m.elements;

        var vector = THREE.Matrix4.__v1;

        var scaleX = 1 / vector.set( me[0], me[1], me[2] ).length();
        var scaleY = 1 / vector.set( me[4], me[5], me[6] ).length();
        var scaleZ = 1 / vector.set( me[8], me[9], me[10] ).length();

        te[0] = me[0] * scaleX;
        te[1] = me[1] * scaleX;
        te[2] = me[2] * scaleX;

        te[4] = me[4] * scaleY;
        te[5] = me[5] * scaleY;
        te[6] = me[6] * scaleY;

        te[8] = me[8] * scaleZ;
        te[9] = me[9] * scaleZ;
        te[10] = me[10] * scaleZ;

        return this;

    },

    //

    translate: function ( v ) {

        var te = this.elements;
        var x = v.x, y = v.y, z = v.z;

        te[12] = te[0] * x + te[4] * y + te[8] * z + te[12];
        te[13] = te[1] * x + te[5] * y + te[9] * z + te[13];
        te[14] = te[2] * x + te[6] * y + te[10] * z + te[14];
        te[15] = te[3] * x + te[7] * y + te[11] * z + te[15];

        return this;

    },

    rotateX: function ( angle ) {

        var te = this.elements;
        var m12 = te[4];
        var m22 = te[5];
        var m32 = te[6];
        var m42 = te[7];
        var m13 = te[8];
        var m23 = te[9];
        var m33 = te[10];
        var m43 = te[11];
        var c = Math.cos( angle );
        var s = Math.sin( angle );

        te[4] = c * m12 + s * m13;
        te[5] = c * m22 + s * m23;
        te[6] = c * m32 + s * m33;
        te[7] = c * m42 + s * m43;

        te[8] = c * m13 - s * m12;
        te[9] = c * m23 - s * m22;
        te[10] = c * m33 - s * m32;
        te[11] = c * m43 - s * m42;

        return this;

    },

    rotateY: function ( angle ) {

        var te = this.elements;
        var m11 = te[0];
        var m21 = te[1];
        var m31 = te[2];
        var m41 = te[3];
        var m13 = te[8];
        var m23 = te[9];
        var m33 = te[10];
        var m43 = te[11];
        var c = Math.cos( angle );
        var s = Math.sin( angle );

        te[0] = c * m11 - s * m13;
        te[1] = c * m21 - s * m23;
        te[2] = c * m31 - s * m33;
        te[3] = c * m41 - s * m43;

        te[8] = c * m13 + s * m11;
        te[9] = c * m23 + s * m21;
        te[10] = c * m33 + s * m31;
        te[11] = c * m43 + s * m41;

        return this;

    },

    rotateZ: function ( angle ) {

        var te = this.elements;
        var m11 = te[0];
        var m21 = te[1];
        var m31 = te[2];
        var m41 = te[3];
        var m12 = te[4];
        var m22 = te[5];
        var m32 = te[6];
        var m42 = te[7];
        var c = Math.cos( angle );
        var s = Math.sin( angle );

        te[0] = c * m11 + s * m12;
        te[1] = c * m21 + s * m22;
        te[2] = c * m31 + s * m32;
        te[3] = c * m41 + s * m42;

        te[4] = c * m12 - s * m11;
        te[5] = c * m22 - s * m21;
        te[6] = c * m32 - s * m31;
        te[7] = c * m42 - s * m41;

        return this;

    },

    rotateByAxis: function ( axis, angle ) {

        var te = this.elements;

        // optimize by checking axis

        if ( axis.x === 1 && axis.y === 0 && axis.z === 0 ) {

            return this.rotateX( angle );

        } else if ( axis.x === 0 && axis.y === 1 && axis.z === 0 ) {

            return this.rotateY( angle );

        } else if ( axis.x === 0 && axis.y === 0 && axis.z === 1 ) {

            return this.rotateZ( angle );

        }

        var x = axis.x, y = axis.y, z = axis.z;
        var n = Math.sqrt(x * x + y * y + z * z);

        x /= n;
        y /= n;
        z /= n;

        var xx = x * x, yy = y * y, zz = z * z;
        var c = Math.cos( angle );
        var s = Math.sin( angle );
        var oneMinusCosine = 1 - c;
        var xy = x * y * oneMinusCosine;
        var xz = x * z * oneMinusCosine;
        var yz = y * z * oneMinusCosine;
        var xs = x * s;
        var ys = y * s;
        var zs = z * s;

        var r11 = xx + (1 - xx) * c;
        var r21 = xy + zs;
        var r31 = xz - ys;
        var r12 = xy - zs;
        var r22 = yy + (1 - yy) * c;
        var r32 = yz + xs;
        var r13 = xz + ys;
        var r23 = yz - xs;
        var r33 = zz + (1 - zz) * c;

        var m11 = te[0], m21 = te[1], m31 = te[2], m41 = te[3];
        var m12 = te[4], m22 = te[5], m32 = te[6], m42 = te[7];
        var m13 = te[8], m23 = te[9], m33 = te[10], m43 = te[11];
        var m14 = te[12], m24 = te[13], m34 = te[14], m44 = te[15];

        te[0] = r11 * m11 + r21 * m12 + r31 * m13;
        te[1] = r11 * m21 + r21 * m22 + r31 * m23;
        te[2] = r11 * m31 + r21 * m32 + r31 * m33;
        te[3] = r11 * m41 + r21 * m42 + r31 * m43;

        te[4] = r12 * m11 + r22 * m12 + r32 * m13;
        te[5] = r12 * m21 + r22 * m22 + r32 * m23;
        te[6] = r12 * m31 + r22 * m32 + r32 * m33;
        te[7] = r12 * m41 + r22 * m42 + r32 * m43;

        te[8] = r13 * m11 + r23 * m12 + r33 * m13;
        te[9] = r13 * m21 + r23 * m22 + r33 * m23;
        te[10] = r13 * m31 + r23 * m32 + r33 * m33;
        te[11] = r13 * m41 + r23 * m42 + r33 * m43;

        return this;

    },

    scale: function ( v ) {

        var te = this.elements;
        var x = v.x, y = v.y, z = v.z;

        te[0] *= x; te[4] *= y; te[8] *= z;
        te[1] *= x; te[5] *= y; te[9] *= z;
        te[2] *= x; te[6] *= y; te[10] *= z;
        te[3] *= x; te[7] *= y; te[11] *= z;

        return this;

    },

    getMaxScaleOnAxis: function () {

        var te = this.elements;

        var scaleXSq =  te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
        var scaleYSq =  te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
        var scaleZSq =  te[8] * te[8] + te[9] * te[9] + te[10] * te[10];

        return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) );

    },

    //

    makeTranslation: function ( x, y, z ) {

        this.set(

            1, 0, 0, x,
            0, 1, 0, y,
            0, 0, 1, z,
            0, 0, 0, 1

        );

        return this;

    },

    makeRotationX: function ( theta ) {

        var c = Math.cos( theta ), s = Math.sin( theta );

        this.set(

            1, 0,  0, 0,
            0, c, -s, 0,
            0, s,  c, 0,
            0, 0,  0, 1

        );

        return this;

    },

    makeRotationY: function ( theta ) {

        var c = Math.cos( theta ), s = Math.sin( theta );

        this.set(

             c, 0, s, 0,
             0, 1, 0, 0,
            -s, 0, c, 0,
             0, 0, 0, 1

        );

        return this;

    },

    makeRotationZ: function ( theta ) {

        var c = Math.cos( theta ), s = Math.sin( theta );

        this.set(

            c, -s, 0, 0,
            s,  c, 0, 0,
            0,  0, 1, 0,
            0,  0, 0, 1

        );

        return this;

    },

    makeRotationAxis: function ( axis, angle ) {

        // Based on http://www.gamedev.net/reference/articles/article1199.asp

        var c = Math.cos( angle );
        var s = Math.sin( angle );
        var t = 1 - c;
        var x = axis.x, y = axis.y, z = axis.z;
        var tx = t * x, ty = t * y;

        this.set(

            tx * x + c, tx * y - s * z, tx * z + s * y, 0,
            tx * y + s * z, ty * y + c, ty * z - s * x, 0,
            tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
            0, 0, 0, 1

        );

         return this;

    },

    makeScale: function ( x, y, z ) {

        this.set(

            x, 0, 0, 0,
            0, y, 0, 0,
            0, 0, z, 0,
            0, 0, 0, 1

        );

        return this;

    },

    makeFrustum: function ( left, right, bottom, top, near, far ) {

        var te = this.elements;
        var x = 2 * near / ( right - left );
        var y = 2 * near / ( top - bottom );

        var a = ( right + left ) / ( right - left );
        var b = ( top + bottom ) / ( top - bottom );
        var c = - ( far + near ) / ( far - near );
        var d = - 2 * far * near / ( far - near );

        te[0] = x;  te[4] = 0;  te[8] = a;   te[12] = 0;
        te[1] = 0;  te[5] = y;  te[9] = b;   te[13] = 0;
        te[2] = 0;  te[6] = 0;  te[10] = c;   te[14] = d;
        te[3] = 0;  te[7] = 0;  te[11] = - 1; te[15] = 0;

        return this;

    },

    makePerspective: function ( fov, aspect, near, far ) {

        var ymax = near * Math.tan( fov * Math.PI / 360 );
        var ymin = - ymax;
        var xmin = ymin * aspect;
        var xmax = ymax * aspect;

        return this.makeFrustum( xmin, xmax, ymin, ymax, near, far );

    },

    makeOrthographic: function ( left, right, top, bottom, near, far ) {

        var te = this.elements;
        var w = right - left;
        var h = top - bottom;
        var p = far - near;

        var x = ( right + left ) / w;
        var y = ( top + bottom ) / h;
        var z = ( far + near ) / p;

        te[0] = 2 / w; te[4] = 0;     te[8] = 0;      te[12] = -x;
        te[1] = 0;     te[5] = 2 / h; te[9] = 0;      te[13] = -y;
        te[2] = 0;     te[6] = 0;     te[10] = -2 / p; te[14] = -z;
        te[3] = 0;     te[7] = 0;     te[11] = 0;      te[15] = 1;

        return this;

    },


    clone: function () {

        var te = this.elements;

        return new THREE.Matrix4(

            te[0], te[4], te[8], te[12],
            te[1], te[5], te[9], te[13],
            te[2], te[6], te[10], te[14],
            te[3], te[7], te[11], te[15]

        );

    }

};

THREE.Matrix4.__v1 = new THREE.Vector3();
THREE.Matrix4.__v2 = new THREE.Vector3();
THREE.Matrix4.__v3 = new THREE.Vector3();

THREE.Matrix4.__m1 = new THREE.Matrix4();
THREE.Matrix4.__m2 = new THREE.Matrix4();
/**
 * https://github.com/mrdoob/eventtarget.js/
 */

THREE.EventTarget = function () {

    var listeners = {};

    this.addEventListener = function ( type, listener ) {

        if ( listeners[ type ] === undefined ) {

            listeners[ type ] = [];

        }

        if ( listeners[ type ].indexOf( listener ) === - 1 ) {

            listeners[ type ].push( listener );

        }

    };

    this.dispatchEvent = function ( event ) {

        for ( var listener in listeners[ event.type ] ) {

            listeners[ event.type ][ listener ]( event );

        }

    };

    this.removeEventListener = function ( type, listener ) {

        var index = listeners[ type ].indexOf( listener );

        if ( index !== - 1 ) {

            listeners[ type ].splice( index, 1 );

        }

    };

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Frustum = function ( ) {

    this.planes = [

        new THREE.Vector4(),
        new THREE.Vector4(),
        new THREE.Vector4(),
        new THREE.Vector4(),
        new THREE.Vector4(),
        new THREE.Vector4()

    ];

};

THREE.Frustum.prototype.setFromMatrix = function ( m ) {

    var plane;
    var planes = this.planes;

    var me = m.elements;
    var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
    var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
    var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
    var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];

    planes[ 0 ].set( me3 - me0, me7 - me4, me11 - me8, me15 - me12 );
    planes[ 1 ].set( me3 + me0, me7 + me4, me11 + me8, me15 + me12 );
    planes[ 2 ].set( me3 + me1, me7 + me5, me11 + me9, me15 + me13 );
    planes[ 3 ].set( me3 - me1, me7 - me5, me11 - me9, me15 - me13 );
    planes[ 4 ].set( me3 - me2, me7 - me6, me11 - me10, me15 - me14 );
    planes[ 5 ].set( me3 + me2, me7 + me6, me11 + me10, me15 + me14 );

    for ( var i = 0; i < 6; i ++ ) {

        plane = planes[ i ];
        plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) );

    }

};

THREE.Frustum.prototype.contains = function ( object ) {

    var distance = 0.0;
    var planes = this.planes;
    var matrix = object.matrixWorld;
    var me = matrix.elements;
    var radius = - object.geometry.boundingSphere.radius * matrix.getMaxScaleOnAxis();

    for ( var i = 0; i < 6; i ++ ) {

        distance = planes[ i ].x * me[12] + planes[ i ].y * me[13] + planes[ i ].z * me[14] + planes[ i ].w;
        if ( distance <= radius ) return false;

    }

    return true;

};

THREE.Frustum.__v1 = new THREE.Vector3();
/**
 * @author mrdoob / http://mrdoob.com/
 */

( function ( THREE ) {

    THREE.Ray = function ( origin, direction, near, far ) {

        this.origin = origin || new THREE.Vector3();
        this.direction = direction || new THREE.Vector3();
        this.near = near || 0;
        this.far = far || Infinity;

    };

    var originCopy = new THREE.Vector3();

    var localOriginCopy = new THREE.Vector3();
    var localDirectionCopy = new THREE.Vector3();

    var vector = new THREE.Vector3();
    var normal = new THREE.Vector3();
    var intersectPoint = new THREE.Vector3();

    var inverseMatrix = new THREE.Matrix4();

    var descSort = function ( a, b ) {

        return a.distance - b.distance;

    };

    var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3();

    var distanceFromIntersection = function ( origin, direction, position ) {

        v0.sub( position, origin );

        var dot = v0.dot( direction );

        var intersect = v1.add( origin, v2.copy( direction ).multiplyScalar( dot ) );
        var distance = position.distanceTo( intersect );

        return distance;

    };

    // http://www.blackpawn.com/texts/pointinpoly/default.html

    var pointInFace3 = function ( p, a, b, c ) {

        v0.sub( c, a );
        v1.sub( b, a );
        v2.sub( p, a );

        var dot00 = v0.dot( v0 );
        var dot01 = v0.dot( v1 );
        var dot02 = v0.dot( v2 );
        var dot11 = v1.dot( v1 );
        var dot12 = v1.dot( v2 );

        var invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
        var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
        var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;

        return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );

    };

    var intersectObject = function ( object, ray, intersects ) {

        var distance,intersect;

        if ( object instanceof THREE.Particle ) {

            distance = distanceFromIntersection( ray.origin, ray.direction, object.matrixWorld.getPosition() );

            if ( distance > object.scale.x ) {

                return intersects;

            }

            intersect = {

                distance: distance,
                point: object.position,
                face: null,
                object: object

            };

            intersects.push( intersect );

        } else if ( object instanceof THREE.Mesh ) {

            // Checking boundingSphere

            var scaledRadius = object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis();

            // Checking distance to ray

            distance = distanceFromIntersection( ray.origin, ray.direction, object.matrixWorld.getPosition() );

            if ( distance > scaledRadius) {

                return intersects;

            }

            // Checking faces

            var f, fl, face, dot, scalar,
            geometry = object.geometry,
            vertices = geometry.vertices,
            objMatrix, geometryMaterials,
            isFaceMaterial, material, side, point;

            geometryMaterials = object.geometry.materials;
            isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
            side = object.material.side;

            var a, b, c, d;
            var precision = ray.precision;

            object.matrixRotationWorld.extractRotation( object.matrixWorld );

            originCopy.copy( ray.origin );

            objMatrix = object.matrixWorld;
            inverseMatrix.getInverse( objMatrix );

            localOriginCopy.copy( originCopy );
            inverseMatrix.multiplyVector3( localOriginCopy );

            localDirectionCopy.copy( ray.direction );
            inverseMatrix.rotateAxis( localDirectionCopy ).normalize();

            for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

                face = geometry.faces[ f ];

                material = isFaceMaterial === true ? geometryMaterials[ face.materialIndex ] : object.material;
                if ( material === undefined ) continue;
                side = material.side;

                vector.sub( face.centroid, localOriginCopy );
                normal = face.normal;
                dot = localDirectionCopy.dot( normal );

                // bail if ray and plane are parallel

                if ( Math.abs( dot ) < precision ) continue;

                // calc distance to plane

                scalar = normal.dot( vector ) / dot;

                // if negative distance, then plane is behind ray

                if ( scalar < 0 ) continue;

                if ( side === THREE.DoubleSide || ( side === THREE.FrontSide ? dot < 0 : dot > 0 ) ) {

                    intersectPoint.add( localOriginCopy, localDirectionCopy.multiplyScalar( scalar ) );

                    if ( face instanceof THREE.Face3 ) {

                        a = vertices[ face.a ];
                        b = vertices[ face.b ];
                        c = vertices[ face.c ];

                        if ( pointInFace3( intersectPoint, a, b, c ) ) {

                            point = object.matrixWorld.multiplyVector3( intersectPoint.clone() );
                            distance = originCopy.distanceTo( point );

                            if ( distance < ray.near || distance > ray.far ) continue;

                            intersect = {

                                distance: distance,
                                point: point,
                                face: face,
                                faceIndex: f,
                                object: object

                            };

                            intersects.push( intersect );

                        }

                    } else if ( face instanceof THREE.Face4 ) {

                        a = vertices[ face.a ];
                        b = vertices[ face.b ];
                        c = vertices[ face.c ];
                        d = vertices[ face.d ];

                        if ( pointInFace3( intersectPoint, a, b, d ) || pointInFace3( intersectPoint, b, c, d ) ) {

                            point = object.matrixWorld.multiplyVector3( intersectPoint.clone() );
                            distance = originCopy.distanceTo( point );

                            if ( distance < ray.near || distance > ray.far ) continue;

                            intersect = {

                                distance: distance,
                                point: point,
                                face: face,
                                faceIndex: f,
                                object: object

                            };

                            intersects.push( intersect );

                        }

                    }

                }

            }

        }

    };

    var intersectDescendants = function ( object, ray, intersects ) {

        var descendants = object.getDescendants();

        for ( var i = 0, l = descendants.length; i < l; i ++ ) {

            intersectObject( descendants[ i ], ray, intersects );

        }
    };

    //

    THREE.Ray.prototype.precision = 0.0001;

    THREE.Ray.prototype.set = function ( origin, direction ) {

        this.origin = origin;
        this.direction = direction;

    };

    THREE.Ray.prototype.intersectObject = function ( object, recursive ) {

        var intersects = [];

        if ( recursive === true ) {

            intersectDescendants( object, this, intersects );

        }

        intersectObject( object, this, intersects );

        intersects.sort( descSort );

        return intersects;

    };

    THREE.Ray.prototype.intersectObjects = function ( objects, recursive ) {

        var intersects = [];

        for ( var i = 0, l = objects.length; i < l; i ++ ) {

            intersectObject( objects[ i ], this, intersects );

            if ( recursive === true ) {

                intersectDescendants( objects[ i ], this, intersects );

            }
        }

        intersects.sort( descSort );

        return intersects;

    };

}( THREE ) );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Rectangle = function () {

    var _left = 0;
    var _top = 0;
    var _right = 0;
    var _bottom = 0;
    var _width = 0;
    var _height = 0;
    var _isEmpty = true;

    function resize() {

        _width = _right - _left;
        _height = _bottom - _top;

    }

    this.getX = function () {

        return _left;

    };

    this.getY = function () {

        return _top;

    };

    this.getWidth = function () {

        return _width;

    };

    this.getHeight = function () {

        return _height;

    };

    this.getLeft = function() {

        return _left;

    };

    this.getTop = function() {

        return _top;

    };

    this.getRight = function() {

        return _right;

    };

    this.getBottom = function() {

        return _bottom;

    };

    this.set = function ( left, top, right, bottom ) {

        _isEmpty = false;

        _left = left; _top = top;
        _right = right; _bottom = bottom;

        resize();

    };

    this.addPoint = function ( x, y ) {

        if ( _isEmpty === true ) {

            _isEmpty = false;
            _left = x; _top = y;
            _right = x; _bottom = y;

            resize();

        } else {

            _left = _left < x ? _left : x; // Math.min( _left, x );
            _top = _top < y ? _top : y; // Math.min( _top, y );
            _right = _right > x ? _right : x; // Math.max( _right, x );
            _bottom = _bottom > y ? _bottom : y; // Math.max( _bottom, y );

            resize();
        }

    };

    this.add3Points = function ( x1, y1, x2, y2, x3, y3 ) {

        if ( _isEmpty === true ) {

            _isEmpty = false;
            _left = x1 < x2 ? ( x1 < x3 ? x1 : x3 ) : ( x2 < x3 ? x2 : x3 );
            _top = y1 < y2 ? ( y1 < y3 ? y1 : y3 ) : ( y2 < y3 ? y2 : y3 );
            _right = x1 > x2 ? ( x1 > x3 ? x1 : x3 ) : ( x2 > x3 ? x2 : x3 );
            _bottom = y1 > y2 ? ( y1 > y3 ? y1 : y3 ) : ( y2 > y3 ? y2 : y3 );

            resize();

        } else {

            _left = x1 < x2 ? ( x1 < x3 ? ( x1 < _left ? x1 : _left ) : ( x3 < _left ? x3 : _left ) ) : ( x2 < x3 ? ( x2 < _left ? x2 : _left ) : ( x3 < _left ? x3 : _left ) );
            _top = y1 < y2 ? ( y1 < y3 ? ( y1 < _top ? y1 : _top ) : ( y3 < _top ? y3 : _top ) ) : ( y2 < y3 ? ( y2 < _top ? y2 : _top ) : ( y3 < _top ? y3 : _top ) );
            _right = x1 > x2 ? ( x1 > x3 ? ( x1 > _right ? x1 : _right ) : ( x3 > _right ? x3 : _right ) ) : ( x2 > x3 ? ( x2 > _right ? x2 : _right ) : ( x3 > _right ? x3 : _right ) );
            _bottom = y1 > y2 ? ( y1 > y3 ? ( y1 > _bottom ? y1 : _bottom ) : ( y3 > _bottom ? y3 : _bottom ) ) : ( y2 > y3 ? ( y2 > _bottom ? y2 : _bottom ) : ( y3 > _bottom ? y3 : _bottom ) );

            resize();

        };

    };

    this.addRectangle = function ( r ) {

        if ( _isEmpty === true ) {

            _isEmpty = false;
            _left = r.getLeft(); _top = r.getTop();
            _right = r.getRight(); _bottom = r.getBottom();

            resize();

        } else {

            _left = _left < r.getLeft() ? _left : r.getLeft(); // Math.min(_left, r.getLeft() );
            _top = _top < r.getTop() ? _top : r.getTop(); // Math.min(_top, r.getTop() );
            _right = _right > r.getRight() ? _right : r.getRight(); // Math.max(_right, r.getRight() );
            _bottom = _bottom > r.getBottom() ? _bottom : r.getBottom(); // Math.max(_bottom, r.getBottom() );

            resize();

        }

    };

    this.inflate = function ( v ) {

        _left -= v; _top -= v;
        _right += v; _bottom += v;

        resize();

    };

    this.minSelf = function ( r ) {

        _left = _left > r.getLeft() ? _left : r.getLeft(); // Math.max( _left, r.getLeft() );
        _top = _top > r.getTop() ? _top : r.getTop(); // Math.max( _top, r.getTop() );
        _right = _right < r.getRight() ? _right : r.getRight(); // Math.min( _right, r.getRight() );
        _bottom = _bottom < r.getBottom() ? _bottom : r.getBottom(); // Math.min( _bottom, r.getBottom() );

        resize();

    };

    this.intersects = function ( r ) {

        // http://gamemath.com/2011/09/detecting-whether-two-boxes-overlap/

        if ( _right < r.getLeft() ) return false;
        if ( _left > r.getRight() ) return false;
        if ( _bottom < r.getTop() ) return false;
        if ( _top > r.getBottom() ) return false;

        return true;

    };

    this.empty = function () {

        _isEmpty = true;

        _left = 0; _top = 0;
        _right = 0; _bottom = 0;

        resize();

    };

    this.isEmpty = function () {

        return _isEmpty;

    };

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Math = {

    // Clamp value to range <a, b>

    clamp: function ( x, a, b ) {

        return ( x < a ) ? a : ( ( x > b ) ? b : x );

    },

    // Clamp value to range <a, inf)

    clampBottom: function ( x, a ) {

        return x < a ? a : x;

    },

    // Linear mapping from range <a1, a2> to range <b1, b2>

    mapLinear: function ( x, a1, a2, b1, b2 ) {

        return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );

    },

    // Random float from <0, 1> with 16 bits of randomness
    // (standard Math.random() creates repetitive patterns when applied over larger space)

    random16: function () {

        return ( 65280 * Math.random() + 255 * Math.random() ) / 65535;

    },

    // Random integer from <low, high> interval

    randInt: function ( low, high ) {

        return low + Math.floor( Math.random() * ( high - low + 1 ) );

    },

    // Random float from <low, high> interval

    randFloat: function ( low, high ) {

        return low + Math.random() * ( high - low );

    },

    // Random float from <-range/2, range/2> interval

    randFloatSpread: function ( range ) {

        return range * ( 0.5 - Math.random() );

    },

    sign: function ( x ) {

        return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 );

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Object3D = function () {

    this.id = THREE.Object3DCount ++;

    this.name = '';
    this.properties = {};

    this.parent = undefined;
    this.children = [];

    this.up = new THREE.Vector3( 0, 1, 0 );

    this.position = new THREE.Vector3();
    this.rotation = new THREE.Vector3();
    this.eulerOrder = 'XYZ';
    this.scale = new THREE.Vector3( 1, 1, 1 );

    this.renderDepth = null;

    this.rotationAutoUpdate = true;

    this.matrix = new THREE.Matrix4();
    this.matrixWorld = new THREE.Matrix4();
    this.matrixRotationWorld = new THREE.Matrix4();

    this.matrixAutoUpdate = true;
    this.matrixWorldNeedsUpdate = true;

    this.quaternion = new THREE.Quaternion();
    this.useQuaternion = false;

    this.boundRadius = 0.0;
    this.boundRadiusScale = 1.0;

    this.visible = true;

    this.castShadow = false;
    this.receiveShadow = false;

    this.frustumCulled = true;

    this._vector = new THREE.Vector3();

};


THREE.Object3D.prototype = {

    constructor: THREE.Object3D,

    applyMatrix: function ( matrix ) {

        this.matrix.multiply( matrix, this.matrix );

        this.scale.getScaleFromMatrix( this.matrix );

        var mat = new THREE.Matrix4().extractRotation( this.matrix );
        this.rotation.setEulerFromRotationMatrix( mat, this.eulerOrder );

        this.position.getPositionFromMatrix( this.matrix );

    },

    translate: function ( distance, axis ) {

        this.matrix.rotateAxis( axis );
        this.position.addSelf( axis.multiplyScalar( distance ) );

    },

    translateX: function ( distance ) {

        this.translate( distance, this._vector.set( 1, 0, 0 ) );

    },

    translateY: function ( distance ) {

        this.translate( distance, this._vector.set( 0, 1, 0 ) );

    },

    translateZ: function ( distance ) {

        this.translate( distance, this._vector.set( 0, 0, 1 ) );

    },

    localToWorld: function ( vector ) {

        return this.matrixWorld.multiplyVector3( vector );

    },

    worldToLocal: function ( vector ) {

        return THREE.Object3D.__m1.getInverse( this.matrixWorld ).multiplyVector3( vector );

    },

    lookAt: function ( vector ) {

        // TODO: Add hierarchy support.

        this.matrix.lookAt( vector, this.position, this.up );

        if ( this.rotationAutoUpdate ) {

            this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );

        }

    },

    add: function ( object ) {

        if ( object === this ) {

            console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' );
            return;

        }

        if ( object instanceof THREE.Object3D ) {

            if ( object.parent !== undefined ) {

                object.parent.remove( object );

            }

            object.parent = this;
            this.children.push( object );

            // add to scene

            var scene = this;

            while ( scene.parent !== undefined ) {

                scene = scene.parent;

            }

            if ( scene !== undefined && scene instanceof THREE.Scene )  {

                scene.__addObject( object );

            }

        }

    },

    remove: function ( object ) {

        var index = this.children.indexOf( object );

        if ( index !== - 1 ) {

            object.parent = undefined;
            this.children.splice( index, 1 );

            // remove from scene

            var scene = this;

            while ( scene.parent !== undefined ) {

                scene = scene.parent;

            }

            if ( scene !== undefined && scene instanceof THREE.Scene ) {

                scene.__removeObject( object );

            }

        }

    },

    getChildByName: function ( name, recursive ) {

        var c, cl, child;

        for ( c = 0, cl = this.children.length; c < cl; c ++ ) {

            child = this.children[ c ];

            if ( child.name === name ) {

                return child;

            }

            if ( recursive ) {

                child = child.getChildByName( name, recursive );

                if ( child !== undefined ) {

                    return child;

                }

            }

        }

        return undefined;

    },

    getDescendants: function ( array ) {

        if ( array === undefined ) array = [];

        Array.prototype.push.apply( array, this.children );

        for ( var i = 0, l = this.children.length; i < l; i ++ ) {

            this.children[ i ].getDescendants( array );

        };

        return array;

    },

    updateMatrix: function () {

        this.matrix.setPosition( this.position );

        if ( this.useQuaternion === false )  {

            this.matrix.setRotationFromEuler( this.rotation, this.eulerOrder );

        } else {

            this.matrix.setRotationFromQuaternion( this.quaternion );

        }

        if ( this.scale.x !== 1 || this.scale.y !== 1 || this.scale.z !== 1 ) {

            this.matrix.scale( this.scale );
            this.boundRadiusScale = Math.max( this.scale.x, Math.max( this.scale.y, this.scale.z ) );

        }

        this.matrixWorldNeedsUpdate = true;

    },

    updateMatrixWorld: function ( force ) {

        if ( this.matrixAutoUpdate === true ) this.updateMatrix();

        if ( this.matrixWorldNeedsUpdate === true || force === true ) {

            if ( this.parent === undefined ) {

                this.matrixWorld.copy( this.matrix );

            } else {

                this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix );

            }

            this.matrixWorldNeedsUpdate = false;

            force = true;

        }

        // update children

        for ( var i = 0, l = this.children.length; i < l; i ++ ) {

            this.children[ i ].updateMatrixWorld( force );

        }

    },

    clone: function () {

        // TODO

    }

};

THREE.Object3D.__m1 = new THREE.Matrix4();

THREE.Object3DCount = 0;
/**
 * @author mrdoob / http://mrdoob.com/
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author julianwa / https://github.com/julianwa
 */

THREE.Projector = function() {

    var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
    _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
    _face, _face3Count, _face3Pool = [], _face3PoolLength = 0,
    _face4Count, _face4Pool = [], _face4PoolLength = 0,
    _line, _lineCount, _linePool = [], _linePoolLength = 0,
    _particle, _particleCount, _particlePool = [], _particlePoolLength = 0,

    _renderData = { objects: [], sprites: [], lights: [], elements: [] },

    _vector3 = new THREE.Vector3(),
    _vector4 = new THREE.Vector4(),

    _viewProjectionMatrix = new THREE.Matrix4(),
    _modelViewProjectionMatrix = new THREE.Matrix4(),

    _frustum = new THREE.Frustum(),

    _clippedVertex1PositionScreen = new THREE.Vector4(),
    _clippedVertex2PositionScreen = new THREE.Vector4(),

    _face3VertexNormals;

    this.projectVector = function ( vector, camera ) {

        camera.matrixWorldInverse.getInverse( camera.matrixWorld );

        _viewProjectionMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
        _viewProjectionMatrix.multiplyVector3( vector );

        return vector;

    };

    this.unprojectVector = function ( vector, camera ) {

        camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );

        _viewProjectionMatrix.multiply( camera.matrixWorld, camera.projectionMatrixInverse );
        _viewProjectionMatrix.multiplyVector3( vector );

        return vector;

    };

    this.pickingRay = function ( vector, camera ) {

        var end, ray, t;

        // set two vectors with opposing z values
        vector.z = -1.0;
        end = new THREE.Vector3( vector.x, vector.y, 1.0 );

        this.unprojectVector( vector, camera );
        this.unprojectVector( end, camera );

        // find direction from vector to end
        end.subSelf( vector ).normalize();

        return new THREE.Ray( vector, end );

    };

    var projectGraph = function ( root, sortObjects ) {

        _objectCount = 0;

        _renderData.objects.length = 0;
        _renderData.sprites.length = 0;
        _renderData.lights.length = 0;

        var projectObject = function ( parent ) {

            for ( var c = 0, cl = parent.children.length; c < cl; c ++ ) {

                var object = parent.children[ c ];

                if ( object.visible === false ) continue;

                if ( object instanceof THREE.Light ) {

                    _renderData.lights.push( object );

                } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) {

                    if ( object.frustumCulled === false || _frustum.contains( object ) === true ) {

                        _object = getNextObjectInPool();
                        _object.object = object;

                        if ( object.renderDepth !== null ) {

                            _object.z = object.renderDepth;

                        } else {

                            _vector3.copy( object.matrixWorld.getPosition() );
                            _viewProjectionMatrix.multiplyVector3( _vector3 );
                            _object.z = _vector3.z;

                        }

                        _renderData.objects.push( _object );

                    }

                } else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) {

                    _object = getNextObjectInPool();
                    _object.object = object;

                    // TODO: Find an elegant and performant solution and remove this dupe code.

                    if ( object.renderDepth !== null ) {

                        _object.z = object.renderDepth;

                    } else {

                        _vector3.copy( object.matrixWorld.getPosition() );
                        _viewProjectionMatrix.multiplyVector3( _vector3 );
                        _object.z = _vector3.z;

                    }

                    _renderData.sprites.push( _object );

                } else {

                    _object = getNextObjectInPool();
                    _object.object = object;

                    if ( object.renderDepth !== null ) {

                        _object.z = object.renderDepth;

                    } else {

                        _vector3.copy( object.matrixWorld.getPosition() );
                        _viewProjectionMatrix.multiplyVector3( _vector3 );
                        _object.z = _vector3.z;

                    }

                    _renderData.objects.push( _object );

                }

                projectObject( object );

            }

        };

        projectObject( root );

        if ( sortObjects === true ) _renderData.objects.sort( painterSort );

        return _renderData;

    };

    this.projectScene = function ( scene, camera, sortObjects, sortElements ) {

        var near = camera.near, far = camera.far, visible = false,
        o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object,
        modelMatrix, rotationMatrix,
        geometry, geometryMaterials, vertices, vertex, vertexPositionScreen,
        faces, face, faceVertexNormals, normal, faceVertexUvs, uvs,
        v1, v2, v3, v4, isFaceMaterial, material, side;

        _face3Count = 0;
        _face4Count = 0;
        _lineCount = 0;
        _particleCount = 0;

        _renderData.elements.length = 0;

        scene.updateMatrixWorld();

        if ( camera.parent === undefined ) camera.updateMatrixWorld();

        camera.matrixWorldInverse.getInverse( camera.matrixWorld );

        _viewProjectionMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );

        _frustum.setFromMatrix( _viewProjectionMatrix );

        _renderData = projectGraph( scene, sortObjects );

        for ( o = 0, ol = _renderData.objects.length; o < ol; o++ ) {

            object = _renderData.objects[ o ].object;

            modelMatrix = object.matrixWorld;

            _vertexCount = 0;

            if ( object instanceof THREE.Mesh ) {

                geometry = object.geometry;
                geometryMaterials = object.geometry.materials;
                vertices = geometry.vertices;
                faces = geometry.faces;
                faceVertexUvs = geometry.faceVertexUvs;

                rotationMatrix = object.matrixRotationWorld.extractRotation( modelMatrix );

                isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
                side = object.material.side;

                for ( v = 0, vl = vertices.length; v < vl; v ++ ) {

                    _vertex = getNextVertexInPool();
                    _vertex.positionWorld.copy( vertices[ v ] );

                    modelMatrix.multiplyVector3( _vertex.positionWorld );

                    _vertex.positionScreen.copy( _vertex.positionWorld );
                    _viewProjectionMatrix.multiplyVector4( _vertex.positionScreen );

                    _vertex.positionScreen.x /= _vertex.positionScreen.w;
                    _vertex.positionScreen.y /= _vertex.positionScreen.w;

                    _vertex.visible = _vertex.positionScreen.z > near && _vertex.positionScreen.z < far;

                }

                for ( f = 0, fl = faces.length; f < fl; f ++ ) {

                    face = faces[ f ];

                    material = isFaceMaterial === true ? geometryMaterials[ face.materialIndex ] : object.material;

                    if ( material === undefined ) continue;

                    side = material.side;

                    if ( face instanceof THREE.Face3 ) {

                        v1 = _vertexPool[ face.a ];
                        v2 = _vertexPool[ face.b ];
                        v3 = _vertexPool[ face.c ];

                        if ( v1.visible === true && v2.visible === true && v3.visible === true ) {

                            visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
                                ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;

                            if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {

                                _face = getNextFace3InPool();

                                _face.v1.copy( v1 );
                                _face.v2.copy( v2 );
                                _face.v3.copy( v3 );

                            } else {

                                continue;

                            }

                        } else {

                            continue;

                        }

                    } else if ( face instanceof THREE.Face4 ) {

                        v1 = _vertexPool[ face.a ];
                        v2 = _vertexPool[ face.b ];
                        v3 = _vertexPool[ face.c ];
                        v4 = _vertexPool[ face.d ];

                        if ( v1.visible === true && v2.visible === true && v3.visible === true && v4.visible === true ) {

                            visible = ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
                                ( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ||
                                ( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) -
                                ( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0;


                            if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {

                                _face = getNextFace4InPool();

                                _face.v1.copy( v1 );
                                _face.v2.copy( v2 );
                                _face.v3.copy( v3 );
                                _face.v4.copy( v4 );

                            } else {

                                continue;

                            }

                        } else {

                            continue;

                        }

                    }

                    _face.normalWorld.copy( face.normal );

                    if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) _face.normalWorld.negate();
                    rotationMatrix.multiplyVector3( _face.normalWorld );

                    _face.centroidWorld.copy( face.centroid );
                    modelMatrix.multiplyVector3( _face.centroidWorld );

                    _face.centroidScreen.copy( _face.centroidWorld );
                    _viewProjectionMatrix.multiplyVector3( _face.centroidScreen );

                    faceVertexNormals = face.vertexNormals;

                    for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) {

                        normal = _face.vertexNormalsWorld[ n ];
                        normal.copy( faceVertexNormals[ n ] );

                        if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) normal.negate();

                        rotationMatrix.multiplyVector3( normal );

                    }

                    _face.vertexNormalsLength = faceVertexNormals.length;

                    for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) {

                        uvs = faceVertexUvs[ c ][ f ];

                        if ( uvs === undefined ) continue;

                        for ( u = 0, ul = uvs.length; u < ul; u ++ ) {

                            _face.uvs[ c ][ u ] = uvs[ u ];

                        }

                    }

                    _face.material = material;

                    _face.z = _face.centroidScreen.z;

                    _renderData.elements.push( _face );

                }

            } else if ( object instanceof THREE.Line ) {

                _modelViewProjectionMatrix.multiply( _viewProjectionMatrix, modelMatrix );

                vertices = object.geometry.vertices;

                v1 = getNextVertexInPool();
                v1.positionScreen.copy( vertices[ 0 ] );
                _modelViewProjectionMatrix.multiplyVector4( v1.positionScreen );

                // Handle LineStrip and LinePieces
                var step = object.type === THREE.LinePieces ? 2 : 1;

                for ( v = 1, vl = vertices.length; v < vl; v ++ ) {

                    v1 = getNextVertexInPool();
                    v1.positionScreen.copy( vertices[ v ] );
                    _modelViewProjectionMatrix.multiplyVector4( v1.positionScreen );

                    if ( ( v + 1 ) % step > 0 ) continue;

                    v2 = _vertexPool[ _vertexCount - 2 ];

                    _clippedVertex1PositionScreen.copy( v1.positionScreen );
                    _clippedVertex2PositionScreen.copy( v2.positionScreen );

                    if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {

                        // Perform the perspective divide
                        _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
                        _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );

                        _line = getNextLineInPool();
                        _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
                        _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );

                        _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );

                        _line.material = object.material;

                        _renderData.elements.push( _line );

                    }

                }

            }

        }

        for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) {

            object = _renderData.sprites[ o ].object;

            modelMatrix = object.matrixWorld;

            if ( object instanceof THREE.Particle ) {

                _vector4.set( modelMatrix.elements[12], modelMatrix.elements[13], modelMatrix.elements[14], 1 );
                _viewProjectionMatrix.multiplyVector4( _vector4 );

                _vector4.z /= _vector4.w;

                if ( _vector4.z > 0 && _vector4.z < 1 ) {

                    _particle = getNextParticleInPool();
                    _particle.object = object;
                    _particle.x = _vector4.x / _vector4.w;
                    _particle.y = _vector4.y / _vector4.w;
                    _particle.z = _vector4.z;

                    _particle.rotation = object.rotation.z;

                    _particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) );
                    _particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) );

                    _particle.material = object.material;

                    _renderData.elements.push( _particle );

                }

            }

        }

        if ( sortElements === true ) _renderData.elements.sort( painterSort );

        return _renderData;

    };

    // Pools

    function getNextObjectInPool() {

        if ( _objectCount === _objectPoolLength ) {

            var object = new THREE.RenderableObject();
            _objectPool.push( object );
            _objectPoolLength ++;
            _objectCount ++;
            return object;

        }

        return _objectPool[ _objectCount ++ ];

    }

    function getNextVertexInPool() {

        if ( _vertexCount === _vertexPoolLength ) {

            var vertex = new THREE.RenderableVertex();
            _vertexPool.push( vertex );
            _vertexPoolLength ++;
            _vertexCount ++;
            return vertex;

        }

        return _vertexPool[ _vertexCount ++ ];

    }

    function getNextFace3InPool() {

        if ( _face3Count === _face3PoolLength ) {

            var face = new THREE.RenderableFace3();
            _face3Pool.push( face );
            _face3PoolLength ++;
            _face3Count ++;
            return face;

        }

        return _face3Pool[ _face3Count ++ ];


    }

    function getNextFace4InPool() {

        if ( _face4Count === _face4PoolLength ) {

            var face = new THREE.RenderableFace4();
            _face4Pool.push( face );
            _face4PoolLength ++;
            _face4Count ++;
            return face;

        }

        return _face4Pool[ _face4Count ++ ];

    }

    function getNextLineInPool() {

        if ( _lineCount === _linePoolLength ) {

            var line = new THREE.RenderableLine();
            _linePool.push( line );
            _linePoolLength ++;
            _lineCount ++
            return line;

        }

        return _linePool[ _lineCount ++ ];

    }

    function getNextParticleInPool() {

        if ( _particleCount === _particlePoolLength ) {

            var particle = new THREE.RenderableParticle();
            _particlePool.push( particle );
            _particlePoolLength ++;
            _particleCount ++
            return particle;

        }

        return _particlePool[ _particleCount ++ ];

    }

    //

    function painterSort( a, b ) {

        return b.z - a.z;

    }

    function clipLine( s1, s2 ) {

        var alpha1 = 0, alpha2 = 1,

        // Calculate the boundary coordinate of each vertex for the near and far clip planes,
        // Z = -1 and Z = +1, respectively.
        bc1near =  s1.z + s1.w,
        bc2near =  s2.z + s2.w,
        bc1far =  - s1.z + s1.w,
        bc2far =  - s2.z + s2.w;

        if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {

            // Both vertices lie entirely within all clip planes.
            return true;

        } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) {

            // Both vertices lie entirely outside one of the clip planes.
            return false;

        } else {

            // The line segment spans at least one clip plane.

            if ( bc1near < 0 ) {

                // v1 lies outside the near plane, v2 inside
                alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );

            } else if ( bc2near < 0 ) {

                // v2 lies outside the near plane, v1 inside
                alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );

            }

            if ( bc1far < 0 ) {

                // v1 lies outside the far plane, v2 inside
                alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );

            } else if ( bc2far < 0 ) {

                // v2 lies outside the far plane, v2 inside
                alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );

            }

            if ( alpha2 < alpha1 ) {

                // The line segment spans two boundaries, but is outside both of them.
                // (This can't happen when we're only clipping against just near/far but good
                //  to leave the check here for future usage if other clip planes are added.)
                return false;

            } else {

                // Update the s1 and s2 vertices to match the clipped line segment.
                s1.lerpSelf( s2, alpha1 );
                s2.lerpSelf( s1, 1 - alpha2 );

                return true;

            }

        }

    }

};
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 */

THREE.Quaternion = function( x, y, z, w ) {

    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
    this.w = ( w !== undefined ) ? w : 1;

};

THREE.Quaternion.prototype = {

    constructor: THREE.Quaternion,

    set: function ( x, y, z, w ) {

        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;

        return this;

    },

    copy: function ( q ) {

        this.x = q.x;
        this.y = q.y;
        this.z = q.z;
        this.w = q.w;

        return this;

    },

    setFromEuler: function ( v, order ) {

        // http://www.mathworks.com/matlabcentral/fileexchange/
        //     20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
        //    content/SpinCalc.m

        var c1 = Math.cos( v.x / 2 );
        var c2 = Math.cos( v.y / 2 );
        var c3 = Math.cos( v.z / 2 );
        var s1 = Math.sin( v.x / 2 );
        var s2 = Math.sin( v.y / 2 );
        var s3 = Math.sin( v.z / 2 );

        if ( order === undefined || order === 'XYZ' ) {

            this.x = s1 * c2 * c3 + c1 * s2 * s3;
            this.y = c1 * s2 * c3 - s1 * c2 * s3;
            this.z = c1 * c2 * s3 + s1 * s2 * c3;
            this.w = c1 * c2 * c3 - s1 * s2 * s3;

        } else if ( order === 'YXZ' ) {

            this.x = s1 * c2 * c3 + c1 * s2 * s3;
            this.y = c1 * s2 * c3 - s1 * c2 * s3;
            this.z = c1 * c2 * s3 - s1 * s2 * c3;
            this.w = c1 * c2 * c3 + s1 * s2 * s3;

        } else if ( order === 'ZXY' ) {

            this.x = s1 * c2 * c3 - c1 * s2 * s3;
            this.y = c1 * s2 * c3 + s1 * c2 * s3;
            this.z = c1 * c2 * s3 + s1 * s2 * c3;
            this.w = c1 * c2 * c3 - s1 * s2 * s3;

        } else if ( order === 'ZYX' ) {

            this.x = s1 * c2 * c3 - c1 * s2 * s3;
            this.y = c1 * s2 * c3 + s1 * c2 * s3;
            this.z = c1 * c2 * s3 - s1 * s2 * c3;
            this.w = c1 * c2 * c3 + s1 * s2 * s3;

        } else if ( order === 'YZX' ) {

            this.x = s1 * c2 * c3 + c1 * s2 * s3;
            this.y = c1 * s2 * c3 + s1 * c2 * s3;
            this.z = c1 * c2 * s3 - s1 * s2 * c3;
            this.w = c1 * c2 * c3 - s1 * s2 * s3;

        } else if ( order === 'XZY' ) {

            this.x = s1 * c2 * c3 - c1 * s2 * s3;
            this.y = c1 * s2 * c3 - s1 * c2 * s3;
            this.z = c1 * c2 * s3 + s1 * s2 * c3;
            this.w = c1 * c2 * c3 + s1 * s2 * s3;

        }

        return this;

    },

    setFromAxisAngle: function ( axis, angle ) {

        // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
        // axis have to be normalized

        var halfAngle = angle / 2,
            s = Math.sin( halfAngle );

        this.x = axis.x * s;
        this.y = axis.y * s;
        this.z = axis.z * s;
        this.w = Math.cos( halfAngle );

        return this;

    },

    setFromRotationMatrix: function ( m ) {

        // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm

        // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

        var te = m.elements,

            m11 = te[0], m12 = te[4], m13 = te[8],
            m21 = te[1], m22 = te[5], m23 = te[9],
            m31 = te[2], m32 = te[6], m33 = te[10],

            trace = m11 + m22 + m33,
            s;

        if( trace > 0 ) {

            s = 0.5 / Math.sqrt( trace + 1.0 );

            this.w = 0.25 / s;
            this.x = ( m32 - m23 ) * s;
            this.y = ( m13 - m31 ) * s;
            this.z = ( m21 - m12 ) * s;

        } else if ( m11 > m22 && m11 > m33 ) {

            s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );

            this.w = (m32 - m23 ) / s;
            this.x = 0.25 * s;
            this.y = (m12 + m21 ) / s;
            this.z = (m13 + m31 ) / s;

        } else if (m22 > m33) {

            s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );

            this.w = (m13 - m31 ) / s;
            this.x = (m12 + m21 ) / s;
            this.y = 0.25 * s;
            this.z = (m23 + m32 ) / s;

        } else {

            s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );

            this.w = ( m21 - m12 ) / s;
            this.x = ( m13 + m31 ) / s;
            this.y = ( m23 + m32 ) / s;
            this.z = 0.25 * s;

        }

        return this;

    },

    calculateW : function () {

        this.w = - Math.sqrt( Math.abs( 1.0 - this.x * this.x - this.y * this.y - this.z * this.z ) );

        return this;

    },

    inverse: function () {

        this.x *= -1;
        this.y *= -1;
        this.z *= -1;

        return this;

    },

    length: function () {

        return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );

    },

    normalize: function () {

        var l = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );

        if ( l === 0 ) {

            this.x = 0;
            this.y = 0;
            this.z = 0;
            this.w = 0;

        } else {

            l = 1 / l;

            this.x = this.x * l;
            this.y = this.y * l;
            this.z = this.z * l;
            this.w = this.w * l;

        }

        return this;

    },

    multiply: function ( a, b ) {

        // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
        var qax = a.x, qay = a.y, qaz = a.z, qaw = a.w,
        qbx = b.x, qby = b.y, qbz = b.z, qbw = b.w;

        this.x =  qax * qbw + qay * qbz - qaz * qby + qaw * qbx;
        this.y = -qax * qbz + qay * qbw + qaz * qbx + qaw * qby;
        this.z =  qax * qby - qay * qbx + qaz * qbw + qaw * qbz;
        this.w = -qax * qbx - qay * qby - qaz * qbz + qaw * qbw;

        return this;

    },

    multiplySelf: function ( b ) {

        var qax = this.x, qay = this.y, qaz = this.z, qaw = this.w,
        qbx = b.x, qby = b.y, qbz = b.z, qbw = b.w;

        this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
        this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
        this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
        this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;

        return this;

    },

    multiplyVector3: function ( vector, dest ) {

        if ( !dest ) { dest = vector; }

        var x    = vector.x,  y  = vector.y,  z  = vector.z,
            qx   = this.x, qy = this.y, qz = this.z, qw = this.w;

        // calculate quat * vector

        var ix =  qw * x + qy * z - qz * y,
            iy =  qw * y + qz * x - qx * z,
            iz =  qw * z + qx * y - qy * x,
            iw = -qx * x - qy * y - qz * z;

        // calculate result * inverse quat

        dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
        dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
        dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;

        return dest;

    },

    slerpSelf: function ( qb, t ) {

        var x = this.x, y = this.y, z = this.z, w = this.w;

        // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

        var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;

        if ( cosHalfTheta < 0 ) {

            this.w = -qb.w;
            this.x = -qb.x;
            this.y = -qb.y;
            this.z = -qb.z;

            cosHalfTheta = -cosHalfTheta;

        } else {

            this.copy( qb );

        }

        if ( cosHalfTheta >= 1.0 ) {

            this.w = w;
            this.x = x;
            this.y = y;
            this.z = z;

            return this;

        }

        var halfTheta = Math.acos( cosHalfTheta );
        var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );

        if ( Math.abs( sinHalfTheta ) < 0.001 ) {

            this.w = 0.5 * ( w + this.w );
            this.x = 0.5 * ( x + this.x );
            this.y = 0.5 * ( y + this.y );
            this.z = 0.5 * ( z + this.z );

            return this;

        }

        var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
        ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;

        this.w = ( w * ratioA + this.w * ratioB );
        this.x = ( x * ratioA + this.x * ratioB );
        this.y = ( y * ratioA + this.y * ratioB );
        this.z = ( z * ratioA + this.z * ratioB );

        return this;

    },

    clone: function () {

        return new THREE.Quaternion( this.x, this.y, this.z, this.w );

    }

}

THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {

    // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

    var cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;

    if ( cosHalfTheta < 0 ) {

        qm.w = -qb.w;
        qm.x = -qb.x;
        qm.y = -qb.y;
        qm.z = -qb.z;

        cosHalfTheta = -cosHalfTheta;

    } else {

        qm.copy( qb );

    }

    if ( Math.abs( cosHalfTheta ) >= 1.0 ) {

        qm.w = qa.w;
        qm.x = qa.x;
        qm.y = qa.y;
        qm.z = qa.z;

        return qm;

    }

    var halfTheta = Math.acos( cosHalfTheta );
    var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );

    if ( Math.abs( sinHalfTheta ) < 0.001 ) {

        qm.w = 0.5 * ( qa.w + qm.w );
        qm.x = 0.5 * ( qa.x + qm.x );
        qm.y = 0.5 * ( qa.y + qm.y );
        qm.z = 0.5 * ( qa.z + qm.z );

        return qm;

    }

    var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta;
    var ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;

    qm.w = ( qa.w * ratioA + qm.w * ratioB );
    qm.x = ( qa.x * ratioA + qm.x * ratioB );
    qm.y = ( qa.y * ratioA + qm.y * ratioB );
    qm.z = ( qa.z * ratioA + qm.z * ratioB );

    return qm;

}
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Vertex = function ( v ) {

    console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.')
    return v;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {

    this.a = a;
    this.b = b;
    this.c = c;

    this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
    this.vertexNormals = normal instanceof Array ? normal : [ ];

    this.color = color instanceof THREE.Color ? color : new THREE.Color();
    this.vertexColors = color instanceof Array ? color : [];

    this.vertexTangents = [];

    this.materialIndex = materialIndex;

    this.centroid = new THREE.Vector3();

};

THREE.Face3.prototype = {

    constructor: THREE.Face3,

    clone: function () {

        var face = new THREE.Face3( this.a, this.b, this.c );

        face.normal.copy( this.normal );
        face.color.copy( this.color );
        face.centroid.copy( this.centroid );

        face.materialIndex = this.materialIndex;

        var i, il;
        for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
        for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
        for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();

        return face;

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {

    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;

    this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
    this.vertexNormals = normal instanceof Array ? normal : [ ];

    this.color = color instanceof THREE.Color ? color : new THREE.Color();
    this.vertexColors = color instanceof Array ? color : [];

    this.vertexTangents = [];

    this.materialIndex = materialIndex;

    this.centroid = new THREE.Vector3();

};

THREE.Face4.prototype = {

    constructor: THREE.Face4,

    clone: function () {

        var face = new THREE.Face4( this.a, this.b, this.c, this.d );

        face.normal.copy( this.normal );
        face.color.copy( this.color );
        face.centroid.copy( this.centroid );

        face.materialIndex = this.materialIndex;

        var i, il;
        for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
        for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
        for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();

        return face;

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.UV = function ( u, v ) {

    this.u = u || 0;
    this.v = v || 0;

};

THREE.UV.prototype = {

    constructor: THREE.UV,

    set: function ( u, v ) {

        this.u = u;
        this.v = v;

        return this;

    },

    copy: function ( uv ) {

        this.u = uv.u;
        this.v = uv.v;

        return this;

    },

    lerpSelf: function ( uv, alpha ) {

        this.u += ( uv.u - this.u ) * alpha;
        this.v += ( uv.v - this.v ) * alpha;

        return this;

    },

    clone: function () {

        return new THREE.UV( this.u, this.v );

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author kile / http://kile.stravaganza.org/
 * @author alteredq / http://alteredqualia.com/
 * @author mikael emtinger / http://gomo.se/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 */

THREE.Geometry = function () {

    this.id = THREE.GeometryCount ++;

    this.name = '';

    this.vertices = [];
    this.colors = []; // one-to-one vertex colors, used in ParticleSystem, Line and Ribbon

    this.materials = [];

    this.faces = [];

    this.faceUvs = [[]];
    this.faceVertexUvs = [[]];

    this.morphTargets = [];
    this.morphColors = [];
    this.morphNormals = [];

    this.skinWeights = [];
    this.skinIndices = [];

    this.boundingBox = null;
    this.boundingSphere = null;

    this.hasTangents = false;

    this.dynamic = true; // the intermediate typearrays will be deleted when set to false

};

THREE.Geometry.prototype = {

    constructor : THREE.Geometry,

    applyMatrix: function ( matrix ) {

        var matrixRotation = new THREE.Matrix4();
        matrixRotation.extractRotation( matrix );

        for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {

            var vertex = this.vertices[ i ];

            matrix.multiplyVector3( vertex );

        }

        for ( var i = 0, il = this.faces.length; i < il; i ++ ) {

            var face = this.faces[ i ];

            matrixRotation.multiplyVector3( face.normal );

            for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {

                matrixRotation.multiplyVector3( face.vertexNormals[ j ] );

            }

            matrix.multiplyVector3( face.centroid );

        }

    },

    computeCentroids: function () {

        var f, fl, face;

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];
            face.centroid.set( 0, 0, 0 );

            if ( face instanceof THREE.Face3 ) {

                face.centroid.addSelf( this.vertices[ face.a ] );
                face.centroid.addSelf( this.vertices[ face.b ] );
                face.centroid.addSelf( this.vertices[ face.c ] );
                face.centroid.divideScalar( 3 );

            } else if ( face instanceof THREE.Face4 ) {

                face.centroid.addSelf( this.vertices[ face.a ] );
                face.centroid.addSelf( this.vertices[ face.b ] );
                face.centroid.addSelf( this.vertices[ face.c ] );
                face.centroid.addSelf( this.vertices[ face.d ] );
                face.centroid.divideScalar( 4 );

            }

        }

    },

    computeFaceNormals: function () {

        var n, nl, v, vl, vertex, f, fl, face, vA, vB, vC,
        cb = new THREE.Vector3(), ab = new THREE.Vector3();

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            vA = this.vertices[ face.a ];
            vB = this.vertices[ face.b ];
            vC = this.vertices[ face.c ];

            cb.sub( vC, vB );
            ab.sub( vA, vB );
            cb.crossSelf( ab );

            if ( !cb.isZero() ) {

                cb.normalize();

            }

            face.normal.copy( cb );

        }

    },

    computeVertexNormals: function () {

        var v, vl, f, fl, face, vertices;

        // create internal buffers for reuse when calling this method repeatedly
        // (otherwise memory allocation / deallocation every frame is big resource hog)

        if ( this.__tmpVertices === undefined ) {

            this.__tmpVertices = new Array( this.vertices.length );
            vertices = this.__tmpVertices;

            for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

                vertices[ v ] = new THREE.Vector3();

            }

            for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

                face = this.faces[ f ];

                if ( face instanceof THREE.Face3 ) {

                    face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];

                } else if ( face instanceof THREE.Face4 ) {

                    face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];

                }

            }

        } else {

            vertices = this.__tmpVertices;

            for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

                vertices[ v ].set( 0, 0, 0 );

            }

        }

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            if ( face instanceof THREE.Face3 ) {

                vertices[ face.a ].addSelf( face.normal );
                vertices[ face.b ].addSelf( face.normal );
                vertices[ face.c ].addSelf( face.normal );

            } else if ( face instanceof THREE.Face4 ) {

                vertices[ face.a ].addSelf( face.normal );
                vertices[ face.b ].addSelf( face.normal );
                vertices[ face.c ].addSelf( face.normal );
                vertices[ face.d ].addSelf( face.normal );

            }

        }

        for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

            vertices[ v ].normalize();

        }

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            if ( face instanceof THREE.Face3 ) {

                face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
                face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
                face.vertexNormals[ 2 ].copy( vertices[ face.c ] );

            } else if ( face instanceof THREE.Face4 ) {

                face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
                face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
                face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
                face.vertexNormals[ 3 ].copy( vertices[ face.d ] );

            }

        }

    },

    computeMorphNormals: function () {

        var i, il, f, fl, face;

        // save original normals
        // - create temp variables on first access
        //   otherwise just copy (for faster repeated calls)

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            if ( ! face.__originalFaceNormal ) {

                face.__originalFaceNormal = face.normal.clone();

            } else {

                face.__originalFaceNormal.copy( face.normal );

            }

            if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];

            for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {

                if ( ! face.__originalVertexNormals[ i ] ) {

                    face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();

                } else {

                    face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );

                }

            }

        }

        // use temp geometry to compute face and vertex normals for each morph

        var tmpGeo = new THREE.Geometry();
        tmpGeo.faces = this.faces;

        for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {

            // create on first access

            if ( ! this.morphNormals[ i ] ) {

                this.morphNormals[ i ] = {};
                this.morphNormals[ i ].faceNormals = [];
                this.morphNormals[ i ].vertexNormals = [];

                var dstNormalsFace = this.morphNormals[ i ].faceNormals;
                var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;

                var faceNormal, vertexNormals;

                for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

                    face = this.faces[ f ];

                    faceNormal = new THREE.Vector3();

                    if ( face instanceof THREE.Face3 ) {

                        vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };

                    } else {

                        vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3(), d: new THREE.Vector3() };

                    }

                    dstNormalsFace.push( faceNormal );
                    dstNormalsVertex.push( vertexNormals );

                }

            }

            var morphNormals = this.morphNormals[ i ];

            // set vertices to morph target

            tmpGeo.vertices = this.morphTargets[ i ].vertices;

            // compute morph normals

            tmpGeo.computeFaceNormals();
            tmpGeo.computeVertexNormals();

            // store morph normals

            var faceNormal, vertexNormals;

            for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

                face = this.faces[ f ];

                faceNormal = morphNormals.faceNormals[ f ];
                vertexNormals = morphNormals.vertexNormals[ f ];

                faceNormal.copy( face.normal );

                if ( face instanceof THREE.Face3 ) {

                    vertexNormals.a.copy( face.vertexNormals[ 0 ] );
                    vertexNormals.b.copy( face.vertexNormals[ 1 ] );
                    vertexNormals.c.copy( face.vertexNormals[ 2 ] );

                } else {

                    vertexNormals.a.copy( face.vertexNormals[ 0 ] );
                    vertexNormals.b.copy( face.vertexNormals[ 1 ] );
                    vertexNormals.c.copy( face.vertexNormals[ 2 ] );
                    vertexNormals.d.copy( face.vertexNormals[ 3 ] );

                }

            }

        }

        // restore original normals

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            face.normal = face.__originalFaceNormal;
            face.vertexNormals = face.__originalVertexNormals;

        }

    },

    computeTangents: function () {

        // based on http://www.terathon.com/code/tangent.html
        // tangents go to vertices

        var f, fl, v, vl, i, il, vertexIndex,
            face, uv, vA, vB, vC, uvA, uvB, uvC,
            x1, x2, y1, y2, z1, z2,
            s1, s2, t1, t2, r, t, test,
            tan1 = [], tan2 = [],
            sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
            tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
            n = new THREE.Vector3(), w;

        for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

            tan1[ v ] = new THREE.Vector3();
            tan2[ v ] = new THREE.Vector3();

        }

        function handleTriangle( context, a, b, c, ua, ub, uc ) {

            vA = context.vertices[ a ];
            vB = context.vertices[ b ];
            vC = context.vertices[ c ];

            uvA = uv[ ua ];
            uvB = uv[ ub ];
            uvC = uv[ uc ];

            x1 = vB.x - vA.x;
            x2 = vC.x - vA.x;
            y1 = vB.y - vA.y;
            y2 = vC.y - vA.y;
            z1 = vB.z - vA.z;
            z2 = vC.z - vA.z;

            s1 = uvB.u - uvA.u;
            s2 = uvC.u - uvA.u;
            t1 = uvB.v - uvA.v;
            t2 = uvC.v - uvA.v;

            r = 1.0 / ( s1 * t2 - s2 * t1 );
            sdir.set( ( t2 * x1 - t1 * x2 ) * r,
                      ( t2 * y1 - t1 * y2 ) * r,
                      ( t2 * z1 - t1 * z2 ) * r );
            tdir.set( ( s1 * x2 - s2 * x1 ) * r,
                      ( s1 * y2 - s2 * y1 ) * r,
                      ( s1 * z2 - s2 * z1 ) * r );

            tan1[ a ].addSelf( sdir );
            tan1[ b ].addSelf( sdir );
            tan1[ c ].addSelf( sdir );

            tan2[ a ].addSelf( tdir );
            tan2[ b ].addSelf( tdir );
            tan2[ c ].addSelf( tdir );

        }

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];
            uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents

            if ( face instanceof THREE.Face3 ) {

                handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );

            } else if ( face instanceof THREE.Face4 ) {

                handleTriangle( this, face.a, face.b, face.d, 0, 1, 3 );
                handleTriangle( this, face.b, face.c, face.d, 1, 2, 3 );

            }

        }

        var faceIndex = [ 'a', 'b', 'c', 'd' ];

        for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

            face = this.faces[ f ];

            for ( i = 0; i < face.vertexNormals.length; i++ ) {

                n.copy( face.vertexNormals[ i ] );

                vertexIndex = face[ faceIndex[ i ] ];

                t = tan1[ vertexIndex ];

                // Gram-Schmidt orthogonalize

                tmp.copy( t );
                tmp.subSelf( n.multiplyScalar( n.dot( t ) ) ).normalize();

                // Calculate handedness

                tmp2.cross( face.vertexNormals[ i ], t );
                test = tmp2.dot( tan2[ vertexIndex ] );
                w = (test < 0.0) ? -1.0 : 1.0;

                face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );

            }

        }

        this.hasTangents = true;

    },

    computeBoundingBox: function () {

        if ( ! this.boundingBox ) {

            this.boundingBox = { min: new THREE.Vector3(), max: new THREE.Vector3() };

        }

        if ( this.vertices.length > 0 ) {

            var position, firstPosition = this.vertices[ 0 ];

            this.boundingBox.min.copy( firstPosition );
            this.boundingBox.max.copy( firstPosition );

            var min = this.boundingBox.min,
                max = this.boundingBox.max;

            for ( var v = 1, vl = this.vertices.length; v < vl; v ++ ) {

                position = this.vertices[ v ];

                if ( position.x < min.x ) {

                    min.x = position.x;

                } else if ( position.x > max.x ) {

                    max.x = position.x;

                }

                if ( position.y < min.y ) {

                    min.y = position.y;

                } else if ( position.y > max.y ) {

                    max.y = position.y;

                }

                if ( position.z < min.z ) {

                    min.z = position.z;

                } else if ( position.z > max.z ) {

                    max.z = position.z;

                }

            }

        } else {

            this.boundingBox.min.set( 0, 0, 0 );
            this.boundingBox.max.set( 0, 0, 0 );

        }

    },

    computeBoundingSphere: function () {

        var maxRadiusSq = 0;

        if ( this.boundingSphere === null ) this.boundingSphere = { radius: 0 };

        for ( var i = 0, l = this.vertices.length; i < l; i ++ ) {

            var radiusSq = this.vertices[ i ].lengthSq();
            if ( radiusSq > maxRadiusSq ) maxRadiusSq = radiusSq;

        }

        this.boundingSphere.radius = Math.sqrt( maxRadiusSq );

    },

    /*
     * Checks for duplicate vertices with hashmap.
     * Duplicated vertices are removed
     * and faces' vertices are updated.
     */

    mergeVertices: function () {

        var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique)
        var unique = [], changes = [];

        var v, key;
        var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001
        var precision = Math.pow( 10, precisionPoints );
        var i,il, face;
        var abcd = 'abcd', o, k, j, jl, u;

        for ( i = 0, il = this.vertices.length; i < il; i ++ ) {

            v = this.vertices[ i ];
            key = [ Math.round( v.x * precision ), Math.round( v.y * precision ), Math.round( v.z * precision ) ].join( '_' );

            if ( verticesMap[ key ] === undefined ) {

                verticesMap[ key ] = i;
                unique.push( this.vertices[ i ] );
                changes[ i ] = unique.length - 1;

            } else {

                //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
                changes[ i ] = changes[ verticesMap[ key ] ];

            }

        };


        // Start to patch face indices

        for( i = 0, il = this.faces.length; i < il; i ++ ) {

            face = this.faces[ i ];

            if ( face instanceof THREE.Face3 ) {

                face.a = changes[ face.a ];
                face.b = changes[ face.b ];
                face.c = changes[ face.c ];

            } else if ( face instanceof THREE.Face4 ) {

                face.a = changes[ face.a ];
                face.b = changes[ face.b ];
                face.c = changes[ face.c ];
                face.d = changes[ face.d ];

                // check dups in (a, b, c, d) and convert to -> face3

                o = [ face.a, face.b, face.c, face.d ];

                for ( k = 3; k > 0; k -- ) {

                    if ( o.indexOf( face[ abcd[ k ] ] ) !== k ) {

                        // console.log('faces', face.a, face.b, face.c, face.d, 'dup at', k);

                        o.splice( k, 1 );

                        this.faces[ i ] = new THREE.Face3( o[0], o[1], o[2], face.normal, face.color, face.materialIndex );

                        for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {

                            u = this.faceVertexUvs[ j ][ i ];
                            if ( u ) u.splice( k, 1 );

                        }

                        this.faces[ i ].vertexColors = face.vertexColors;

                        break;
                    }

                }

            }

        }

        // Use unique set of vertices

        var diff = this.vertices.length - unique.length;
        this.vertices = unique;
        return diff;

    },

    clone: function () {

        // TODO

    }

};

THREE.GeometryCount = 0;
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.BufferGeometry = function () {

    this.id = THREE.GeometryCount ++;

    // attributes

    this.attributes = {};

    // attributes typed arrays are kept only if dynamic flag is set

    this.dynamic = false;

    // boundings

    this.boundingBox = null;
    this.boundingSphere = null;

    this.hasTangents = false;

    // for compatibility

    this.morphTargets = [];

};

THREE.BufferGeometry.prototype = {

    constructor : THREE.BufferGeometry,

    applyMatrix: function ( matrix ) {

        var positionArray;
        var normalArray;

        if ( this.attributes[ "position" ] ) positionArray = this.attributes[ "position" ].array;
        if ( this.attributes[ "normal" ] ) normalArray = this.attributes[ "normal" ].array;

        if ( positionArray !== undefined ) {

            matrix.multiplyVector3Array( positionArray );
            this.verticesNeedUpdate = true;

        }

        if ( normalArray !== undefined ) {

            var matrixRotation = new THREE.Matrix4();
            matrixRotation.extractRotation( matrix );

            matrixRotation.multiplyVector3Array( normalArray );
            this.normalsNeedUpdate = true;

        }

    },

    computeBoundingBox: function () {

        if ( ! this.boundingBox ) {

            this.boundingBox = {

                min: new THREE.Vector3( Infinity, Infinity, Infinity ),
                max: new THREE.Vector3( -Infinity, -Infinity, -Infinity )

            };

        }

        var positions = this.attributes[ "position" ].array;

        if ( positions ) {

            var bb = this.boundingBox;
            var x, y, z;

            for ( var i = 0, il = positions.length; i < il; i += 3 ) {

                x = positions[ i ];
                y = positions[ i + 1 ];
                z = positions[ i + 2 ];

                // bounding box

                if ( x < bb.min.x ) {

                    bb.min.x = x;

                } else if ( x > bb.max.x ) {

                    bb.max.x = x;

                }

                if ( y < bb.min.y ) {

                    bb.min.y = y;

                } else if ( y > bb.max.y ) {

                    bb.max.y = y;

                }

                if ( z < bb.min.z ) {

                    bb.min.z = z;

                } else if ( z > bb.max.z ) {

                    bb.max.z = z;

                }

            }

        }

        if ( positions === undefined || positions.length === 0 ) {

            this.boundingBox.min.set( 0, 0, 0 );
            this.boundingBox.max.set( 0, 0, 0 );

        }

    },

    computeBoundingSphere: function () {

        if ( ! this.boundingSphere ) this.boundingSphere = { radius: 0 };

        var positions = this.attributes[ "position" ].array;

        if ( positions ) {

            var radiusSq, maxRadiusSq = 0;
            var x, y, z;

            for ( var i = 0, il = positions.length; i < il; i += 3 ) {

                x = positions[ i ];
                y = positions[ i + 1 ];
                z = positions[ i + 2 ];

                radiusSq =  x * x + y * y + z * z;
                if ( radiusSq > maxRadiusSq ) maxRadiusSq = radiusSq;

            }

            this.boundingSphere.radius = Math.sqrt( maxRadiusSq );

        }

    },

    computeVertexNormals: function () {

        if ( this.attributes[ "position" ] && this.attributes[ "index" ] ) {

            var i, il;
            var j, jl;

            var nVertexElements = this.attributes[ "position" ].array.length;

            if ( this.attributes[ "normal" ] === undefined ) {

                this.attributes[ "normal" ] = {

                    itemSize: 3,
                    array: new Float32Array( nVertexElements ),
                    numItems: nVertexElements

                };

            } else {

                // reset existing normals to zero

                for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) {

                    this.attributes[ "normal" ].array[ i ] = 0;

                }

            }

            var offsets = this.offsets;

            var indices = this.attributes[ "index" ].array;
            var positions = this.attributes[ "position" ].array;
            var normals = this.attributes[ "normal" ].array;

            var vA, vB, vC, x, y, z,

            pA = new THREE.Vector3(),
            pB = new THREE.Vector3(),
            pC = new THREE.Vector3(),

            cb = new THREE.Vector3(),
            ab = new THREE.Vector3();

            for ( j = 0, jl = offsets.length; j < jl; ++ j ) {

                var start = offsets[ j ].start;
                var count = offsets[ j ].count;
                var index = offsets[ j ].index;

                for ( i = start, il = start + count; i < il; i += 3 ) {

                    vA = index + indices[ i ];
                    vB = index + indices[ i + 1 ];
                    vC = index + indices[ i + 2 ];

                    x = positions[ vA * 3 ];
                    y = positions[ vA * 3 + 1 ];
                    z = positions[ vA * 3 + 2 ];
                    pA.set( x, y, z );

                    x = positions[ vB * 3 ];
                    y = positions[ vB * 3 + 1 ];
                    z = positions[ vB * 3 + 2 ];
                    pB.set( x, y, z );

                    x = positions[ vC * 3 ];
                    y = positions[ vC * 3 + 1 ];
                    z = positions[ vC * 3 + 2 ];
                    pC.set( x, y, z );

                    cb.sub( pC, pB );
                    ab.sub( pA, pB );
                    cb.crossSelf( ab );

                    normals[ vA * 3 ] += cb.x;
                    normals[ vA * 3 + 1 ] += cb.y;
                    normals[ vA * 3 + 2 ] += cb.z;

                    normals[ vB * 3 ] += cb.x;
                    normals[ vB * 3 + 1 ] += cb.y;
                    normals[ vB * 3 + 2 ] += cb.z;

                    normals[ vC * 3 ] += cb.x;
                    normals[ vC * 3 + 1 ] += cb.y;
                    normals[ vC * 3 + 2 ] += cb.z;

                }

            }

            // normalize normals

            for ( i = 0, il = normals.length; i < il; i += 3 ) {

                x = normals[ i ];
                y = normals[ i + 1 ];
                z = normals[ i + 2 ];

                var n = 1.0 / Math.sqrt( x * x + y * y + z * z );

                normals[ i ] *= n;
                normals[ i + 1 ] *= n;
                normals[ i + 2 ] *= n;

            }

            this.normalsNeedUpdate = true;

        }

    },

    computeTangents: function () {

        // based on http://www.terathon.com/code/tangent.html
        // (per vertex tangents)

        if ( this.attributes[ "index" ] === undefined ||
             this.attributes[ "position" ] === undefined ||
             this.attributes[ "normal" ] === undefined ||
             this.attributes[ "uv" ] === undefined ) {

            console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" );
            return;

        }

        var indices = this.attributes[ "index" ].array;
        var positions = this.attributes[ "position" ].array;
        var normals = this.attributes[ "normal" ].array;
        var uvs = this.attributes[ "uv" ].array;

        var nVertices = positions.length / 3;

        if ( this.attributes[ "tangent" ] === undefined ) {

            var nTangentElements = 4 * nVertices;

            this.attributes[ "tangent" ] = {

                itemSize: 4,
                array: new Float32Array( nTangentElements ),
                numItems: nTangentElements

            };

        }

        var tangents = this.attributes[ "tangent" ].array;

        var tan1 = [], tan2 = [];

        for ( var k = 0; k < nVertices; k ++ ) {

            tan1[ k ] = new THREE.Vector3();
            tan2[ k ] = new THREE.Vector3();

        }

        var xA, yA, zA,
            xB, yB, zB,
            xC, yC, zC,

            uA, vA,
            uB, vB,
            uC, vC,

            x1, x2, y1, y2, z1, z2,
            s1, s2, t1, t2, r;

        var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();

        function handleTriangle( a, b, c ) {

            xA = positions[ a * 3 ];
            yA = positions[ a * 3 + 1 ];
            zA = positions[ a * 3 + 2 ];

            xB = positions[ b * 3 ];
            yB = positions[ b * 3 + 1 ];
            zB = positions[ b * 3 + 2 ];

            xC = positions[ c * 3 ];
            yC = positions[ c * 3 + 1 ];
            zC = positions[ c * 3 + 2 ];

            uA = uvs[ a * 2 ];
            vA = uvs[ a * 2 + 1 ];

            uB = uvs[ b * 2 ];
            vB = uvs[ b * 2 + 1 ];

            uC = uvs[ c * 2 ];
            vC = uvs[ c * 2 + 1 ];

            x1 = xB - xA;
            x2 = xC - xA;

            y1 = yB - yA;
            y2 = yC - yA;

            z1 = zB - zA;
            z2 = zC - zA;

            s1 = uB - uA;
            s2 = uC - uA;

            t1 = vB - vA;
            t2 = vC - vA;

            r = 1.0 / ( s1 * t2 - s2 * t1 );

            sdir.set(
                ( t2 * x1 - t1 * x2 ) * r,
                ( t2 * y1 - t1 * y2 ) * r,
                ( t2 * z1 - t1 * z2 ) * r
            );

            tdir.set(
                ( s1 * x2 - s2 * x1 ) * r,
                ( s1 * y2 - s2 * y1 ) * r,
                ( s1 * z2 - s2 * z1 ) * r
            );

            tan1[ a ].addSelf( sdir );
            tan1[ b ].addSelf( sdir );
            tan1[ c ].addSelf( sdir );

            tan2[ a ].addSelf( tdir );
            tan2[ b ].addSelf( tdir );
            tan2[ c ].addSelf( tdir );

        }

        var i, il;
        var j, jl;
        var iA, iB, iC;

        var offsets = this.offsets;

        for ( j = 0, jl = offsets.length; j < jl; ++ j ) {

            var start = offsets[ j ].start;
            var count = offsets[ j ].count;
            var index = offsets[ j ].index;

            for ( i = start, il = start + count; i < il; i += 3 ) {

                iA = index + indices[ i ];
                iB = index + indices[ i + 1 ];
                iC = index + indices[ i + 2 ];

                handleTriangle( iA, iB, iC );

            }

        }

        var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
        var n = new THREE.Vector3(), n2 = new THREE.Vector3();
        var w, t, test;
        var nx, ny, nz;

        function handleVertex( v ) {

            n.x = normals[ v * 3 ];
            n.y = normals[ v * 3 + 1 ];
            n.z = normals[ v * 3 + 2 ];

            n2.copy( n );

            t = tan1[ v ];

            // Gram-Schmidt orthogonalize

            tmp.copy( t );
            tmp.subSelf( n.multiplyScalar( n.dot( t ) ) ).normalize();

            // Calculate handedness

            tmp2.cross( n2, t );
            test = tmp2.dot( tan2[ v ] );
            w = ( test < 0.0 ) ? -1.0 : 1.0;

            tangents[ v * 4 ]       = tmp.x;
            tangents[ v * 4 + 1 ] = tmp.y;
            tangents[ v * 4 + 2 ] = tmp.z;
            tangents[ v * 4 + 3 ] = w;

        }

        for ( j = 0, jl = offsets.length; j < jl; ++ j ) {

            var start = offsets[ j ].start;
            var count = offsets[ j ].count;
            var index = offsets[ j ].index;

            for ( i = start, il = start + count; i < il; i += 3 ) {

                iA = index + indices[ i ];
                iB = index + indices[ i + 1 ];
                iC = index + indices[ i + 2 ];

                handleVertex( iA );
                handleVertex( iB );
                handleVertex( iC );

            }

        }

        this.hasTangents = true;
        this.tangentsNeedUpdate = true;

    }

};

/**
 * Spline from Tween.js, slightly optimized (and trashed)
 * http://sole.github.com/tween.js/examples/05_spline.html
 *
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Spline = function ( points ) {

    this.points = points;

    var c = [], v3 = { x: 0, y: 0, z: 0 },
    point, intPoint, weight, w2, w3,
    pa, pb, pc, pd;

    this.initFromArray = function( a ) {

        this.points = [];

        for ( var i = 0; i < a.length; i++ ) {

            this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] };

        }

    };

    this.getPoint = function ( k ) {

        point = ( this.points.length - 1 ) * k;
        intPoint = Math.floor( point );
        weight = point - intPoint;

        c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
        c[ 1 ] = intPoint;
        c[ 2 ] = intPoint  > this.points.length - 2 ? this.points.length - 1 : intPoint + 1;
        c[ 3 ] = intPoint  > this.points.length - 3 ? this.points.length - 1 : intPoint + 2;

        pa = this.points[ c[ 0 ] ];
        pb = this.points[ c[ 1 ] ];
        pc = this.points[ c[ 2 ] ];
        pd = this.points[ c[ 3 ] ];

        w2 = weight * weight;
        w3 = weight * w2;

        v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 );
        v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 );
        v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 );

        return v3;

    };

    this.getControlPointsArray = function () {

        var i, p, l = this.points.length,
            coords = [];

        for ( i = 0; i < l; i ++ ) {

            p = this.points[ i ];
            coords[ i ] = [ p.x, p.y, p.z ];

        }

        return coords;

    };

    // approximate length by summing linear segments

    this.getLength = function ( nSubDivisions ) {

        var i, index, nSamples, position,
            point = 0, intPoint = 0, oldIntPoint = 0,
            oldPosition = new THREE.Vector3(),
            tmpVec = new THREE.Vector3(),
            chunkLengths = [],
            totalLength = 0;

        // first point has 0 length

        chunkLengths[ 0 ] = 0;

        if ( !nSubDivisions ) nSubDivisions = 100;

        nSamples = this.points.length * nSubDivisions;

        oldPosition.copy( this.points[ 0 ] );

        for ( i = 1; i < nSamples; i ++ ) {

            index = i / nSamples;

            position = this.getPoint( index );
            tmpVec.copy( position );

            totalLength += tmpVec.distanceTo( oldPosition );

            oldPosition.copy( position );

            point = ( this.points.length - 1 ) * index;
            intPoint = Math.floor( point );

            if ( intPoint != oldIntPoint ) {

                chunkLengths[ intPoint ] = totalLength;
                oldIntPoint = intPoint;

            }

        }

        // last point ends with total length

        chunkLengths[ chunkLengths.length ] = totalLength;

        return { chunks: chunkLengths, total: totalLength };

    };

    this.reparametrizeByArcLength = function ( samplingCoef ) {

        var i, j,
            index, indexCurrent, indexNext,
            linearDistance, realDistance,
            sampling, position,
            newpoints = [],
            tmpVec = new THREE.Vector3(),
            sl = this.getLength();

        newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() );

        for ( i = 1; i < this.points.length; i++ ) {

            //tmpVec.copy( this.points[ i - 1 ] );
            //linearDistance = tmpVec.distanceTo( this.points[ i ] );

            realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ];

            sampling = Math.ceil( samplingCoef * realDistance / sl.total );

            indexCurrent = ( i - 1 ) / ( this.points.length - 1 );
            indexNext = i / ( this.points.length - 1 );

            for ( j = 1; j < sampling - 1; j++ ) {

                index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent );

                position = this.getPoint( index );
                newpoints.push( tmpVec.copy( position ).clone() );

            }

            newpoints.push( tmpVec.copy( this.points[ i ] ).clone() );

        }

        this.points = newpoints;

    };

    // Catmull-Rom

    function interpolate( p0, p1, p2, p3, t, t2, t3 ) {

        var v0 = ( p2 - p0 ) * 0.5,
            v1 = ( p3 - p1 ) * 0.5;

        return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;

    };

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 */

THREE.Camera = function () {

    THREE.Object3D.call( this );

    this.matrixWorldInverse = new THREE.Matrix4();

    this.projectionMatrix = new THREE.Matrix4();
    this.projectionMatrixInverse = new THREE.Matrix4();

};

THREE.Camera.prototype = Object.create( THREE.Object3D.prototype );

THREE.Camera.prototype.lookAt = function ( vector ) {

    // TODO: Add hierarchy support.

    this.matrix.lookAt( this.position, vector, this.up );

    if ( this.rotationAutoUpdate === true ) {

        this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) {

    THREE.Camera.call( this );

    this.left = left;
    this.right = right;
    this.top = top;
    this.bottom = bottom;

    this.near = ( near !== undefined ) ? near : 0.1;
    this.far = ( far !== undefined ) ? far : 2000;

    this.updateProjectionMatrix();

};

THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype );

THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () {

    this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far );

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author greggman / http://games.greggman.com/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 */

THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {

    THREE.Camera.call( this );

    this.fov = fov !== undefined ? fov : 50;
    this.aspect = aspect !== undefined ? aspect : 1;
    this.near = near !== undefined ? near : 0.1;
    this.far = far !== undefined ? far : 2000;

    this.updateProjectionMatrix();

};

THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );


/**
 * Uses Focal Length (in mm) to estimate and set FOV
 * 35mm (fullframe) camera is used if frame size is not specified;
 * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
 */

THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {

    if ( frameHeight === undefined ) frameHeight = 24;

    this.fov = 2 * Math.atan( frameHeight / ( focalLength * 2 ) ) * ( 180 / Math.PI );
    this.updateProjectionMatrix();

}


/**
 * Sets an offset in a larger frustum. This is useful for multi-window or
 * multi-monitor/multi-machine setups.
 *
 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
 * the monitors are in grid like this
 *
 *   +---+---+---+
 *   | A | B | C |
 *   +---+---+---+
 *   | D | E | F |
 *   +---+---+---+
 *
 * then for each monitor you would call it like this
 *
 *   var w = 1920;
 *   var h = 1080;
 *   var fullWidth = w * 3;
 *   var fullHeight = h * 2;
 *
 *   --A--
 *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
 *   --B--
 *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
 *   --C--
 *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
 *   --D--
 *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
 *   --E--
 *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
 *   --F--
 *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
 *
 *   Note there is no reason monitors have to be the same size or in a grid.
 */

THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {

    this.fullWidth = fullWidth;
    this.fullHeight = fullHeight;
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;

    this.updateProjectionMatrix();

};


THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {

    if ( this.fullWidth ) {

        var aspect = this.fullWidth / this.fullHeight;
        var top = Math.tan( this.fov * Math.PI / 360 ) * this.near;
        var bottom = -top;
        var left = aspect * bottom;
        var right = aspect * top;
        var width = Math.abs( right - left );
        var height = Math.abs( top - bottom );

        this.projectionMatrix.makeFrustum(
            left + this.x * width / this.fullWidth,
            left + ( this.x + this.width ) * width / this.fullWidth,
            top - ( this.y + this.height ) * height / this.fullHeight,
            top - this.y * height / this.fullHeight,
            this.near,
            this.far
        );

    } else {

        this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far );

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Light = function ( hex ) {

    THREE.Object3D.call( this );

    this.color = new THREE.Color( hex );

};

THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.AmbientLight = function ( hex ) {

    THREE.Light.call( this, hex );

};

THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.DirectionalLight = function ( hex, intensity, distance ) {

    THREE.Light.call( this, hex );

    this.position = new THREE.Vector3( 0, 1, 0 );
    this.target = new THREE.Object3D();

    this.intensity = ( intensity !== undefined ) ? intensity : 1;
    this.distance = ( distance !== undefined ) ? distance : 0;

    this.castShadow = false;
    this.onlyShadow = false;

    //

    this.shadowCameraNear = 50;
    this.shadowCameraFar = 5000;

    this.shadowCameraLeft = -500;
    this.shadowCameraRight = 500;
    this.shadowCameraTop = 500;
    this.shadowCameraBottom = -500;

    this.shadowCameraVisible = false;

    this.shadowBias = 0;
    this.shadowDarkness = 0.5;

    this.shadowMapWidth = 512;
    this.shadowMapHeight = 512;

    //

    this.shadowCascade = false;

    this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 );
    this.shadowCascadeCount = 2;

    this.shadowCascadeBias = [ 0, 0, 0 ];
    this.shadowCascadeWidth = [ 512, 512, 512 ];
    this.shadowCascadeHeight = [ 512, 512, 512 ];

    this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ];
    this.shadowCascadeFarZ  = [  0.990, 0.998, 1.000 ];

    this.shadowCascadeArray = [];

    //

    this.shadowMap = null;
    this.shadowMapSize = null;
    this.shadowCamera = null;
    this.shadowMatrix = null;

};

THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype );
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.HemisphereLight = function ( skyColorHex, groundColorHex, intensity ) {

    THREE.Light.call( this, skyColorHex );

    this.groundColor = new THREE.Color( groundColorHex );

    this.position = new THREE.Vector3( 0, 100, 0 );

    this.intensity = ( intensity !== undefined ) ? intensity : 1;

};

THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.PointLight = function ( hex, intensity, distance ) {

    THREE.Light.call( this, hex );

    this.position = new THREE.Vector3( 0, 0, 0 );
    this.intensity = ( intensity !== undefined ) ? intensity : 1;
    this.distance = ( distance !== undefined ) ? distance : 0;

};

THREE.PointLight.prototype = Object.create( THREE.Light.prototype );
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SpotLight = function ( hex, intensity, distance, angle, exponent ) {

    THREE.Light.call( this, hex );

    this.position = new THREE.Vector3( 0, 1, 0 );
    this.target = new THREE.Object3D();

    this.intensity = ( intensity !== undefined ) ? intensity : 1;
    this.distance = ( distance !== undefined ) ? distance : 0;
    this.angle = ( angle !== undefined ) ? angle : Math.PI / 2;
    this.exponent = ( exponent !== undefined ) ? exponent : 10;

    this.castShadow = false;
    this.onlyShadow = false;

    //

    this.shadowCameraNear = 50;
    this.shadowCameraFar = 5000;
    this.shadowCameraFov = 50;

    this.shadowCameraVisible = false;

    this.shadowBias = 0;
    this.shadowDarkness = 0.5;

    this.shadowMapWidth = 512;
    this.shadowMapHeight = 512;

    //

    this.shadowMap = null;
    this.shadowMapSize = null;
    this.shadowCamera = null;
    this.shadowMatrix = null;

};

THREE.SpotLight.prototype = Object.create( THREE.Light.prototype );
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Loader = function ( showStatus ) {

    this.showStatus = showStatus;
    this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null;

    this.onLoadStart = function () {};
    this.onLoadProgress = function () {};
    this.onLoadComplete = function () {};

};

THREE.Loader.prototype = {

    constructor: THREE.Loader,

    crossOrigin: 'anonymous',

    addStatusElement: function () {

        var e = document.createElement( "div" );

        e.style.position = "absolute";
        e.style.right = "0px";
        e.style.top = "0px";
        e.style.fontSize = "0.8em";
        e.style.textAlign = "left";
        e.style.background = "rgba(0,0,0,0.25)";
        e.style.color = "#fff";
        e.style.width = "120px";
        e.style.padding = "0.5em 0.5em 0.5em 0.5em";
        e.style.zIndex = 1000;

        e.innerHTML = "Loading ...";

        return e;

    },

    updateProgress: function ( progress ) {

        var message = "Loaded ";

        if ( progress.total ) {

            message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%";


        } else {

            message += ( progress.loaded / 1000 ).toFixed(2) + " KB";

        }

        this.statusDomElement.innerHTML = message;

    },

    extractUrlBase: function ( url ) {

        var parts = url.split( '/' );
        parts.pop();
        return ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';

    },

    initMaterials: function ( scope, materials, texturePath ) {

        scope.materials = [];

        for ( var i = 0; i < materials.length; ++ i ) {

            scope.materials[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath );

        }

    },

    hasNormals: function ( scope ) {

        var m, i, il = scope.materials.length;

        for( i = 0; i < il; i ++ ) {

            m = scope.materials[ i ];

            if ( m instanceof THREE.ShaderMaterial ) return true;

        }

        return false;

    },

    createMaterial: function ( m, texturePath ) {

        var _this = this;

        function is_pow2( n ) {

            var l = Math.log( n ) / Math.LN2;
            return Math.floor( l ) == l;

        }

        function nearest_pow2( n ) {

            var l = Math.log( n ) / Math.LN2;
            return Math.pow( 2, Math.round(  l ) );

        }

        function load_image( where, url ) {

            var image = new Image();

            image.onload = function () {

                if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) {

                    var width = nearest_pow2( this.width );
                    var height = nearest_pow2( this.height );

                    where.image.width = width;
                    where.image.height = height;
                    where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height );

                } else {

                    where.image = this;

                }

                where.needsUpdate = true;

            };

            image.crossOrigin = _this.crossOrigin;
            image.src = url;

        }

        function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) {

            var isCompressed = sourceFile.toLowerCase().endsWith( ".dds" );
            var fullPath = texturePath + "/" + sourceFile;

            if ( isCompressed ) {

                var texture = THREE.ImageUtils.loadCompressedTexture( fullPath );

                where[ name ] = texture;

            } else {

                var texture = document.createElement( 'canvas' );

                where[ name ] = new THREE.Texture( texture );

            }

            where[ name ].sourceFile = sourceFile;

            if( repeat ) {

                where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] );

                if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping;
                if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping;

            }

            if ( offset ) {

                where[ name ].offset.set( offset[ 0 ], offset[ 1 ] );

            }

            if ( wrap ) {

                var wrapMap = {
                    "repeat": THREE.RepeatWrapping,
                    "mirror": THREE.MirroredRepeatWrapping
                }

                if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ];
                if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ];

            }

            if ( anisotropy ) {

                where[ name ].anisotropy = anisotropy;

            }

            if ( ! isCompressed ) {

                load_image( where[ name ], fullPath );

            }

        }

        function rgb2hex( rgb ) {

            return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255;

        }

        // defaults

        var mtype = "MeshLambertMaterial";
        var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false };

        // parameters from model file

        if ( m.shading ) {

            var shading = m.shading.toLowerCase();

            if ( shading === "phong" ) mtype = "MeshPhongMaterial";
            else if ( shading === "basic" ) mtype = "MeshBasicMaterial";

        }

        if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) {

            mpars.blending = THREE[ m.blending ];

        }

        if ( m.transparent !== undefined || m.opacity < 1.0 ) {

            mpars.transparent = m.transparent;

        }

        if ( m.depthTest !== undefined ) {

            mpars.depthTest = m.depthTest;

        }

        if ( m.depthWrite !== undefined ) {

            mpars.depthWrite = m.depthWrite;

        }

        if ( m.visible !== undefined ) {

            mpars.visible = m.visible;

        }

        if ( m.flipSided !== undefined ) {

            mpars.side = THREE.BackSide;

        }

        if ( m.doubleSided !== undefined ) {

            mpars.side = THREE.DoubleSide;

        }

        if ( m.wireframe !== undefined ) {

            mpars.wireframe = m.wireframe;

        }

        if ( m.vertexColors !== undefined ) {

            if ( m.vertexColors === "face" ) {

                mpars.vertexColors = THREE.FaceColors;

            } else if ( m.vertexColors ) {

                mpars.vertexColors = THREE.VertexColors;

            }

        }

        // colors

        if ( m.colorDiffuse ) {

            mpars.color = rgb2hex( m.colorDiffuse );

        } else if ( m.DbgColor ) {

            mpars.color = m.DbgColor;

        }

        if ( m.colorSpecular ) {

            mpars.specular = rgb2hex( m.colorSpecular );

        }

        if ( m.colorAmbient ) {

            mpars.ambient = rgb2hex( m.colorAmbient );

        }

        // modifiers

        if ( m.transparency ) {

            mpars.opacity = m.transparency;

        }

        if ( m.specularCoef ) {

            mpars.shininess = m.specularCoef;

        }

        // textures

        if ( m.mapDiffuse && texturePath ) {

            create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );

        }

        if ( m.mapLight && texturePath ) {

            create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );

        }

        if ( m.mapBump && texturePath ) {

            create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );

        }

        if ( m.mapNormal && texturePath ) {

            create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );

        }

        if ( m.mapSpecular && texturePath ) {

            create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );

        }

        //

        if ( m.mapBumpScale ) {

            mpars.bumpScale = m.mapBumpScale;

        }

        // special case for normal mapped material

        if ( m.mapNormal ) {

            var shader = THREE.ShaderUtils.lib[ "normal" ];
            var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

            uniforms[ "tNormal" ].value = mpars.normalMap;

            if ( m.mapNormalFactor ) {

                uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor );

            }

            if ( mpars.map ) {

                uniforms[ "tDiffuse" ].value = mpars.map;
                uniforms[ "enableDiffuse" ].value = true;

            }

            if ( mpars.specularMap ) {

                uniforms[ "tSpecular" ].value = mpars.specularMap;
                uniforms[ "enableSpecular" ].value = true;

            }

            if ( mpars.lightMap ) {

                uniforms[ "tAO" ].value = mpars.lightMap;
                uniforms[ "enableAO" ].value = true;

            }

            // for the moment don't handle displacement texture

            uniforms[ "uDiffuseColor" ].value.setHex( mpars.color );
            uniforms[ "uSpecularColor" ].value.setHex( mpars.specular );
            uniforms[ "uAmbientColor" ].value.setHex( mpars.ambient );

            uniforms[ "uShininess" ].value = mpars.shininess;

            if ( mpars.opacity !== undefined ) {

                uniforms[ "uOpacity" ].value = mpars.opacity;

            }

            var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
            var material = new THREE.ShaderMaterial( parameters );

        } else {

            var material = new THREE[ mtype ]( mpars );

        }

        if ( m.DbgName !== undefined ) material.name = m.DbgName;

        return material;

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.BinaryLoader = function ( showStatus ) {

    THREE.Loader.call( this, showStatus );

};

THREE.BinaryLoader.prototype = Object.create( THREE.Loader.prototype );

// Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary)
//  - binary models consist of two files: JS and BIN
//  - parameters
//        - url (required)
//        - callback (required)
//        - texturePath (optional: if not specified, textures will be assumed to be in the same folder as JS model file)
//        - binaryPath (optional: if not specified, binary file will be assumed to be in the same folder as JS model file)

THREE.BinaryLoader.prototype.load = function( url, callback, texturePath, binaryPath ) {

    texturePath = texturePath ? texturePath : this.extractUrlBase( url );
    binaryPath = binaryPath ? binaryPath : this.extractUrlBase( url );

    var callbackProgress = this.showProgress ? THREE.Loader.prototype.updateProgress : null;

    this.onLoadStart();

    // #1 load JS part via web worker

    this.loadAjaxJSON( this, url, callback, texturePath, binaryPath, callbackProgress );

};

THREE.BinaryLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, binaryPath, callbackProgress ) {

    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function () {

        if ( xhr.readyState == 4 ) {

            if ( xhr.status == 200 || xhr.status == 0 ) {

                var json = JSON.parse( xhr.responseText );
                context.loadAjaxBuffers( json, callback, binaryPath, texturePath, callbackProgress );

            } else {

                console.error( "THREE.BinaryLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );

            }

        }

    };

    xhr.open( "GET", url, true );
    xhr.send( null );

};

THREE.BinaryLoader.prototype.loadAjaxBuffers = function ( json, callback, binaryPath, texturePath, callbackProgress ) {

    var xhr = new XMLHttpRequest(),
        url = binaryPath + "/" + json.buffers;

    var length = 0;

    xhr.onreadystatechange = function () {

        if ( xhr.readyState == 4 ) {

            if ( xhr.status == 200 || xhr.status == 0 ) {

                var buffer = xhr.response;
                if ( buffer === undefined ) buffer = ( new Uint8Array( xhr.responseBody ) ).buffer; // IEWEBGL needs this
                THREE.BinaryLoader.prototype.createBinModel( buffer, callback, texturePath, json.materials );

            } else {

                console.error( "THREE.BinaryLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );

            }

        } else if ( xhr.readyState == 3 ) {

            if ( callbackProgress ) {

                if ( length == 0 ) {

                    length = xhr.getResponseHeader( "Content-Length" );

                }

                callbackProgress( { total: length, loaded: xhr.responseText.length } );

            }

        } else if ( xhr.readyState == 2 ) {

            length = xhr.getResponseHeader( "Content-Length" );

        }

    };

    xhr.open( "GET", url, true );
    xhr.responseType = "arraybuffer";
    xhr.send( null );

};

// Binary AJAX parser

THREE.BinaryLoader.prototype.createBinModel = function ( data, callback, texturePath, materials ) {

    var Model = function ( texturePath ) {

        var scope = this,
            currentOffset = 0,
            md,
            normals = [],
            uvs = [],
            start_tri_flat, start_tri_smooth, start_tri_flat_uv, start_tri_smooth_uv,
            start_quad_flat, start_quad_smooth, start_quad_flat_uv, start_quad_smooth_uv,
            tri_size, quad_size,
            len_tri_flat, len_tri_smooth, len_tri_flat_uv, len_tri_smooth_uv,
            len_quad_flat, len_quad_smooth, len_quad_flat_uv, len_quad_smooth_uv;


        THREE.Geometry.call( this );

        THREE.Loader.prototype.initMaterials( scope, materials, texturePath );

        md = parseMetaData( data, currentOffset );

        currentOffset += md.header_bytes;
/*
        md.vertex_index_bytes = Uint32Array.BYTES_PER_ELEMENT;
        md.material_index_bytes = Uint16Array.BYTES_PER_ELEMENT;
        md.normal_index_bytes = Uint32Array.BYTES_PER_ELEMENT;
        md.uv_index_bytes = Uint32Array.BYTES_PER_ELEMENT;
*/
        // buffers sizes

        tri_size =  md.vertex_index_bytes * 3 + md.material_index_bytes;
        quad_size = md.vertex_index_bytes * 4 + md.material_index_bytes;

        len_tri_flat      = md.ntri_flat      * ( tri_size );
        len_tri_smooth    = md.ntri_smooth    * ( tri_size + md.normal_index_bytes * 3 );
        len_tri_flat_uv   = md.ntri_flat_uv   * ( tri_size + md.uv_index_bytes * 3 );
        len_tri_smooth_uv = md.ntri_smooth_uv * ( tri_size + md.normal_index_bytes * 3 + md.uv_index_bytes * 3 );

        len_quad_flat      = md.nquad_flat      * ( quad_size );
        len_quad_smooth    = md.nquad_smooth    * ( quad_size + md.normal_index_bytes * 4 );
        len_quad_flat_uv   = md.nquad_flat_uv   * ( quad_size + md.uv_index_bytes * 4 );
        len_quad_smooth_uv = md.nquad_smooth_uv * ( quad_size + md.normal_index_bytes * 4 + md.uv_index_bytes * 4 );

        // read buffers

        currentOffset += init_vertices( currentOffset );

        currentOffset += init_normals( currentOffset );
        currentOffset += handlePadding( md.nnormals * 3 );

        currentOffset += init_uvs( currentOffset );

        start_tri_flat         = currentOffset;
        start_tri_smooth    = start_tri_flat    + len_tri_flat    + handlePadding( md.ntri_flat * 2 );
        start_tri_flat_uv   = start_tri_smooth  + len_tri_smooth  + handlePadding( md.ntri_smooth * 2 );
        start_tri_smooth_uv = start_tri_flat_uv + len_tri_flat_uv + handlePadding( md.ntri_flat_uv * 2 );

        start_quad_flat     = start_tri_smooth_uv + len_tri_smooth_uv  + handlePadding( md.ntri_smooth_uv * 2 );
        start_quad_smooth   = start_quad_flat     + len_quad_flat       + handlePadding( md.nquad_flat * 2 );
        start_quad_flat_uv  = start_quad_smooth   + len_quad_smooth    + handlePadding( md.nquad_smooth * 2 );
        start_quad_smooth_uv= start_quad_flat_uv  + len_quad_flat_uv   + handlePadding( md.nquad_flat_uv * 2 );

        // have to first process faces with uvs
        // so that face and uv indices match

        init_triangles_flat_uv( start_tri_flat_uv );
        init_triangles_smooth_uv( start_tri_smooth_uv );

        init_quads_flat_uv( start_quad_flat_uv );
        init_quads_smooth_uv( start_quad_smooth_uv );

        // now we can process untextured faces

        init_triangles_flat( start_tri_flat );
        init_triangles_smooth( start_tri_smooth );

        init_quads_flat( start_quad_flat );
        init_quads_smooth( start_quad_smooth );

        this.computeCentroids();
        this.computeFaceNormals();

        if ( THREE.Loader.prototype.hasNormals( this ) ) this.computeTangents();

        function handlePadding( n ) {

            return ( n % 4 ) ? ( 4 - n % 4 ) : 0;

        };

        function parseMetaData( data, offset ) {

            var metaData = {

                'signature'               :parseString( data, offset,  12 ),
                'header_bytes'            :parseUChar8( data, offset + 12 ),

                'vertex_coordinate_bytes' :parseUChar8( data, offset + 13 ),
                'normal_coordinate_bytes' :parseUChar8( data, offset + 14 ),
                'uv_coordinate_bytes'     :parseUChar8( data, offset + 15 ),

                'vertex_index_bytes'      :parseUChar8( data, offset + 16 ),
                'normal_index_bytes'      :parseUChar8( data, offset + 17 ),
                'uv_index_bytes'          :parseUChar8( data, offset + 18 ),
                'material_index_bytes'    :parseUChar8( data, offset + 19 ),

                'nvertices'    :parseUInt32( data, offset + 20 ),
                'nnormals'     :parseUInt32( data, offset + 20 + 4*1 ),
                'nuvs'         :parseUInt32( data, offset + 20 + 4*2 ),

                'ntri_flat'      :parseUInt32( data, offset + 20 + 4*3 ),
                'ntri_smooth'    :parseUInt32( data, offset + 20 + 4*4 ),
                'ntri_flat_uv'   :parseUInt32( data, offset + 20 + 4*5 ),
                'ntri_smooth_uv' :parseUInt32( data, offset + 20 + 4*6 ),

                'nquad_flat'      :parseUInt32( data, offset + 20 + 4*7 ),
                'nquad_smooth'    :parseUInt32( data, offset + 20 + 4*8 ),
                'nquad_flat_uv'   :parseUInt32( data, offset + 20 + 4*9 ),
                'nquad_smooth_uv' :parseUInt32( data, offset + 20 + 4*10 )

            };
/*
            console.log( "signature: " + metaData.signature );

            console.log( "header_bytes: " + metaData.header_bytes );
            console.log( "vertex_coordinate_bytes: " + metaData.vertex_coordinate_bytes );
            console.log( "normal_coordinate_bytes: " + metaData.normal_coordinate_bytes );
            console.log( "uv_coordinate_bytes: " + metaData.uv_coordinate_bytes );

            console.log( "vertex_index_bytes: " + metaData.vertex_index_bytes );
            console.log( "normal_index_bytes: " + metaData.normal_index_bytes );
            console.log( "uv_index_bytes: " + metaData.uv_index_bytes );
            console.log( "material_index_bytes: " + metaData.material_index_bytes );

            console.log( "nvertices: " + metaData.nvertices );
            console.log( "nnormals: " + metaData.nnormals );
            console.log( "nuvs: " + metaData.nuvs );

            console.log( "ntri_flat: " + metaData.ntri_flat );
            console.log( "ntri_smooth: " + metaData.ntri_smooth );
            console.log( "ntri_flat_uv: " + metaData.ntri_flat_uv );
            console.log( "ntri_smooth_uv: " + metaData.ntri_smooth_uv );

            console.log( "nquad_flat: " + metaData.nquad_flat );
            console.log( "nquad_smooth: " + metaData.nquad_smooth );
            console.log( "nquad_flat_uv: " + metaData.nquad_flat_uv );
            console.log( "nquad_smooth_uv: " + metaData.nquad_smooth_uv );

            var total = metaData.header_bytes
                      + metaData.nvertices * metaData.vertex_coordinate_bytes * 3
                      + metaData.nnormals * metaData.normal_coordinate_bytes * 3
                      + metaData.nuvs * metaData.uv_coordinate_bytes * 2
                      + metaData.ntri_flat * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes )
                      + metaData.ntri_smooth * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 )
                      + metaData.ntri_flat_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.uv_index_bytes*3 )
                      + metaData.ntri_smooth_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 + metaData.uv_index_bytes*3 )
                      + metaData.nquad_flat * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes )
                      + metaData.nquad_smooth * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 )
                      + metaData.nquad_flat_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.uv_index_bytes*4 )
                      + metaData.nquad_smooth_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 + metaData.uv_index_bytes*4 );
            console.log( "total bytes: " + total );
*/

            return metaData;

        };

        function parseString( data, offset, length ) {

            var charArray = new Uint8Array( data, offset, length );

            var text = "";

            for ( var i = 0; i < length; i ++ ) {

                text += String.fromCharCode( charArray[ offset + i ] );

            }

            return text;

        };

        function parseUChar8( data, offset ) {

            var charArray = new Uint8Array( data, offset, 1 );

            return charArray[ 0 ];

        };

        function parseUInt32( data, offset ) {

            var intArray = new Uint32Array( data, offset, 1 );

            return intArray[ 0 ];

        };

        function init_vertices( start ) {

            var nElements = md.nvertices;

            var coordArray = new Float32Array( data, start, nElements * 3 );

            var i, x, y, z;

            for( i = 0; i < nElements; i ++ ) {

                x = coordArray[ i * 3 ];
                y = coordArray[ i * 3 + 1 ];
                z = coordArray[ i * 3 + 2 ];

                vertex( scope, x, y, z );

            }

            return nElements * 3 * Float32Array.BYTES_PER_ELEMENT;

        };

        function init_normals( start ) {

            var nElements = md.nnormals;

            if ( nElements ) {

                var normalArray = new Int8Array( data, start, nElements * 3 );

                var i, x, y, z;

                for( i = 0; i < nElements; i ++ ) {

                    x = normalArray[ i * 3 ];
                    y = normalArray[ i * 3 + 1 ];
                    z = normalArray[ i * 3 + 2 ];

                    normals.push( x/127, y/127, z/127 );

                }

            }

            return nElements * 3 * Int8Array.BYTES_PER_ELEMENT;

        };

        function init_uvs( start ) {

            var nElements = md.nuvs;

            if ( nElements ) {

                var uvArray = new Float32Array( data, start, nElements * 2 );

                var i, u, v;

                for( i = 0; i < nElements; i ++ ) {

                    u = uvArray[ i * 2 ];
                    v = uvArray[ i * 2 + 1 ];

                    uvs.push( u, v );

                }

            }

            return nElements * 2 * Float32Array.BYTES_PER_ELEMENT;

        };

        function init_uvs3( nElements, offset ) {

            var i, uva, uvb, uvc, u1, u2, u3, v1, v2, v3;

            var uvIndexBuffer = new Uint32Array( data, offset, 3 * nElements );

            for( i = 0; i < nElements; i ++ ) {

                uva = uvIndexBuffer[ i * 3 ];
                uvb = uvIndexBuffer[ i * 3 + 1 ];
                uvc = uvIndexBuffer[ i * 3 + 2 ];

                u1 = uvs[ uva*2 ];
                v1 = uvs[ uva*2 + 1 ];

                u2 = uvs[ uvb*2 ];
                v2 = uvs[ uvb*2 + 1 ];

                u3 = uvs[ uvc*2 ];
                v3 = uvs[ uvc*2 + 1 ];

                uv3( scope.faceVertexUvs[ 0 ], u1, v1, u2, v2, u3, v3 );

            }

        };

        function init_uvs4( nElements, offset ) {

            var i, uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4;

            var uvIndexBuffer = new Uint32Array( data, offset, 4 * nElements );

            for( i = 0; i < nElements; i ++ ) {

                uva = uvIndexBuffer[ i * 4 ];
                uvb = uvIndexBuffer[ i * 4 + 1 ];
                uvc = uvIndexBuffer[ i * 4 + 2 ];
                uvd = uvIndexBuffer[ i * 4 + 3 ];

                u1 = uvs[ uva*2 ];
                v1 = uvs[ uva*2 + 1 ];

                u2 = uvs[ uvb*2 ];
                v2 = uvs[ uvb*2 + 1 ];

                u3 = uvs[ uvc*2 ];
                v3 = uvs[ uvc*2 + 1 ];

                u4 = uvs[ uvd*2 ];
                v4 = uvs[ uvd*2 + 1 ];

                uv4( scope.faceVertexUvs[ 0 ], u1, v1, u2, v2, u3, v3, u4, v4 );

            }

        };

        function init_faces3_flat( nElements, offsetVertices, offsetMaterials ) {

            var i, a, b, c, m;

            var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements );
            var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements );

            for( i = 0; i < nElements; i ++ ) {

                a = vertexIndexBuffer[ i * 3 ];
                b = vertexIndexBuffer[ i * 3 + 1 ];
                c = vertexIndexBuffer[ i * 3 + 2 ];

                m = materialIndexBuffer[ i ];

                f3( scope, a, b, c, m );

            }

        };

        function init_faces4_flat( nElements, offsetVertices, offsetMaterials ) {

            var i, a, b, c, d, m;

            var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements );
            var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements );

            for( i = 0; i < nElements; i ++ ) {

                a = vertexIndexBuffer[ i * 4 ];
                b = vertexIndexBuffer[ i * 4 + 1 ];
                c = vertexIndexBuffer[ i * 4 + 2 ];
                d = vertexIndexBuffer[ i * 4 + 3 ];

                m = materialIndexBuffer[ i ];

                f4( scope, a, b, c, d, m );

            }

        };

        function init_faces3_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) {

            var i, a, b, c, m;
            var na, nb, nc;

            var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements );
            var normalIndexBuffer = new Uint32Array( data, offsetNormals, 3 * nElements );
            var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements );

            for( i = 0; i < nElements; i ++ ) {

                a = vertexIndexBuffer[ i * 3 ];
                b = vertexIndexBuffer[ i * 3 + 1 ];
                c = vertexIndexBuffer[ i * 3 + 2 ];

                na = normalIndexBuffer[ i * 3 ];
                nb = normalIndexBuffer[ i * 3 + 1 ];
                nc = normalIndexBuffer[ i * 3 + 2 ];

                m = materialIndexBuffer[ i ];

                f3n( scope, normals, a, b, c, m, na, nb, nc );

            }

        };

        function init_faces4_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) {

            var i, a, b, c, d, m;
            var na, nb, nc, nd;

            var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements );
            var normalIndexBuffer = new Uint32Array( data, offsetNormals, 4 * nElements );
            var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements );

            for( i = 0; i < nElements; i ++ ) {

                a = vertexIndexBuffer[ i * 4 ];
                b = vertexIndexBuffer[ i * 4 + 1 ];
                c = vertexIndexBuffer[ i * 4 + 2 ];
                d = vertexIndexBuffer[ i * 4 + 3 ];

                na = normalIndexBuffer[ i * 4 ];
                nb = normalIndexBuffer[ i * 4 + 1 ];
                nc = normalIndexBuffer[ i * 4 + 2 ];
                nd = normalIndexBuffer[ i * 4 + 3 ];

                m = materialIndexBuffer[ i ];

                f4n( scope, normals, a, b, c, d, m, na, nb, nc, nd );

            }

        };

        function init_triangles_flat( start ) {

            var nElements = md.ntri_flat;

            if ( nElements ) {

                var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;
                init_faces3_flat( nElements, start, offsetMaterials );

            }

        };

        function init_triangles_flat_uv( start ) {

            var nElements = md.ntri_flat_uv;

            if ( nElements ) {

                var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;
                var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;

                init_faces3_flat( nElements, start, offsetMaterials );
                init_uvs3( nElements, offsetUvs );

            }

        };

        function init_triangles_smooth( start ) {

            var nElements = md.ntri_smooth;

            if ( nElements ) {

                var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;
                var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;

                init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials );

            }

        };

        function init_triangles_smooth_uv( start ) {

            var nElements = md.ntri_smooth_uv;

            if ( nElements ) {

                var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;
                var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;
                var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3;

                init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials );
                init_uvs3( nElements, offsetUvs );

            }

        };

        function init_quads_flat( start ) {

            var nElements = md.nquad_flat;

            if ( nElements ) {

                var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;
                init_faces4_flat( nElements, start, offsetMaterials );

            }

        };

        function init_quads_flat_uv( start ) {

            var nElements = md.nquad_flat_uv;

            if ( nElements ) {

                var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;
                var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;

                init_faces4_flat( nElements, start, offsetMaterials );
                init_uvs4( nElements, offsetUvs );

            }

        };

        function init_quads_smooth( start ) {

            var nElements = md.nquad_smooth;

            if ( nElements ) {

                var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;
                var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;

                init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials );

            }

        };

        function init_quads_smooth_uv( start ) {

            var nElements = md.nquad_smooth_uv;

            if ( nElements ) {

                var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;
                var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;
                var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4;

                init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials );
                init_uvs4( nElements, offsetUvs );

            }

        };

    };

    function vertex ( scope, x, y, z ) {

        scope.vertices.push( new THREE.Vector3( x, y, z ) );

    };

    function f3 ( scope, a, b, c, mi ) {

        scope.faces.push( new THREE.Face3( a, b, c, null, null, mi ) );

    };

    function f4 ( scope, a, b, c, d, mi ) {

        scope.faces.push( new THREE.Face4( a, b, c, d, null, null, mi ) );

    };

    function f3n ( scope, normals, a, b, c, mi, na, nb, nc ) {

        var nax = normals[ na*3     ],
            nay = normals[ na*3 + 1 ],
            naz = normals[ na*3 + 2 ],

            nbx = normals[ nb*3     ],
            nby = normals[ nb*3 + 1 ],
            nbz = normals[ nb*3 + 2 ],

            ncx = normals[ nc*3     ],
            ncy = normals[ nc*3 + 1 ],
            ncz = normals[ nc*3 + 2 ];

        scope.faces.push( new THREE.Face3( a, b, c,
                          [new THREE.Vector3( nax, nay, naz ),
                           new THREE.Vector3( nbx, nby, nbz ),
                           new THREE.Vector3( ncx, ncy, ncz )],
                          null,
                          mi ) );

    };

    function f4n ( scope, normals, a, b, c, d, mi, na, nb, nc, nd ) {

        var nax = normals[ na*3     ],
            nay = normals[ na*3 + 1 ],
            naz = normals[ na*3 + 2 ],

            nbx = normals[ nb*3     ],
            nby = normals[ nb*3 + 1 ],
            nbz = normals[ nb*3 + 2 ],

            ncx = normals[ nc*3     ],
            ncy = normals[ nc*3 + 1 ],
            ncz = normals[ nc*3 + 2 ],

            ndx = normals[ nd*3     ],
            ndy = normals[ nd*3 + 1 ],
            ndz = normals[ nd*3 + 2 ];

        scope.faces.push( new THREE.Face4( a, b, c, d,
                          [new THREE.Vector3( nax, nay, naz ),
                           new THREE.Vector3( nbx, nby, nbz ),
                           new THREE.Vector3( ncx, ncy, ncz ),
                           new THREE.Vector3( ndx, ndy, ndz )],
                          null,
                          mi ) );

    };

    function uv3 ( where, u1, v1, u2, v2, u3, v3 ) {

        var uv = [];
        uv.push( new THREE.UV( u1, v1 ) );
        uv.push( new THREE.UV( u2, v2 ) );
        uv.push( new THREE.UV( u3, v3 ) );
        where.push( uv );

    };

    function uv4 ( where, u1, v1, u2, v2, u3, v3, u4, v4 ) {

        var uv = [];
        uv.push( new THREE.UV( u1, v1 ) );
        uv.push( new THREE.UV( u2, v2 ) );
        uv.push( new THREE.UV( u3, v3 ) );
        uv.push( new THREE.UV( u4, v4 ) );
        where.push( uv );

    };

    Model.prototype = Object.create( THREE.Geometry.prototype );

    callback( new Model( texturePath ) );

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.ImageLoader = function () {

    THREE.EventTarget.call( this );

    this.crossOrigin = null;

};

THREE.ImageLoader.prototype = {

    constructor: THREE.ImageLoader,

    load: function ( url, image ) {

        var scope = this;

        if ( image === undefined ) image = new Image();

        image.addEventListener( 'load', function () {

            scope.dispatchEvent( { type: 'load', content: image } );

        }, false );

        image.addEventListener( 'error', function () {

            scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );

        }, false );

        if ( scope.crossOrigin ) image.crossOrigin = scope.crossOrigin;

        image.src = url;

    }

}
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.JSONLoader = function ( showStatus ) {

    THREE.Loader.call( this, showStatus );

};

THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype );

THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {

    var scope = this;

    texturePath = texturePath ? texturePath : this.extractUrlBase( url );

    this.onLoadStart();
    this.loadAjaxJSON( this, url, callback, texturePath );

};

THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) {

    var xhr = new XMLHttpRequest();

    var length = 0;

    xhr.onreadystatechange = function () {

        if ( xhr.readyState === xhr.DONE ) {

            if ( xhr.status === 200 || xhr.status === 0 ) {

                if ( xhr.responseText ) {

                    var json = JSON.parse( xhr.responseText );
                    context.createModel( json, callback, texturePath );

                } else {

                    console.warn( "THREE.JSONLoader: [" + url + "] seems to be unreachable or file there is empty" );

                }

                // in context of more complex asset initialization
                // do not block on single failed file
                // maybe should go even one more level up

                context.onLoadComplete();

            } else {

                console.error( "THREE.JSONLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );

            }

        } else if ( xhr.readyState === xhr.LOADING ) {

            if ( callbackProgress ) {

                if ( length === 0 ) {

                    length = xhr.getResponseHeader( "Content-Length" );

                }

                callbackProgress( { total: length, loaded: xhr.responseText.length } );

            }

        } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) {

            length = xhr.getResponseHeader( "Content-Length" );

        }

    };

    xhr.open( "GET", url, true );
    xhr.send( null );

};

THREE.JSONLoader.prototype.createModel = function ( json, callback, texturePath ) {

    var scope = this,
    geometry = new THREE.Geometry(),
    scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;

    this.initMaterials( geometry, json.materials, texturePath );

    parseModel( scale );

    parseSkin();
    parseMorphing( scale );

    geometry.computeCentroids();
    geometry.computeFaceNormals();

    if ( this.hasNormals( geometry ) ) geometry.computeTangents();


    function parseModel( scale ) {

        function isBitSet( value, position ) {

            return value & ( 1 << position );

        }

        var i, j, fi,

        offset, zLength, nVertices,

        colorIndex, normalIndex, uvIndex, materialIndex,

        type,
        isQuad,
        hasMaterial,
        hasFaceUv, hasFaceVertexUv,
        hasFaceNormal, hasFaceVertexNormal,
        hasFaceColor, hasFaceVertexColor,

        vertex, face, color, normal,

        uvLayer, uvs, u, v,

        faces = json.faces,
        vertices = json.vertices,
        normals = json.normals,
        colors = json.colors,

        nUvLayers = 0;

        // disregard empty arrays

        for ( i = 0; i < json.uvs.length; i++ ) {

            if ( json.uvs[ i ].length ) nUvLayers ++;

        }

        for ( i = 0; i < nUvLayers; i++ ) {

            geometry.faceUvs[ i ] = [];
            geometry.faceVertexUvs[ i ] = [];

        }

        offset = 0;
        zLength = vertices.length;

        while ( offset < zLength ) {

            vertex = new THREE.Vector3();

            vertex.x = vertices[ offset ++ ] * scale;
            vertex.y = vertices[ offset ++ ] * scale;
            vertex.z = vertices[ offset ++ ] * scale;

            geometry.vertices.push( vertex );

        }

        offset = 0;
        zLength = faces.length;

        while ( offset < zLength ) {

            type = faces[ offset ++ ];


            isQuad              = isBitSet( type, 0 );
            hasMaterial         = isBitSet( type, 1 );
            hasFaceUv           = isBitSet( type, 2 );
            hasFaceVertexUv     = isBitSet( type, 3 );
            hasFaceNormal       = isBitSet( type, 4 );
            hasFaceVertexNormal = isBitSet( type, 5 );
            hasFaceColor        = isBitSet( type, 6 );
            hasFaceVertexColor  = isBitSet( type, 7 );

            //console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);

            if ( isQuad ) {

                face = new THREE.Face4();

                face.a = faces[ offset ++ ];
                face.b = faces[ offset ++ ];
                face.c = faces[ offset ++ ];
                face.d = faces[ offset ++ ];

                nVertices = 4;

            } else {

                face = new THREE.Face3();

                face.a = faces[ offset ++ ];
                face.b = faces[ offset ++ ];
                face.c = faces[ offset ++ ];

                nVertices = 3;

            }

            if ( hasMaterial ) {

                materialIndex = faces[ offset ++ ];
                face.materialIndex = materialIndex;

            }

            // to get face <=> uv index correspondence

            fi = geometry.faces.length;

            if ( hasFaceUv ) {

                for ( i = 0; i < nUvLayers; i++ ) {

                    uvLayer = json.uvs[ i ];

                    uvIndex = faces[ offset ++ ];

                    u = uvLayer[ uvIndex * 2 ];
                    v = uvLayer[ uvIndex * 2 + 1 ];

                    geometry.faceUvs[ i ][ fi ] = new THREE.UV( u, v );

                }

            }

            if ( hasFaceVertexUv ) {

                for ( i = 0; i < nUvLayers; i++ ) {

                    uvLayer = json.uvs[ i ];

                    uvs = [];

                    for ( j = 0; j < nVertices; j ++ ) {

                        uvIndex = faces[ offset ++ ];

                        u = uvLayer[ uvIndex * 2 ];
                        v = uvLayer[ uvIndex * 2 + 1 ];

                        uvs[ j ] = new THREE.UV( u, v );

                    }

                    geometry.faceVertexUvs[ i ][ fi ] = uvs;

                }

            }

            if ( hasFaceNormal ) {

                normalIndex = faces[ offset ++ ] * 3;

                normal = new THREE.Vector3();

                normal.x = normals[ normalIndex ++ ];
                normal.y = normals[ normalIndex ++ ];
                normal.z = normals[ normalIndex ];

                face.normal = normal;

            }

            if ( hasFaceVertexNormal ) {

                for ( i = 0; i < nVertices; i++ ) {

                    normalIndex = faces[ offset ++ ] * 3;

                    normal = new THREE.Vector3();

                    normal.x = normals[ normalIndex ++ ];
                    normal.y = normals[ normalIndex ++ ];
                    normal.z = normals[ normalIndex ];

                    face.vertexNormals.push( normal );

                }

            }


            if ( hasFaceColor ) {

                colorIndex = faces[ offset ++ ];

                color = new THREE.Color( colors[ colorIndex ] );
                face.color = color;

            }


            if ( hasFaceVertexColor ) {

                for ( i = 0; i < nVertices; i++ ) {

                    colorIndex = faces[ offset ++ ];

                    color = new THREE.Color( colors[ colorIndex ] );
                    face.vertexColors.push( color );

                }

            }

            geometry.faces.push( face );

        }

    };

    function parseSkin() {

        var i, l, x, y, z, w, a, b, c, d;

        if ( json.skinWeights ) {

            for ( i = 0, l = json.skinWeights.length; i < l; i += 2 ) {

                x = json.skinWeights[ i     ];
                y = json.skinWeights[ i + 1 ];
                z = 0;
                w = 0;

                geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );

            }

        }

        if ( json.skinIndices ) {

            for ( i = 0, l = json.skinIndices.length; i < l; i += 2 ) {

                a = json.skinIndices[ i     ];
                b = json.skinIndices[ i + 1 ];
                c = 0;
                d = 0;

                geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );

            }

        }

        geometry.bones = json.bones;
        geometry.animation = json.animation;

    };

    function parseMorphing( scale ) {

        if ( json.morphTargets !== undefined ) {

            var i, l, v, vl, dstVertices, srcVertices;

            for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {

                geometry.morphTargets[ i ] = {};
                geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
                geometry.morphTargets[ i ].vertices = [];

                dstVertices = geometry.morphTargets[ i ].vertices;
                srcVertices = json.morphTargets [ i ].vertices;

                for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {

                    var vertex = new THREE.Vector3();
                    vertex.x = srcVertices[ v ] * scale;
                    vertex.y = srcVertices[ v + 1 ] * scale;
                    vertex.z = srcVertices[ v + 2 ] * scale;

                    dstVertices.push( vertex );

                }

            }

        }

        if ( json.morphColors !== undefined ) {

            var i, l, c, cl, dstColors, srcColors, color;

            for ( i = 0, l = json.morphColors.length; i < l; i++ ) {

                geometry.morphColors[ i ] = {};
                geometry.morphColors[ i ].name = json.morphColors[ i ].name;
                geometry.morphColors[ i ].colors = [];

                dstColors = geometry.morphColors[ i ].colors;
                srcColors = json.morphColors [ i ].colors;

                for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) {

                    color = new THREE.Color( 0xffaa00 );
                    color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );
                    dstColors.push( color );

                }

            }

        }

    };

    callback( geometry );

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.LoadingMonitor = function () {

    THREE.EventTarget.call( this );

    var scope = this;

    var loaded = 0;
    var total = 0;

    var onLoad = function ( event ) {

        loaded ++;

        scope.dispatchEvent( { type: 'progress', loaded: loaded, total: total } );

        if ( loaded === total ) {

            scope.dispatchEvent( { type: 'load' } );

        }

    };

    this.add = function ( loader ) {

        total ++;

        loader.addEventListener( 'load', onLoad, false );

    };

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.GeometryLoader = function () {

    THREE.EventTarget.call( this );

    this.crossOrigin = null;
    this.path = null;


};

THREE.GeometryLoader.prototype = {

    constructor: THREE.GeometryLoader,

    load: function ( url ) {

        var scope = this;
        var geometry = null;

        if ( scope.path === null ) {

            var parts = url.split( '/' ); parts.pop();
            scope.path = ( parts.length < 1 ? '.' : parts.join( '/' ) );

        }

        //

        var xhr = new XMLHttpRequest();

        xhr.addEventListener( 'load', function ( event ) {

            if ( event.target.responseText ) {

                geometry = scope.parse( JSON.parse( event.target.responseText ), monitor );

            } else {

                scope.dispatchEvent( { type: 'error', message: 'Invalid file [' + url + ']' } );

            }

        }, false );

        xhr.addEventListener( 'error', function () {

            scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );

        }, false );

        xhr.open( 'GET', url, true );
        xhr.send( null );

        //

        var monitor = new THREE.LoadingMonitor();

        monitor.addEventListener( 'load', function ( event ) {

            scope.dispatchEvent( { type: 'load', content: geometry } );

        } );

        monitor.add( xhr );

    },

    parse: function ( data, monitor ) {

        var scope = this;
        var geometry = new THREE.Geometry();

        var scale = ( data.scale !== undefined ) ? 1 / data.scale : 1;

        // materials

        if ( data.materials ) {

            geometry.materials = [];

            for ( var i = 0; i < data.materials.length; ++ i ) {

                var m = data.materials[ i ];

                function isPow2( n ) {

                    var l = Math.log( n ) / Math.LN2;
                    return Math.floor( l ) == l;

                }

                function nearestPow2( n ) {

                    var l = Math.log( n ) / Math.LN2;
                    return Math.pow( 2, Math.round(  l ) );

                }

                function createTexture( where, name, sourceFile, repeat, offset, wrap ) {

                    where[ name ] = new THREE.Texture();
                    where[ name ].sourceFile = sourceFile;

                    if ( repeat ) {

                        where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] );

                        if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping;
                        if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping;

                    }

                    if ( offset ) {

                        where[ name ].offset.set( offset[ 0 ], offset[ 1 ] );

                    }

                    if ( wrap ) {

                        var wrapMap = {

                            "repeat": THREE.RepeatWrapping,
                            "mirror": THREE.MirroredRepeatWrapping

                        }

                        if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ];
                        if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ];

                    }

                    // load image

                    var texture = where[ name ];

                    var loader = new THREE.ImageLoader();
                    loader.addEventListener( 'load', function ( event ) {

                        var image = event.content;

                        if ( !isPow2( image.width ) || !isPow2( image.height ) ) {

                            var width = nearestPow2( image.width );
                            var height = nearestPow2( image.height );

                            texture.image = document.createElement( 'canvas' );
                            texture.image.width = width;
                            texture.image.height = height;
                            texture.image.getContext( '2d' ).drawImage( image, 0, 0, width, height );

                        } else {

                            texture.image = image;

                        }

                        texture.needsUpdate = true;

                    } );
                    loader.crossOrigin = scope.crossOrigin;
                    loader.load( scope.path + '/' + sourceFile );

                    if ( monitor ) monitor.add( loader );

                }

                function rgb2hex( rgb ) {

                    return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255;

                }

                // defaults

                var mtype = "MeshLambertMaterial";
                var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false };

                // parameters from model file

                if ( m.shading ) {

                    var shading = m.shading.toLowerCase();

                    if ( shading === "phong" ) mtype = "MeshPhongMaterial";
                    else if ( shading === "basic" ) mtype = "MeshBasicMaterial";

                }

                if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) {

                    mpars.blending = THREE[ m.blending ];

                }

                if ( m.transparent !== undefined || m.opacity < 1.0 ) {

                    mpars.transparent = m.transparent;

                }

                if ( m.depthTest !== undefined ) {

                    mpars.depthTest = m.depthTest;

                }

                if ( m.depthWrite !== undefined ) {

                    mpars.depthWrite = m.depthWrite;

                }

                if ( m.vertexColors !== undefined ) {

                    if ( m.vertexColors == "face" ) {

                        mpars.vertexColors = THREE.FaceColors;

                    } else if ( m.vertexColors ) {

                        mpars.vertexColors = THREE.VertexColors;

                    }

                }

                // colors

                if ( m.colorDiffuse ) {

                    mpars.color = rgb2hex( m.colorDiffuse );

                } else if ( m.DbgColor ) {

                    mpars.color = m.DbgColor;

                }

                if ( m.colorSpecular ) {

                    mpars.specular = rgb2hex( m.colorSpecular );

                }

                if ( m.colorAmbient ) {

                    mpars.ambient = rgb2hex( m.colorAmbient );

                }

                // modifiers

                if ( m.transparency ) {

                    mpars.opacity = m.transparency;

                }

                if ( m.specularCoef ) {

                    mpars.shininess = m.specularCoef;

                }

                if ( m.visible !== undefined ) {

                    mpars.visible = m.visible;

                }

                if ( m.flipSided !== undefined ) {

                    mpars.side = THREE.BackSide;

                }

                if ( m.doubleSided !== undefined ) {

                    mpars.side = THREE.DoubleSide;

                }

                if ( m.wireframe !== undefined ) {

                    mpars.wireframe = m.wireframe;

                }

                // textures

                if ( m.mapDiffuse ) {

                    createTexture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap );

                }

                if ( m.mapLight ) {

                    createTexture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap );

                }

                if ( m.mapBump ) {

                    createTexture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap );

                }

                if ( m.mapNormal ) {

                    createTexture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap );

                }

                if ( m.mapSpecular ) {

                    createTexture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap );

                }

                // special case for normal mapped material

                if ( m.mapNormal ) {

                    var shader = THREE.ShaderUtils.lib[ "normal" ];
                    var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

                    uniforms[ "tNormal" ].value = mpars.normalMap;

                    if ( m.mapNormalFactor ) {

                        uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor );

                    }

                    if ( mpars.map ) {

                        uniforms[ "tDiffuse" ].value = mpars.map;
                        uniforms[ "enableDiffuse" ].value = true;

                    }

                    if ( mpars.specularMap ) {

                        uniforms[ "tSpecular" ].value = mpars.specularMap;
                        uniforms[ "enableSpecular" ].value = true;

                    }

                    if ( mpars.lightMap ) {

                        uniforms[ "tAO" ].value = mpars.lightMap;
                        uniforms[ "enableAO" ].value = true;

                    }

                    // for the moment don't handle displacement texture

                    uniforms[ "uDiffuseColor" ].value.setHex( mpars.color );
                    uniforms[ "uSpecularColor" ].value.setHex( mpars.specular );
                    uniforms[ "uAmbientColor" ].value.setHex( mpars.ambient );

                    uniforms[ "uShininess" ].value = mpars.shininess;

                    if ( mpars.opacity !== undefined ) {

                        uniforms[ "uOpacity" ].value = mpars.opacity;

                    }

                    var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
                    var material = new THREE.ShaderMaterial( parameters );

                } else {

                    var material = new THREE[ mtype ]( mpars );

                }

                if ( m.DbgName !== undefined ) material.name = m.DbgName;

                geometry.materials[ i ] = material;

            }

        }

        // geometry

        function isBitSet( value, position ) {

            return value & ( 1 << position );

        }

        var faces = data.faces;
        var vertices = data.vertices;
        var normals = data.normals;
        var colors = data.colors;
        var nUvLayers = 0;

        // disregard empty arrays

        if ( data.uvs ) {

            for ( var i = 0; i < data.uvs.length; i ++ ) {

                if ( data.uvs[ i ].length ) nUvLayers ++;

            }

        }

        for ( var i = 0; i < nUvLayers; i ++ ) {

            geometry.faceUvs[ i ] = [];
            geometry.faceVertexUvs[ i ] = [];

        }

        var offset = 0;
        var zLength = vertices.length;

        while ( offset < zLength ) {

            var vertex = new THREE.Vector3();

            vertex.x = vertices[ offset ++ ] * scale;
            vertex.y = vertices[ offset ++ ] * scale;
            vertex.z = vertices[ offset ++ ] * scale;

            geometry.vertices.push( vertex );

        }

        offset = 0;
        zLength = faces.length;

        while ( offset < zLength ) {

            var type = faces[ offset ++ ];

            var isQuad = isBitSet( type, 0 );

            var hasMaterial = isBitSet( type, 1 );
            var hasFaceUv = isBitSet( type, 2 );
            var hasFaceVertexUv = isBitSet( type, 3 );
            var hasFaceNormal = isBitSet( type, 4 );
            var hasFaceVertexNormal = isBitSet( type, 5 );
            var hasFaceColor = isBitSet( type, 6 );
            var hasFaceVertexColor = isBitSet( type, 7 );

            // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);

            if ( isQuad ) {

                var face = new THREE.Face4();

                face.a = faces[ offset ++ ];
                face.b = faces[ offset ++ ];
                face.c = faces[ offset ++ ];
                face.d = faces[ offset ++ ];

                var nVertices = 4;

            } else {

                var face = new THREE.Face3();

                face.a = faces[ offset ++ ];
                face.b = faces[ offset ++ ];
                face.c = faces[ offset ++ ];

                var nVertices = 3;

            }

            if ( hasMaterial ) {

                var materialIndex = faces[ offset ++ ];
                face.materialIndex = materialIndex;

            }

            // to get face <=> uv index correspondence

            var fi = geometry.faces.length;

            if ( hasFaceUv ) {

                for ( var i = 0; i < nUvLayers; i ++ ) {

                    var uvLayer = data.uvs[ i ];

                    var uvIndex = faces[ offset ++ ];

                    var u = uvLayer[ uvIndex * 2 ];
                    var v = uvLayer[ uvIndex * 2 + 1 ];

                    geometry.faceUvs[ i ][ fi ] = new THREE.UV( u, v );

                }

            }

            if ( hasFaceVertexUv ) {

                for ( var i = 0; i < nUvLayers; i ++ ) {

                    var uvLayer = data.uvs[ i ];

                    var uvs = [];

                    for ( var j = 0; j < nVertices; j ++ ) {

                        var uvIndex = faces[ offset ++ ];

                        var u = uvLayer[ uvIndex * 2 ];
                        var v = uvLayer[ uvIndex * 2 + 1 ];

                        uvs[ j ] = new THREE.UV( u, v );

                    }

                    geometry.faceVertexUvs[ i ][ fi ] = uvs;

                }

            }

            if ( hasFaceNormal ) {

                var normalIndex = faces[ offset ++ ] * 3;

                var normal = new THREE.Vector3();

                normal.x = normals[ normalIndex ++ ];
                normal.y = normals[ normalIndex ++ ];
                normal.z = normals[ normalIndex ];

                face.normal = normal;

            }

            if ( hasFaceVertexNormal ) {

                for ( i = 0; i < nVertices; i ++ ) {

                    var normalIndex = faces[ offset ++ ] * 3;

                    var normal = new THREE.Vector3();

                    normal.x = normals[ normalIndex ++ ];
                    normal.y = normals[ normalIndex ++ ];
                    normal.z = normals[ normalIndex ];

                    face.vertexNormals.push( normal );

                }

            }


            if ( hasFaceColor ) {

                var colorIndex = faces[ offset ++ ];

                face.color = new THREE.Color( colors[ colorIndex ] );

            }


            if ( hasFaceVertexColor ) {

                for ( var i = 0; i < nVertices; i ++ ) {

                    var colorIndex = faces[ offset ++ ];

                    face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );

                }

            }

            geometry.faces.push( face );

        }


        // skin

        if ( data.skinWeights ) {

            for ( var i = 0, l = data.skinWeights.length; i < l; i += 2 ) {

                var x = data.skinWeights[ i ];
                var y = data.skinWeights[ i + 1 ];
                var z = 0;
                var w = 0;

                geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );

            }

        }

        if ( data.skinIndices ) {

            for ( var i = 0, l = data.skinIndices.length; i < l; i += 2 ) {

                var a = data.skinIndices[ i ];
                var b = data.skinIndices[ i + 1 ];
                var c = 0;
                var d = 0;

                geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );

            }

        }

        geometry.bones = data.bones;
        geometry.animation = data.animation;


        // morphing

        if ( data.morphTargets ) {

            for ( var i = 0, l = data.morphTargets.length; i < l; i ++ ) {

                geometry.morphTargets[ i ] = {};
                geometry.morphTargets[ i ].name = data.morphTargets[ i ].name;
                geometry.morphTargets[ i ].vertices = [];

                var dstVertices = geometry.morphTargets[ i ].vertices;
                var srcVertices = data.morphTargets [ i ].vertices;

                for( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {

                    var vertex = new THREE.Vector3();
                    vertex.x = srcVertices[ v ] * scale;
                    vertex.y = srcVertices[ v + 1 ] * scale;
                    vertex.z = srcVertices[ v + 2 ] * scale;

                    dstVertices.push( vertex );

                }

            }

        }

        if ( data.morphColors ) {

            for ( var i = 0, l = data.morphColors.length; i < l; i++ ) {

                geometry.morphColors[ i ] = {};
                geometry.morphColors[ i ].name = data.morphColors[ i ].name;
                geometry.morphColors[ i ].colors = [];

                var dstColors = geometry.morphColors[ i ].colors;
                var srcColors = data.morphColors [ i ].colors;

                for ( var c = 0, cl = srcColors.length; c < cl; c += 3 ) {

                    var color = new THREE.Color( 0xffaa00 );
                    color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );

                    dstColors.push( color );

                }

            }

        }

        geometry.computeCentroids();
        geometry.computeFaceNormals();

        return geometry;

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SceneLoader = function () {

    this.onLoadStart = function () {};
    this.onLoadProgress = function() {};
    this.onLoadComplete = function () {};

    this.callbackSync = function () {};
    this.callbackProgress = function () {};

    this.geometryHandlerMap = {};

    this.addGeometryHandler( "ascii", THREE.JSONLoader );
    this.addGeometryHandler( "binary", THREE.BinaryLoader );

};

THREE.SceneLoader.prototype.constructor = THREE.SceneLoader;

THREE.SceneLoader.prototype.load = function ( url, callbackFinished ) {

    var scope = this;

    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function () {

        if ( xhr.readyState === 4 ) {

            if ( xhr.status === 200 || xhr.status === 0 ) {

                var json = JSON.parse( xhr.responseText );
                scope.parse( json, callbackFinished, url );

            } else {

                console.error( "THREE.SceneLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );

            }

        }

    };

    xhr.open( "GET", url, true );
    xhr.send( null );

};

THREE.SceneLoader.prototype.addGeometryHandler = function ( typeID, loaderClass ) {

    this.geometryHandlerMap[ typeID ] = { "loaderClass": loaderClass };

};

THREE.SceneLoader.prototype.parse = function ( json, callbackFinished, url ) {

    var scope = this;

    var urlBase = THREE.Loader.prototype.extractUrlBase( url );

    var dg, dm, dl, dc, df, dt,
        g, m, l, d, p, r, q, s, c, t, f, tt, pp, u,
        geometry, material, camera, fog,
        texture, images,
        light,
        counter_models, counter_textures,
        total_models, total_textures,
        result;

    var data = json;

    // async geometry loaders

    for ( var typeID in this.geometryHandlerMap ) {

        var loaderClass = this.geometryHandlerMap[ typeID ][ "loaderClass" ];
        this.geometryHandlerMap[ typeID ][ "loaderObject" ] = new loaderClass();

    }

    counter_models = 0;
    counter_textures = 0;

    result = {

        scene: new THREE.Scene(),
        geometries: {},
        materials: {},
        textures: {},
        objects: {},
        cameras: {},
        lights: {},
        fogs: {},
        empties: {}

    };

    if ( data.transform ) {

        var position = data.transform.position,
            rotation = data.transform.rotation,
            scale = data.transform.scale;

        if ( position )
            result.scene.position.set( position[ 0 ], position[ 1 ], position [ 2 ] );

        if ( rotation )
            result.scene.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation [ 2 ] );

        if ( scale )
            result.scene.scale.set( scale[ 0 ], scale[ 1 ], scale [ 2 ] );

        if ( position || rotation || scale ) {

            result.scene.updateMatrix();
            result.scene.updateMatrixWorld();

        }

    }

    function get_url( source_url, url_type ) {

        if ( url_type == "relativeToHTML" ) {

            return source_url;

        } else {

            return urlBase + "/" + source_url;

        }

    };

    // toplevel loader function, delegates to handle_children

    function handle_objects() {

        handle_children( result.scene, data.objects );

    }

    // handle all the children from the loaded json and attach them to given parent

    function handle_children( parent, children ) {

        for ( var dd in children ) {

            // check by id if child has already been handled,
            // if not, create new object

            if ( result.objects[ dd ] === undefined ) {

                var o = children[ dd ];

                var object = null;

                if ( o.geometry !== undefined ) {

                    geometry = result.geometries[ o.geometry ];

                    // geometry already loaded

                    if ( geometry ) {

                        var hasNormals = false;

                        // not anymore support for multiple materials
                        // shouldn't really be array

                        material = result.materials[ o.materials[ 0 ] ];
                        hasNormals = material instanceof THREE.ShaderMaterial;

                        if ( hasNormals ) {

                            geometry.computeTangents();

                        }

                        p = o.position;
                        r = o.rotation;
                        q = o.quaternion;
                        s = o.scale;
                        m = o.matrix;

                        // turn off quaternions, for the moment

                        q = 0;

                        if ( o.materials.length === 0 ) {

                            material = new THREE.MeshFaceMaterial();

                        }

                        // dirty hack to handle meshes with multiple materials
                        // just use face materials defined in model

                        if ( o.materials.length > 1 ) {

                            material = new THREE.MeshFaceMaterial();

                        }

                        if ( o.morph ) {

                            object = new THREE.MorphAnimMesh( geometry, material );

                            if ( o.duration !== undefined ) {

                                object.duration = o.duration;

                            }

                            if ( o.time !== undefined ) {

                                object.time = o.time;

                            }

                            if ( o.mirroredLoop !== undefined ) {

                                object.mirroredLoop = o.mirroredLoop;

                            }

                            if ( material.morphNormals ) {

                                geometry.computeMorphNormals();

                            }

                        } else {

                            object = new THREE.Mesh( geometry, material );

                        }

                        object.name = dd;

                        if ( m ) {

                            object.matrixAutoUpdate = false;
                            object.matrix.set(
                                m[0], m[1], m[2], m[3],
                                m[4], m[5], m[6], m[7],
                                m[8], m[9], m[10], m[11],
                                m[12], m[13], m[14], m[15]
                            );

                        } else {

                            object.position.set( p[0], p[1], p[2] );

                            if ( q ) {

                                object.quaternion.set( q[0], q[1], q[2], q[3] );
                                object.useQuaternion = true;

                            } else {

                                object.rotation.set( r[0], r[1], r[2] );

                            }

                            object.scale.set( s[0], s[1], s[2] );

                        }

                        object.visible = o.visible;
                        object.castShadow = o.castShadow;
                        object.receiveShadow = o.receiveShadow;

                        parent.add( object );

                        result.objects[ dd ] = object;

                    }

                // pure Object3D

                } else {

                    p = o.position;
                    r = o.rotation;
                    q = o.quaternion;
                    s = o.scale;

                    // turn off quaternions, for the moment

                    q = 0;

                    object = new THREE.Object3D();
                    object.name = dd;
                    object.position.set( p[0], p[1], p[2] );

                    if ( q ) {

                        object.quaternion.set( q[0], q[1], q[2], q[3] );
                        object.useQuaternion = true;

                    } else {

                        object.rotation.set( r[0], r[1], r[2] );

                    }

                    object.scale.set( s[0], s[1], s[2] );
                    object.visible = ( o.visible !== undefined ) ? o.visible : false;

                    parent.add( object );

                    result.objects[ dd ] = object;
                    result.empties[ dd ] = object;

                }

                if ( object ) {

                    if ( o.properties !== undefined )  {

                        for ( var key in o.properties ) {

                            var value = o.properties[ key ];
                            object.properties[ key ] = value;

                        }

                    }

                    if ( o.children !== undefined ) {

                        handle_children( object, o.children );

                    }

                }

            }

        }

    };

    function handle_mesh( geo, id ) {

        result.geometries[ id ] = geo;
        handle_objects();

    };

    function create_callback( id ) {

        return function( geo ) {

            handle_mesh( geo, id );

            counter_models -= 1;

            scope.onLoadComplete();

            async_callback_gate();

        }

    };

    function create_callback_embed( id ) {

        return function( geo ) {

            result.geometries[ id ] = geo;

        }

    };

    function async_callback_gate() {

        var progress = {

            totalModels : total_models,
            totalTextures : total_textures,
            loadedModels : total_models - counter_models,
            loadedTextures : total_textures - counter_textures

        };

        scope.callbackProgress( progress, result );

        scope.onLoadProgress();

        if ( counter_models === 0 && counter_textures === 0 ) {

            callbackFinished( result );

        }

    };

    var callbackTexture = function ( count ) {

        counter_textures -= count;
        async_callback_gate();

        scope.onLoadComplete();

    };

    // must use this instead of just directly calling callbackTexture
    // because of closure in the calling context loop

    var generateTextureCallback = function ( count ) {

        return function() {

            callbackTexture( count );

        };

    };

    // first go synchronous elements

    // cameras

    for( dc in data.cameras ) {

        c = data.cameras[ dc ];

        if ( c.type === "perspective" ) {

            camera = new THREE.PerspectiveCamera( c.fov, c.aspect, c.near, c.far );

        } else if ( c.type === "ortho" ) {

            camera = new THREE.OrthographicCamera( c.left, c.right, c.top, c.bottom, c.near, c.far );

        }

        p = c.position;
        t = c.target;
        u = c.up;

        camera.position.set( p[0], p[1], p[2] );
        camera.target = new THREE.Vector3( t[0], t[1], t[2] );
        if ( u ) camera.up.set( u[0], u[1], u[2] );

        result.cameras[ dc ] = camera;

    }

    // lights

    var hex, intensity;

    for ( dl in data.lights ) {

        l = data.lights[ dl ];

        hex = ( l.color !== undefined ) ? l.color : 0xffffff;
        intensity = ( l.intensity !== undefined ) ? l.intensity : 1;

        if ( l.type === "directional" ) {

            p = l.direction;

            light = new THREE.DirectionalLight( hex, intensity );
            light.position.set( p[0], p[1], p[2] );
            light.position.normalize();

        } else if ( l.type === "point" ) {

            p = l.position;
            d = l.distance;

            light = new THREE.PointLight( hex, intensity, d );
            light.position.set( p[0], p[1], p[2] );

        } else if ( l.type === "ambient" ) {

            light = new THREE.AmbientLight( hex );

        }

        result.scene.add( light );

        result.lights[ dl ] = light;

    }

    // fogs

    for( df in data.fogs ) {

        f = data.fogs[ df ];

        if ( f.type === "linear" ) {

            fog = new THREE.Fog( 0x000000, f.near, f.far );

        } else if ( f.type === "exp2" ) {

            fog = new THREE.FogExp2( 0x000000, f.density );

        }

        c = f.color;
        fog.color.setRGB( c[0], c[1], c[2] );

        result.fogs[ df ] = fog;

    }

    // defaults

    if ( result.cameras && data.defaults && data.defaults.camera ) {

        result.currentCamera = result.cameras[ data.defaults.camera ];

    }

    if ( result.fogs && data.defaults && data.defaults.fog ) {

        result.scene.fog = result.fogs[ data.defaults.fog ];

    }

    c = data.defaults.bgcolor;
    result.bgColor = new THREE.Color();
    result.bgColor.setRGB( c[0], c[1], c[2] );

    result.bgColorAlpha = data.defaults.bgalpha;

    // now come potentially asynchronous elements

    // geometries

    // count how many models will be loaded asynchronously

    for( dg in data.geometries ) {

        g = data.geometries[ dg ];

        if ( g.type in this.geometryHandlerMap ) {

            counter_models += 1;

            scope.onLoadStart();

        }

    }

    total_models = counter_models;

    for ( dg in data.geometries ) {

        g = data.geometries[ dg ];

        if ( g.type === "cube" ) {

            geometry = new THREE.CubeGeometry( g.width, g.height, g.depth, g.segmentsWidth, g.segmentsHeight, g.segmentsDepth, null, g.flipped, g.sides );
            result.geometries[ dg ] = geometry;

        } else if ( g.type === "plane" ) {

            geometry = new THREE.PlaneGeometry( g.width, g.height, g.segmentsWidth, g.segmentsHeight );
            result.geometries[ dg ] = geometry;

        } else if ( g.type === "sphere" ) {

            geometry = new THREE.SphereGeometry( g.radius, g.segmentsWidth, g.segmentsHeight );
            result.geometries[ dg ] = geometry;

        } else if ( g.type === "cylinder" ) {

            geometry = new THREE.CylinderGeometry( g.topRad, g.botRad, g.height, g.radSegs, g.heightSegs );
            result.geometries[ dg ] = geometry;

        } else if ( g.type === "torus" ) {

            geometry = new THREE.TorusGeometry( g.radius, g.tube, g.segmentsR, g.segmentsT );
            result.geometries[ dg ] = geometry;

        } else if ( g.type === "icosahedron" ) {

            geometry = new THREE.IcosahedronGeometry( g.radius, g.subdivisions );
            result.geometries[ dg ] = geometry;

        } else if ( g.type in this.geometryHandlerMap ) {

            var loaderParameters = {};
            for ( var parType in g ) {

                if ( parType !== "type" && parType !== "url" ) {

                    loaderParameters[ parType ] = g[ parType ];

                }

            }

            var loader = this.geometryHandlerMap[ g.type ][ "loaderObject" ];
            loader.load( get_url( g.url, data.urlBaseType ), create_callback( dg ), loaderParameters );

        } else if ( g.type === "embedded" ) {

            var modelJson = data.embeds[ g.id ],
                texture_path = "";

            // pass metadata along to jsonLoader so it knows the format version

            modelJson.metadata = data.metadata;

            if ( modelJson ) {

                var jsonLoader = this.geometryHandlerMap[ "ascii" ][ "loaderObject" ];
                jsonLoader.createModel( modelJson, create_callback_embed( dg ), texture_path );

            }

        }

    }

    // textures

    // count how many textures will be loaded asynchronously

    for( dt in data.textures ) {

        tt = data.textures[ dt ];

        if( tt.url instanceof Array ) {

            counter_textures += tt.url.length;

            for( var n = 0; n < tt.url.length; n ++ ) {

                scope.onLoadStart();

            }

        } else {

            counter_textures += 1;

            scope.onLoadStart();

        }

    }

    total_textures = counter_textures;

    for ( dt in data.textures ) {

        tt = data.textures[ dt ];

        if ( tt.mapping !== undefined && THREE[ tt.mapping ] !== undefined  ) {

            tt.mapping = new THREE[ tt.mapping ]();

        }

        if ( tt.url instanceof Array ) {

            var count = tt.url.length;
            var url_array = [];

            for( var i = 0; i < count; i ++ ) {

                url_array[ i ] = get_url( tt.url[ i ], data.urlBaseType );

            }

            var isCompressed = url_array[ 0 ].endsWith( ".dds" );

            if ( isCompressed ) {

                texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, tt.mapping, generateTextureCallback( count ) );

            } else {

                texture = THREE.ImageUtils.loadTextureCube( url_array, tt.mapping, generateTextureCallback( count ) );

            }

        } else {

            var isCompressed = tt.url.toLowerCase().endsWith( ".dds" );
            var fullUrl = get_url( tt.url, data.urlBaseType );
            var textureCallback = generateTextureCallback( 1 );

            if ( isCompressed ) {

                texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, tt.mapping, textureCallback );

            } else {

                texture = THREE.ImageUtils.loadTexture( fullUrl, tt.mapping, textureCallback );

            }

            if ( THREE[ tt.minFilter ] !== undefined )
                texture.minFilter = THREE[ tt.minFilter ];

            if ( THREE[ tt.magFilter ] !== undefined )
                texture.magFilter = THREE[ tt.magFilter ];

            if ( tt.anisotropy ) texture.anisotropy = tt.anisotropy;

            if ( tt.repeat ) {

                texture.repeat.set( tt.repeat[ 0 ], tt.repeat[ 1 ] );

                if ( tt.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
                if ( tt.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;

            }

            if ( tt.offset ) {

                texture.offset.set( tt.offset[ 0 ], tt.offset[ 1 ] );

            }

            // handle wrap after repeat so that default repeat can be overriden

            if ( tt.wrap ) {

                var wrapMap = {
                "repeat"     : THREE.RepeatWrapping,
                "mirror"    : THREE.MirroredRepeatWrapping
                }

                if ( wrapMap[ tt.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ tt.wrap[ 0 ] ];
                if ( wrapMap[ tt.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ tt.wrap[ 1 ] ];

            }

        }

        result.textures[ dt ] = texture;

    }

    // materials

    for ( dm in data.materials ) {

        m = data.materials[ dm ];

        for ( pp in m.parameters ) {

            if ( pp === "envMap" || pp === "map" || pp === "lightMap" || pp === "bumpMap" ) {

                m.parameters[ pp ] = result.textures[ m.parameters[ pp ] ];

            } else if ( pp === "shading" ) {

                m.parameters[ pp ] = ( m.parameters[ pp ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading;

            } else if ( pp === "side" ) {

                if (  m.parameters[ pp ] == "double" ) {

                    m.parameters[ pp ] = THREE.DoubleSide;

                } else if ( m.parameters[ pp ] == "back" ) {

                    m.parameters[ pp ] = THREE.BackSide;

                } else {

                    m.parameters[ pp ] = THREE.FrontSide;

                }

            } else if ( pp === "blending" ) {

                m.parameters[ pp ] = m.parameters[ pp ] in THREE ? THREE[ m.parameters[ pp ] ] : THREE.NormalBlending;

            } else if ( pp === "combine" ) {

                m.parameters[ pp ] = ( m.parameters[ pp ] == "MixOperation" ) ? THREE.MixOperation : THREE.MultiplyOperation;

            } else if ( pp === "vertexColors" ) {

                if ( m.parameters[ pp ] == "face" ) {

                    m.parameters[ pp ] = THREE.FaceColors;

                // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false

                } else if ( m.parameters[ pp ] )   {

                    m.parameters[ pp ] = THREE.VertexColors;

                }

            } else if ( pp === "wrapRGB" ) {

                var v3 = m.parameters[ pp ];
                m.parameters[ pp ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] );

            }

        }

        if ( m.parameters.opacity !== undefined && m.parameters.opacity < 1.0 ) {

            m.parameters.transparent = true;

        }

        if ( m.parameters.normalMap ) {

            var shader = THREE.ShaderUtils.lib[ "normal" ];
            var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

            var diffuse = m.parameters.color;
            var specular = m.parameters.specular;
            var ambient = m.parameters.ambient;
            var shininess = m.parameters.shininess;

            uniforms[ "tNormal" ].value = result.textures[ m.parameters.normalMap ];

            if ( m.parameters.normalScale ) {

                uniforms[ "uNormalScale" ].value.set( m.parameters.normalScale[ 0 ], m.parameters.normalScale[ 1 ] );

            }

            if ( m.parameters.map ) {

                uniforms[ "tDiffuse" ].value = m.parameters.map;
                uniforms[ "enableDiffuse" ].value = true;

            }

            if ( m.parameters.envMap ) {

                uniforms[ "tCube" ].value = m.parameters.envMap;
                uniforms[ "enableReflection" ].value = true;
                uniforms[ "uReflectivity" ].value = m.parameters.reflectivity;

            }

            if ( m.parameters.lightMap ) {

                uniforms[ "tAO" ].value = m.parameters.lightMap;
                uniforms[ "enableAO" ].value = true;

            }

            if ( m.parameters.specularMap ) {

                uniforms[ "tSpecular" ].value = result.textures[ m.parameters.specularMap ];
                uniforms[ "enableSpecular" ].value = true;

            }

            if ( m.parameters.displacementMap ) {

                uniforms[ "tDisplacement" ].value = result.textures[ m.parameters.displacementMap ];
                uniforms[ "enableDisplacement" ].value = true;

                uniforms[ "uDisplacementBias" ].value = m.parameters.displacementBias;
                uniforms[ "uDisplacementScale" ].value = m.parameters.displacementScale;

            }

            uniforms[ "uDiffuseColor" ].value.setHex( diffuse );
            uniforms[ "uSpecularColor" ].value.setHex( specular );
            uniforms[ "uAmbientColor" ].value.setHex( ambient );

            uniforms[ "uShininess" ].value = shininess;

            if ( m.parameters.opacity ) {

                uniforms[ "uOpacity" ].value = m.parameters.opacity;

            }

            var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };

            material = new THREE.ShaderMaterial( parameters );

        } else {

            material = new THREE[ m.type ]( m.parameters );

        }

        result.materials[ dm ] = material;

    }

    // objects ( synchronous init of procedural primitives )

    handle_objects();

    // synchronous callback

    scope.callbackSync( result );

    // just in case there are no async elements

    async_callback_gate();

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.TextureLoader = function () {

    THREE.EventTarget.call( this );

    this.crossOrigin = null;

};

THREE.TextureLoader.prototype = {

    constructor: THREE.TextureLoader,

    load: function ( url ) {

        var scope = this;

        var image = new Image();

        image.addEventListener( 'load', function () {

            var texture = new THREE.Texture( image );
            texture.needsUpdate = true;

            scope.dispatchEvent( { type: 'load', content: texture } );

        }, false );

        image.addEventListener( 'error', function () {

            scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );

        }, false );

        if ( scope.crossOrigin ) image.crossOrigin = scope.crossOrigin;

        image.src = url;

    }

}
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Material = function () {

    this.id = THREE.MaterialCount ++;

    this.name = '';

    this.side = THREE.FrontSide;

    this.opacity = 1;
    this.transparent = false;

    this.blending = THREE.NormalBlending;

    this.blendSrc = THREE.SrcAlphaFactor;
    this.blendDst = THREE.OneMinusSrcAlphaFactor;
    this.blendEquation = THREE.AddEquation;

    this.depthTest = true;
    this.depthWrite = true;

    this.polygonOffset = false;
    this.polygonOffsetFactor = 0;
    this.polygonOffsetUnits = 0;

    this.alphaTest = 0;

    this.overdraw = false; // Boolean for fixing antialiasing gaps in CanvasRenderer

    this.visible = true;

    this.needsUpdate = true;

};

THREE.Material.prototype.setValues = function ( values ) {

    if ( values === undefined ) return;

    for ( var key in values ) {

        var newValue = values[ key ];

        if ( newValue === undefined ) {

            console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
            continue;

        }

        if ( key in this ) {

            var currentValue = this[ key ];

            if ( currentValue instanceof THREE.Color && newValue instanceof THREE.Color ) {

                currentValue.copy( newValue );

            } else if ( currentValue instanceof THREE.Color && typeof( newValue ) === "number" ) {

                currentValue.setHex( newValue );

            } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {

                currentValue.copy( newValue );

            } else {

                this[ key ] = newValue;

            }

        }

    }

};

THREE.Material.prototype.clone = function ( material ) {

    if ( material === undefined ) material = new THREE.Material();

    material.name = this.name;

    material.side = this.side;

    material.opacity = this.opacity;
    material.transparent = this.transparent;

    material.blending = this.blending;

    material.blendSrc = this.blendSrc;
    material.blendDst = this.blendDst;
    material.blendEquation = this.blendEquation;

    material.depthTest = this.depthTest;
    material.depthWrite = this.depthWrite;

    material.polygonOffset = this.polygonOffset;
    material.polygonOffsetFactor = this.polygonOffsetFactor;
    material.polygonOffsetUnits = this.polygonOffsetUnits;

    material.alphaTest = this.alphaTest;

    material.overdraw = this.overdraw;

    material.visible = this.visible;

    return material;

};

THREE.MaterialCount = 0;
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  linewidth: <float>,
 *  linecap: "round",
 *  linejoin: "round",
 *
 *  vertexColors: <bool>
 *
 *  fog: <bool>
 * }
 */

THREE.LineBasicMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.color = new THREE.Color( 0xffffff );

    this.linewidth = 1;
    this.linecap = 'round';
    this.linejoin = 'round';

    this.vertexColors = false;

    this.fog = true;

    this.setValues( parameters );

};

THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.LineBasicMaterial.prototype.clone = function () {

    var material = new THREE.LineBasicMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.color.copy( this.color );

    material.linewidth = this.linewidth;
    material.linecap = this.linecap;
    material.linejoin = this.linejoin;

    material.vertexColors = this.vertexColors;

    material.fog = this.fog;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *  lightMap: new THREE.Texture( <Image> ),
 *
 *  specularMap: new THREE.Texture( <Image> ),
 *
 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
 *  combine: THREE.Multiply,
 *  reflectivity: <float>,
 *  refractionRatio: <float>,
 *
 *  shading: THREE.SmoothShading,
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *
 *  fog: <bool>
 * }
 */

THREE.MeshBasicMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.color = new THREE.Color( 0xffffff ); // emissive

    this.map = null;

    this.lightMap = null;

    this.specularMap = null;

    this.envMap = null;
    this.combine = THREE.MultiplyOperation;
    this.reflectivity = 1;
    this.refractionRatio = 0.98;

    this.fog = true;

    this.shading = THREE.SmoothShading;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.vertexColors = THREE.NoColors;

    this.skinning = false;
    this.morphTargets = false;

    this.setValues( parameters );

};

THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.MeshBasicMaterial.prototype.clone = function () {

    var material = new THREE.MeshBasicMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.color.copy( this.color );

    material.map = this.map;

    material.lightMap = this.lightMap;

    material.specularMap = this.specularMap;

    material.envMap = this.envMap;
    material.combine = this.combine;
    material.reflectivity = this.reflectivity;
    material.refractionRatio = this.refractionRatio;

    material.fog = this.fog;

    material.shading = this.shading;

    material.wireframe = this.wireframe;
    material.wireframeLinewidth = this.wireframeLinewidth;
    material.wireframeLinecap = this.wireframeLinecap;
    material.wireframeLinejoin = this.wireframeLinejoin;

    material.vertexColors = this.vertexColors;

    material.skinning = this.skinning;
    material.morphTargets = this.morphTargets;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  ambient: <hex>,
 *  emissive: <hex>,
 *  opacity: <float>,
 *
 *  map: new THREE.Texture( <Image> ),
 *
 *  lightMap: new THREE.Texture( <Image> ),
 *
 *  specularMap: new THREE.Texture( <Image> ),
 *
 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
 *  combine: THREE.Multiply,
 *  reflectivity: <float>,
 *  refractionRatio: <float>,
 *
 *  shading: THREE.SmoothShading,
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>,
 *
 *    fog: <bool>
 * }
 */

THREE.MeshLambertMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.color = new THREE.Color( 0xffffff ); // diffuse
    this.ambient = new THREE.Color( 0xffffff );
    this.emissive = new THREE.Color( 0x000000 );

    this.wrapAround = false;
    this.wrapRGB = new THREE.Vector3( 1, 1, 1 );

    this.map = null;

    this.lightMap = null;

    this.specularMap = null;

    this.envMap = null;
    this.combine = THREE.MultiplyOperation;
    this.reflectivity = 1;
    this.refractionRatio = 0.98;

    this.fog = true;

    this.shading = THREE.SmoothShading;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.vertexColors = THREE.NoColors;

    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;

    this.setValues( parameters );

};

THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.MeshLambertMaterial.prototype.clone = function () {

    var material = new THREE.MeshLambertMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.color.copy( this.color );
    material.ambient.copy( this.ambient );
    material.emissive.copy( this.emissive );

    material.wrapAround = this.wrapAround;
    material.wrapRGB.copy( this.wrapRGB );

    material.map = this.map;

    material.lightMap = this.lightMap;

    material.specularMap = this.specularMap;

    material.envMap = this.envMap;
    material.combine = this.combine;
    material.reflectivity = this.reflectivity;
    material.refractionRatio = this.refractionRatio;

    material.fog = this.fog;

    material.shading = this.shading;

    material.wireframe = this.wireframe;
    material.wireframeLinewidth = this.wireframeLinewidth;
    material.wireframeLinecap = this.wireframeLinecap;
    material.wireframeLinejoin = this.wireframeLinejoin;

    material.vertexColors = this.vertexColors;

    material.skinning = this.skinning;
    material.morphTargets = this.morphTargets;
    material.morphNormals = this.morphNormals;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  ambient: <hex>,
 *  emissive: <hex>,
 *  specular: <hex>,
 *  shininess: <float>,
 *  opacity: <float>,
 *
 *  map: new THREE.Texture( <Image> ),
 *
 *  lightMap: new THREE.Texture( <Image> ),
 *
 *  bumpMap: new THREE.Texture( <Image> ),
 *  bumpScale: <float>,
 *
 *  normalMap: new THREE.Texture( <Image> ),
 *  normalScale: <Vector2>,
 *
 *  specularMap: new THREE.Texture( <Image> ),
 *
 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
 *  combine: THREE.Multiply,
 *  reflectivity: <float>,
 *  refractionRatio: <float>,
 *
 *  shading: THREE.SmoothShading,
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>,
 *
 *    fog: <bool>
 * }
 */

THREE.MeshPhongMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.color = new THREE.Color( 0xffffff ); // diffuse
    this.ambient = new THREE.Color( 0xffffff );
    this.emissive = new THREE.Color( 0x000000 );
    this.specular = new THREE.Color( 0x111111 );
    this.shininess = 30;

    this.metal = false;
    this.perPixel = false;

    this.wrapAround = false;
    this.wrapRGB = new THREE.Vector3( 1, 1, 1 );

    this.map = null;

    this.lightMap = null;

    this.bumpMap = null;
    this.bumpScale = 1;

    this.normalMap = null;
    this.normalScale = new THREE.Vector2( 1, 1 );

    this.specularMap = null;

    this.envMap = null;
    this.combine = THREE.MultiplyOperation;
    this.reflectivity = 1;
    this.refractionRatio = 0.98;

    this.fog = true;

    this.shading = THREE.SmoothShading;

    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';

    this.vertexColors = THREE.NoColors;

    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;

    this.setValues( parameters );

};

THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.MeshPhongMaterial.prototype.clone = function () {

    var material = new THREE.MeshPhongMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.color.copy( this.color );
    material.ambient.copy( this.ambient );
    material.emissive.copy( this.emissive );
    material.specular.copy( this.specular );
    material.shininess = this.shininess;

    material.metal = this.metal;
    material.perPixel = this.perPixel;

    material.wrapAround = this.wrapAround;
    material.wrapRGB.copy( this.wrapRGB );

    material.map = this.map;

    material.lightMap = this.lightMap;

    material.bumpMap = this.bumpMap;
    material.bumpScale = this.bumpScale;

    material.normalMap = this.normalMap;
    material.normalScale.copy( this.normalScale );

    material.specularMap = this.specularMap;

    material.envMap = this.envMap;
    material.combine = this.combine;
    material.reflectivity = this.reflectivity;
    material.refractionRatio = this.refractionRatio;

    material.fog = this.fog;

    material.shading = this.shading;

    material.wireframe = this.wireframe;
    material.wireframeLinewidth = this.wireframeLinewidth;
    material.wireframeLinecap = this.wireframeLinecap;
    material.wireframeLinejoin = this.wireframeLinejoin;

    material.vertexColors = this.vertexColors;

    material.skinning = this.skinning;
    material.morphTargets = this.morphTargets;
    material.morphNormals = this.morphNormals;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  opacity: <float>,

 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,

 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>
 * }
 */

THREE.MeshDepthMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.wireframe = false;
    this.wireframeLinewidth = 1;

    this.setValues( parameters );

};

THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.MeshDepthMaterial.prototype.clone = function () {

    var material = new THREE.LineBasicMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.wireframe = this.wireframe;
    material.wireframeLinewidth = this.wireframeLinewidth;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 *
 * parameters = {
 *  opacity: <float>,

 *  shading: THREE.FlatShading,
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,

 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>
 * }
 */

THREE.MeshNormalMaterial = function ( parameters ) {

    THREE.Material.call( this, parameters );

    this.shading = THREE.FlatShading;

    this.wireframe = false;
    this.wireframeLinewidth = 1;

    this.setValues( parameters );

};

THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.MeshNormalMaterial.prototype.clone = function () {

    var material = new THREE.MeshNormalMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.shading = this.shading;

    material.wireframe = this.wireframe;
    material.wireframeLinewidth = this.wireframeLinewidth;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.MeshFaceMaterial = function () {};

THREE.MeshFaceMaterial.prototype.clone = function () {

    return new THREE.MeshFaceMaterial();

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *  size: <float>,
 *
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  vertexColors: <bool>,
 *
 *  fog: <bool>
 * }
 */

THREE.ParticleBasicMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.color = new THREE.Color( 0xffffff );

    this.map = null;

    this.size = 1;
    this.sizeAttenuation = true;

    this.vertexColors = false;

    this.fog = true;

    this.setValues( parameters );

};

THREE.ParticleBasicMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.ParticleBasicMaterial.prototype.clone = function () {

    var material = new THREE.ParticleBasicMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.color.copy( this.color );

    material.map = this.map;

    material.size = this.size;
    material.sizeAttenuation = this.sizeAttenuation;

    material.vertexColors = this.vertexColors;

    material.fog = this.fog;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 *
 * parameters = {
 *  color: <hex>,
 *  program: <function>,
 *  opacity: <float>,
 *  blending: THREE.NormalBlending
 * }
 */

THREE.ParticleCanvasMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.color = new THREE.Color( 0xffffff );
    this.program = function ( context, color ) {};

    this.setValues( parameters );

};

THREE.ParticleCanvasMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.ParticleCanvasMaterial.prototype.clone = function () {

    var material = new THREE.ParticleCanvasMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.color.copy( this.color );
    material.program = this.program;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.ParticleDOMMaterial = function ( element ) {

    this.element = element;

};

THREE.ParticleDOMMaterial.prototype.clone = function(){

    return new THREE.ParticleDOMMaterial( this.element );

};
/**
 * @author alteredq / http://alteredqualia.com/
 *
 * parameters = {
 *  fragmentShader: <string>,
 *  vertexShader: <string>,
 *
 *  uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } },
 *
 *  shading: THREE.SmoothShading,
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  wireframe: <boolean>,
 *  wireframeLinewidth: <float>,
 *
 *  lights: <bool>,
 *
 *  vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
 *
 *  skinning: <bool>,
 *  morphTargets: <bool>,
 *  morphNormals: <bool>,
 *
 *    fog: <bool>
 * }
 */

THREE.ShaderMaterial = function ( parameters ) {

    THREE.Material.call( this );

    this.fragmentShader = "void main() {}";
    this.vertexShader = "void main() {}";
    this.uniforms = {};
    this.attributes = null;

    this.shading = THREE.SmoothShading;

    this.wireframe = false;
    this.wireframeLinewidth = 1;

    this.fog = false; // set to use scene fog

    this.lights = false; // set to use scene lights

    this.vertexColors = THREE.NoColors; // set to use "color" attribute stream

    this.skinning = false; // set to use skinning attribute streams

    this.morphTargets = false; // set to use morph targets
    this.morphNormals = false; // set to use morph normals

    this.setValues( parameters );

};

THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );

THREE.ShaderMaterial.prototype.clone = function () {

    var material = new THREE.ShaderMaterial();

    THREE.Material.prototype.clone.call( this, material );

    material.fragmentShader = this.fragmentShader;
    material.vertexShader = this.vertexShader;
    material.uniforms = this.uniforms;
    material.attributes = this.attributes;

    material.shading = this.shading;

    material.wireframe = this.wireframe;
    material.wireframeLinewidth = this.wireframeLinewidth;

    material.fog = this.fog;

    material.lights = this.lights;

    material.vertexColors = this.vertexColors;

    material.skinning = this.skinning;

    material.morphTargets = this.morphTargets;
    material.morphNormals = this.morphNormals;

    return material;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author szimek / https://github.com/szimek/
 */

THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {

    this.id = THREE.TextureCount ++;

    this.image = image;

    this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping();

    this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping;
    this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;

    this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;
    this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter;

    this.anisotropy = anisotropy !== undefined ? anisotropy : 1;

    this.format = format !== undefined ? format : THREE.RGBAFormat;
    this.type = type !== undefined ? type : THREE.UnsignedByteType;

    this.offset = new THREE.Vector2( 0, 0 );
    this.repeat = new THREE.Vector2( 1, 1 );

    this.generateMipmaps = true;
    this.premultiplyAlpha = false;
    this.flipY = true;

    this.needsUpdate = false;
    this.onUpdate = null;

};

THREE.Texture.prototype = {

    constructor: THREE.Texture,

    clone: function () {

        var texture = new THREE.Texture();

        texture.image = this.image;

        texture.mapping = this.mapping;

        texture.wrapS = this.wrapS;
        texture.wrapT = this.wrapT;

        texture.magFilter = this.magFilter;
        texture.minFilter = this.minFilter;

        texture.anisotropy = this.anisotropy;

        texture.format = this.format;
        texture.type = this.type;

        texture.offset.copy( this.offset );
        texture.repeat.copy( this.repeat );

        texture.generateMipmaps = this.generateMipmaps;
        texture.premultiplyAlpha = this.premultiplyAlpha;
        texture.flipY = this.flipY;

        return texture;

    }

};

THREE.TextureCount = 0;
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter ) {

    THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type );

    this.image = { width: width, height: height };
    this.mipmaps = mipmaps;

};

THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype );

THREE.CompressedTexture.prototype.clone = function () {

    var texture = new THREE.CompressedTexture();

    texture.image = this.image;
    texture.mipmaps = this.mipmaps;

    texture.format = this.format;
    texture.type = this.type;

    texture.mapping = this.mapping;

    texture.wrapS = this.wrapS;
    texture.wrapT = this.wrapT;

    texture.magFilter = this.magFilter;
    texture.minFilter = this.minFilter;

    texture.anisotropy = this.anisotropy;

    texture.offset.copy( this.offset );
    texture.repeat.copy( this.repeat );

    return texture;

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter ) {

    THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type );

    this.image = { data: data, width: width, height: height };

};

THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype );

THREE.DataTexture.prototype.clone = function () {

    var clonedTexture = new THREE.DataTexture( this.image.data,  this.image.width, this.image.height, this.format, this.type, this.mapping, this.wrapS, this.wrapT, this.magFilter, this.minFilter );

    clonedTexture.offset.copy( this.offset );
    clonedTexture.repeat.copy( this.repeat );

    return clonedTexture;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Particle = function ( material ) {

    THREE.Object3D.call( this );

    this.material = material;

};

THREE.Particle.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.ParticleSystem = function ( geometry, material ) {

    THREE.Object3D.call( this );

    this.geometry = geometry;
    this.material = ( material !== undefined ) ? material : new THREE.ParticleBasicMaterial( { color: Math.random() * 0xffffff } );

    this.sortParticles = false;

    if ( this.geometry ) {

        // calc bound radius

        if( !this.geometry.boundingSphere ) {

            this.geometry.computeBoundingSphere();

        }

        this.boundRadius = geometry.boundingSphere.radius;

    }

    this.frustumCulled = false;

};

THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Line = function ( geometry, material, type ) {

    THREE.Object3D.call( this );

    this.geometry = geometry;
    this.material = ( material !== undefined ) ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } );
    this.type = ( type !== undefined ) ? type : THREE.LineStrip;

    if ( this.geometry ) {

        if ( ! this.geometry.boundingSphere ) {

            this.geometry.computeBoundingSphere();

        }

    }

};

THREE.LineStrip = 0;
THREE.LinePieces = 1;

THREE.Line.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author mikael emtinger / http://gomo.se/
 */

THREE.Mesh = function ( geometry, material ) {

    THREE.Object3D.call( this );

    this.geometry = geometry;
    this.material = ( material !== undefined ) ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: true } );

    if ( this.geometry ) {

        // calc bound radius

        if ( ! this.geometry.boundingSphere ) {

            this.geometry.computeBoundingSphere();

        }

        this.boundRadius = geometry.boundingSphere.radius;


        // setup morph targets

        if( this.geometry.morphTargets.length ) {

            this.morphTargetBase = -1;
            this.morphTargetForcedOrder = [];
            this.morphTargetInfluences = [];
            this.morphTargetDictionary = {};

            for( var m = 0; m < this.geometry.morphTargets.length; m ++ ) {

                this.morphTargetInfluences.push( 0 );
                this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;

            }

        }

    }

}

THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );


/*
 * Get Morph Target Index by Name
 */

THREE.Mesh.prototype.getMorphTargetIndexByName = function( name ) {

    if ( this.morphTargetDictionary[ name ] !== undefined ) {

        return this.morphTargetDictionary[ name ];
    }

    console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." );
    return 0;

}
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Bone = function( belongsToSkin ) {

    THREE.Object3D.call( this );

    this.skin = belongsToSkin;
    this.skinMatrix = new THREE.Matrix4();

};

THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );

THREE.Bone.prototype.update = function( parentSkinMatrix, forceUpdate ) {

    // update local

    if ( this.matrixAutoUpdate ) {

        forceUpdate |= this.updateMatrix();

    }

    // update skin matrix

    if ( forceUpdate || this.matrixWorldNeedsUpdate ) {

        if( parentSkinMatrix ) {

            this.skinMatrix.multiply( parentSkinMatrix, this.matrix );

        } else {

            this.skinMatrix.copy( this.matrix );

        }

        this.matrixWorldNeedsUpdate = false;
        forceUpdate = true;

    }

    // update children

    var child, i, l = this.children.length;

    for ( i = 0; i < l; i ++ ) {

        this.children[ i ].update( this.skinMatrix, forceUpdate );

    }

};

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {

    THREE.Mesh.call( this, geometry, material );

    //

    this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;

    // init bones

    this.identityMatrix = new THREE.Matrix4();

    this.bones = [];
    this.boneMatrices = [];

    var b, bone, gbone, p, q, s;

    if ( this.geometry.bones !== undefined ) {

        for ( b = 0; b < this.geometry.bones.length; b ++ ) {

            gbone = this.geometry.bones[ b ];

            p = gbone.pos;
            q = gbone.rotq;
            s = gbone.scl;

            bone = this.addBone();

            bone.name = gbone.name;
            bone.position.set( p[0], p[1], p[2] );
            bone.quaternion.set( q[0], q[1], q[2], q[3] );
            bone.useQuaternion = true;

            if ( s !== undefined ) {

                bone.scale.set( s[0], s[1], s[2] );

            } else {

                bone.scale.set( 1, 1, 1 );

            }

        }

        for ( b = 0; b < this.bones.length; b ++ ) {

            gbone = this.geometry.bones[ b ];
            bone = this.bones[ b ];

            if ( gbone.parent === -1 ) {

                this.add( bone );

            } else {

                this.bones[ gbone.parent ].add( bone );

            }

        }

        //

        var nBones = this.bones.length;

        if ( this.useVertexTexture ) {

            // layout (1 matrix = 4 pixels)
            //    RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
            //  with  8x8  pixel texture max   16 bones  (8 * 8  / 4)
            //       16x16 pixel texture max   64 bones (16 * 16 / 4)
            //       32x32 pixel texture max  256 bones (32 * 32 / 4)
            //       64x64 pixel texture max 1024 bones (64 * 64 / 4)

            var size;

            if ( nBones > 256 )
                size = 64;
            else if ( nBones > 64 )
                size = 32;
            else if ( nBones > 16 )
                size = 16;
            else
                size = 8;

            this.boneTextureWidth = size;
            this.boneTextureHeight = size;

            this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
            this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
            this.boneTexture.minFilter = THREE.NearestFilter;
            this.boneTexture.magFilter = THREE.NearestFilter;
            this.boneTexture.generateMipmaps = false;
            this.boneTexture.flipY = false;

        } else {

            this.boneMatrices = new Float32Array( 16 * nBones );

        }

        this.pose();

    }

};

THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );

THREE.SkinnedMesh.prototype.addBone = function( bone ) {

    if ( bone === undefined ) {

        bone = new THREE.Bone( this );

    }

    this.bones.push( bone );

    return bone;

};

THREE.SkinnedMesh.prototype.updateMatrixWorld = function ( force ) {

    this.matrixAutoUpdate && this.updateMatrix();

    // update matrixWorld

    if ( this.matrixWorldNeedsUpdate || force ) {

        if ( this.parent ) {

            this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix );

        } else {

            this.matrixWorld.copy( this.matrix );

        }

        this.matrixWorldNeedsUpdate = false;

        force = true;

    }

    // update children

    for ( var i = 0, l = this.children.length; i < l; i ++ ) {

        var child = this.children[ i ];

        if ( child instanceof THREE.Bone ) {

            child.update( this.identityMatrix, false );

        } else {

            child.updateMatrixWorld( true );

        }

    }

    // make a snapshot of the bones' rest position

    if ( this.boneInverses == undefined ) {

        this.boneInverses = [];

        for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

            var inverse = new THREE.Matrix4();

            inverse.getInverse( this.bones[ b ].skinMatrix );

            this.boneInverses.push( inverse );

        }

    }

    // flatten bone matrices to array

    for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

        // compute the offset between the current and the original transform;

        //TODO: we could get rid of this multiplication step if the skinMatrix
        // was already representing the offset; however, this requires some
        // major changes to the animation system

        THREE.SkinnedMesh.offsetMatrix.multiply( this.bones[ b ].skinMatrix, this.boneInverses[ b ] );

        THREE.SkinnedMesh.offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );

    }

    if ( this.useVertexTexture ) {

        this.boneTexture.needsUpdate = true;

    }

};

/*
 * Pose
 */

THREE.SkinnedMesh.prototype.pose = function() {

    this.updateMatrixWorld( true );

    for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {

        // normalize weights

        var sw = this.geometry.skinWeights[ i ];

        var scale = 1.0 / sw.lengthManhattan();

        if ( scale !== Infinity ) {

            sw.multiplyScalar( scale );

        } else {

            sw.set( 1 ); // this will be normalized by the shader anyway

        }

    }

};

THREE.SkinnedMesh.offsetMatrix = new THREE.Matrix4();

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.MorphAnimMesh = function ( geometry, material ) {

    THREE.Mesh.call( this, geometry, material );

    // API

    this.duration = 1000; // milliseconds
    this.mirroredLoop = false;
    this.time = 0;

    // internals

    this.lastKeyframe = 0;
    this.currentKeyframe = 0;

    this.direction = 1;
    this.directionBackwards = false;

    this.setFrameRange( 0, this.geometry.morphTargets.length - 1 );

};

THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype );

THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) {

    this.startKeyframe = start;
    this.endKeyframe = end;

    this.length = this.endKeyframe - this.startKeyframe + 1;

};

THREE.MorphAnimMesh.prototype.setDirectionForward = function () {

    this.direction = 1;
    this.directionBackwards = false;

};

THREE.MorphAnimMesh.prototype.setDirectionBackward = function () {

    this.direction = -1;
    this.directionBackwards = true;

};

THREE.MorphAnimMesh.prototype.parseAnimations = function () {

    var geometry = this.geometry;

    if ( ! geometry.animations ) geometry.animations = {};

    var firstAnimation, animations = geometry.animations;

    var pattern = /([a-z]+)(\d+)/;

    for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {

        var morph = geometry.morphTargets[ i ];
        var parts = morph.name.match( pattern );

        if ( parts && parts.length > 1 ) {

            var label = parts[ 1 ];
            var num = parts[ 2 ];

            if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity };

            var animation = animations[ label ];

            if ( i < animation.start ) animation.start = i;
            if ( i > animation.end ) animation.end = i;

            if ( ! firstAnimation ) firstAnimation = label;

        }

    }

    geometry.firstAnimation = firstAnimation;

};

THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) {

    if ( ! this.geometry.animations ) this.geometry.animations = {};

    this.geometry.animations[ label ] = { start: start, end: end };

};

THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {

    var animation = this.geometry.animations[ label ];

    if ( animation ) {

        this.setFrameRange( animation.start, animation.end );
        this.duration = 1000 * ( ( animation.end - animation.start ) / fps );
        this.time = 0;

    } else {

        console.warn( "animation[" + label + "] undefined" );

    }

};

THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) {

    var frameTime = this.duration / this.length;

    this.time += this.direction * delta;

    if ( this.mirroredLoop ) {

        if ( this.time > this.duration || this.time < 0 ) {

            this.direction *= -1;

            if ( this.time > this.duration ) {

                this.time = this.duration;
                this.directionBackwards = true;

            }

            if ( this.time < 0 ) {

                this.time = 0;
                this.directionBackwards = false;

            }

        }

    } else {

        this.time = this.time % this.duration;

        if ( this.time < 0 ) this.time += this.duration;

    }

    var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 );

    if ( keyframe !== this.currentKeyframe ) {

        this.morphTargetInfluences[ this.lastKeyframe ] = 0;
        this.morphTargetInfluences[ this.currentKeyframe ] = 1;

        this.morphTargetInfluences[ keyframe ] = 0;

        this.lastKeyframe = this.currentKeyframe;
        this.currentKeyframe = keyframe;

    }

    var mix = ( this.time % frameTime ) / frameTime;

    if ( this.directionBackwards ) {

        mix = 1 - mix;

    }

    this.morphTargetInfluences[ this.currentKeyframe ] = mix;
    this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix;

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Ribbon = function ( geometry, material ) {

    THREE.Object3D.call( this );

    this.geometry = geometry;
    this.material = material;

};

THREE.Ribbon.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.LOD = function () {

    THREE.Object3D.call( this );

    this.LODs = [];

};


THREE.LOD.prototype = Object.create( THREE.Object3D.prototype );

THREE.LOD.prototype.addLevel = function ( object3D, visibleAtDistance ) {

    if ( visibleAtDistance === undefined ) {

        visibleAtDistance = 0;

    }

    visibleAtDistance = Math.abs( visibleAtDistance );

    for ( var l = 0; l < this.LODs.length; l ++ ) {

        if ( visibleAtDistance < this.LODs[ l ].visibleAtDistance ) {

            break;

        }

    }

    this.LODs.splice( l, 0, { visibleAtDistance: visibleAtDistance, object3D: object3D } );
    this.add( object3D );

};

THREE.LOD.prototype.update = function ( camera ) {

    if ( this.LODs.length > 1 ) {

        camera.matrixWorldInverse.getInverse( camera.matrixWorld );

        var inverse  = camera.matrixWorldInverse;
        var distance = -( inverse.elements[2] * this.matrixWorld.elements[12] + inverse.elements[6] * this.matrixWorld.elements[13] + inverse.elements[10] * this.matrixWorld.elements[14] + inverse.elements[14] );

        this.LODs[ 0 ].object3D.visible = true;

        for ( var l = 1; l < this.LODs.length; l ++ ) {

            if( distance >= this.LODs[ l ].visibleAtDistance ) {

                this.LODs[ l - 1 ].object3D.visible = false;
                this.LODs[ l     ].object3D.visible = true;

            } else {

                break;

            }

        }

        for( ; l < this.LODs.length; l ++ ) {

            this.LODs[ l ].object3D.visible = false;

        }

    }

};
/**
 * @author mikael emtinger / http://gomo.se/
 */

THREE.Sprite = function ( parameters ) {

    THREE.Object3D.call( this );

    this.color = ( parameters.color !== undefined ) ? new THREE.Color( parameters.color ) : new THREE.Color( 0xffffff );
    this.map = ( parameters.map !== undefined ) ? parameters.map : new THREE.Texture();

    this.blending = ( parameters.blending !== undefined ) ? parameters.blending : THREE.NormalBlending;

    this.blendSrc = parameters.blendSrc !== undefined ? parameters.blendSrc : THREE.SrcAlphaFactor;
    this.blendDst = parameters.blendDst !== undefined ? parameters.blendDst : THREE.OneMinusSrcAlphaFactor;
    this.blendEquation = parameters.blendEquation !== undefined ? parameters.blendEquation : THREE.AddEquation;

    this.useScreenCoordinates = ( parameters.useScreenCoordinates !== undefined ) ? parameters.useScreenCoordinates : true;
    this.mergeWith3D = ( parameters.mergeWith3D !== undefined ) ? parameters.mergeWith3D : !this.useScreenCoordinates;
    this.affectedByDistance = ( parameters.affectedByDistance !== undefined ) ? parameters.affectedByDistance : !this.useScreenCoordinates;
    this.scaleByViewport = ( parameters.scaleByViewport !== undefined ) ? parameters.scaleByViewport : !this.affectedByDistance;
    this.alignment = ( parameters.alignment instanceof THREE.Vector2 ) ? parameters.alignment : THREE.SpriteAlignment.center;

    this.rotation3d = this.rotation;
    this.rotation = 0;
    this.opacity = 1;

    this.uvOffset = new THREE.Vector2( 0, 0 );
    this.uvScale  = new THREE.Vector2( 1, 1 );

};

THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype );

/*
 * Custom update matrix
 */

THREE.Sprite.prototype.updateMatrix = function () {

    this.matrix.setPosition( this.position );

    this.rotation3d.set( 0, 0, this.rotation );
    this.matrix.setRotationFromEuler( this.rotation3d );

    if ( this.scale.x !== 1 || this.scale.y !== 1 ) {

        this.matrix.scale( this.scale );
        this.boundRadiusScale = Math.max( this.scale.x, this.scale.y );

    }

    this.matrixWorldNeedsUpdate = true;

};

/*
 * Alignment
 */

THREE.SpriteAlignment = {};
THREE.SpriteAlignment.topLeft = new THREE.Vector2( 1, -1 );
THREE.SpriteAlignment.topCenter = new THREE.Vector2( 0, -1 );
THREE.SpriteAlignment.topRight = new THREE.Vector2( -1, -1 );
THREE.SpriteAlignment.centerLeft = new THREE.Vector2( 1, 0 );
THREE.SpriteAlignment.center = new THREE.Vector2( 0, 0 );
THREE.SpriteAlignment.centerRight = new THREE.Vector2( -1, 0 );
THREE.SpriteAlignment.bottomLeft = new THREE.Vector2( 1, 1 );
THREE.SpriteAlignment.bottomCenter = new THREE.Vector2( 0, 1 );
THREE.SpriteAlignment.bottomRight = new THREE.Vector2( -1, 1 );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Scene = function () {

    THREE.Object3D.call( this );

    this.fog = null;
    this.overrideMaterial = null;

    this.matrixAutoUpdate = false;

    this.__objects = [];
    this.__lights = [];

    this.__objectsAdded = [];
    this.__objectsRemoved = [];

};

THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );

THREE.Scene.prototype.__addObject = function ( object ) {

    if ( object instanceof THREE.Light ) {

        if ( this.__lights.indexOf( object ) === - 1 ) {

            this.__lights.push( object );

        }

        if ( object.target && object.target.parent === undefined ) {

            this.add( object.target );

        }

    } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) {

        if ( this.__objects.indexOf( object ) === - 1 ) {

            this.__objects.push( object );
            this.__objectsAdded.push( object );

            // check if previously removed

            var i = this.__objectsRemoved.indexOf( object );

            if ( i !== -1 ) {

                this.__objectsRemoved.splice( i, 1 );

            }

        }

    }

    for ( var c = 0; c < object.children.length; c ++ ) {

        this.__addObject( object.children[ c ] );

    }

};

THREE.Scene.prototype.__removeObject = function ( object ) {

    if ( object instanceof THREE.Light ) {

        var i = this.__lights.indexOf( object );

        if ( i !== -1 ) {

            this.__lights.splice( i, 1 );

        }

    } else if ( !( object instanceof THREE.Camera ) ) {

        var i = this.__objects.indexOf( object );

        if( i !== -1 ) {

            this.__objects.splice( i, 1 );
            this.__objectsRemoved.push( object );

            // check if previously added

            var ai = this.__objectsAdded.indexOf( object );

            if ( ai !== -1 ) {

                this.__objectsAdded.splice( ai, 1 );

            }

        }

    }

    for ( var c = 0; c < object.children.length; c ++ ) {

        this.__removeObject( object.children[ c ] );

    }

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Fog = function ( hex, near, far ) {

    this.color = new THREE.Color( hex );

    this.near = ( near !== undefined ) ? near : 1;
    this.far = ( far !== undefined ) ? far : 1000;

};
/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.FogExp2 = function ( hex, density ) {

    this.color = new THREE.Color( hex );
    this.density = ( density !== undefined ) ? density : 0.00025;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.CanvasRenderer = function ( parameters ) {

    console.log( 'THREE.CanvasRenderer', THREE.REVISION );

    parameters = parameters || {};

    var _this = this,
    _renderData, _elements, _lights,
    _projector = new THREE.Projector(),

    _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),

    _canvasWidth, _canvasHeight, _canvasWidthHalf, _canvasHeightHalf,
    _context = _canvas.getContext( '2d' ),

    _clearColor = new THREE.Color( 0x000000 ),
    _clearOpacity = 0,

    _contextGlobalAlpha = 1,
    _contextGlobalCompositeOperation = 0,
    _contextStrokeStyle = null,
    _contextFillStyle = null,
    _contextLineWidth = null,
    _contextLineCap = null,
    _contextLineJoin = null,

    _v1, _v2, _v3, _v4,
    _v5 = new THREE.RenderableVertex(),
    _v6 = new THREE.RenderableVertex(),

    _v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
    _v4x, _v4y, _v5x, _v5y, _v6x, _v6y,

    _color = new THREE.Color(),
    _color1 = new THREE.Color(),
    _color2 = new THREE.Color(),
    _color3 = new THREE.Color(),
    _color4 = new THREE.Color(),

    _patterns = {}, _imagedatas = {},

    _near, _far,

    _image, _uvs,
    _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,

    _clipRect = new THREE.Rectangle(),
    _clearRect = new THREE.Rectangle(),
    _bboxRect = new THREE.Rectangle(),

    _enableLighting = false,
    _ambientLight = new THREE.Color(),
    _directionalLights = new THREE.Color(),
    _pointLights = new THREE.Color(),

    _pi2 = Math.PI * 2,
    _vector3 = new THREE.Vector3(), // Needed for PointLight

    _pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData,
    _gradientMap, _gradientMapContext, _gradientMapQuality = 16;

    _pixelMap = document.createElement( 'canvas' );
    _pixelMap.width = _pixelMap.height = 2;

    _pixelMapContext = _pixelMap.getContext( '2d' );
    _pixelMapContext.fillStyle = 'rgba(0,0,0,1)';
    _pixelMapContext.fillRect( 0, 0, 2, 2 );

    _pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 );
    _pixelMapData = _pixelMapImage.data;

    _gradientMap = document.createElement( 'canvas' );
    _gradientMap.width = _gradientMap.height = _gradientMapQuality;

    _gradientMapContext = _gradientMap.getContext( '2d' );
    _gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 );
    _gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality );

    _gradientMapQuality --; // Fix UVs

    this.domElement = _canvas;

    this.autoClear = true;
    this.sortObjects = true;
    this.sortElements = true;

    this.info = {

        render: {

            vertices: 0,
            faces: 0

        }

    }

    this.setSize = function ( width, height ) {

        _canvasWidth = width;
        _canvasHeight = height;
        _canvasWidthHalf = Math.floor( _canvasWidth / 2 );
        _canvasHeightHalf = Math.floor( _canvasHeight / 2 );

        _canvas.width = _canvasWidth;
        _canvas.height = _canvasHeight;

        _clipRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
        _clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );

        _contextGlobalAlpha = 1;
        _contextGlobalCompositeOperation = 0;
        _contextStrokeStyle = null;
        _contextFillStyle = null;
        _contextLineWidth = null;
        _contextLineCap = null;
        _contextLineJoin = null;

    };

    this.setClearColor = function ( color, opacity ) {

        _clearColor.copy( color );
        _clearOpacity = opacity !== undefined ? opacity : 1;

        _clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );

    };

    this.setClearColorHex = function ( hex, opacity ) {

        _clearColor.setHex( hex );
        _clearOpacity = opacity !== undefined ? opacity : 1;

        _clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );

    };

    this.getMaxAnisotropy  = function () {

        return 0;

    };

    this.clear = function () {

        _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf );

        if ( _clearRect.isEmpty() === false ) {

            _clearRect.minSelf( _clipRect );
            _clearRect.inflate( 2 );

            if ( _clearOpacity < 1 ) {

                _context.clearRect( Math.floor( _clearRect.getX() ), Math.floor( _clearRect.getY() ), Math.floor( _clearRect.getWidth() ), Math.floor( _clearRect.getHeight() ) );

            }

            if ( _clearOpacity > 0 ) {

                setBlending( THREE.NormalBlending );
                setOpacity( 1 );

                setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearOpacity + ')' );

                _context.fillRect( Math.floor( _clearRect.getX() ), Math.floor( _clearRect.getY() ), Math.floor( _clearRect.getWidth() ), Math.floor( _clearRect.getHeight() ) );

            }

            _clearRect.empty();

        }


    };

    this.render = function ( scene, camera ) {

        if ( camera instanceof THREE.Camera === false ) {

            console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
            return;

        }

        var e, el, element, material;

        this.autoClear === true ? this.clear() : _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf );

        _this.info.render.vertices = 0;
        _this.info.render.faces = 0;

        _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
        _elements = _renderData.elements;
        _lights = _renderData.lights;

        /* DEBUG
        _context.fillStyle = 'rgba( 0, 255, 255, 0.5 )';
        _context.fillRect( _clipRect.getX(), _clipRect.getY(), _clipRect.getWidth(), _clipRect.getHeight() );
        */

        _enableLighting = _lights.length > 0;

        if ( _enableLighting === true ) {

             calculateLights();

        }

        for ( e = 0, el = _elements.length; e < el; e++ ) {

            element = _elements[ e ];

            material = element.material;

            if ( material === undefined || material.visible === false ) continue;

            _bboxRect.empty();

            if ( element instanceof THREE.RenderableParticle ) {

                _v1 = element;
                _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;

                renderParticle( _v1, element, material, scene );

            } else if ( element instanceof THREE.RenderableLine ) {

                _v1 = element.v1; _v2 = element.v2;

                _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
                _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;

                _bboxRect.addPoint( _v1.positionScreen.x, _v1.positionScreen.y );
                _bboxRect.addPoint( _v2.positionScreen.x, _v2.positionScreen.y );

                if ( _clipRect.intersects( _bboxRect ) === true ) {

                    renderLine( _v1, _v2, element, material, scene );

                }


            } else if ( element instanceof THREE.RenderableFace3 ) {

                _v1 = element.v1; _v2 = element.v2; _v3 = element.v3;

                _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
                _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
                _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;

                if ( material.overdraw === true ) {

                    expand( _v1.positionScreen, _v2.positionScreen );
                    expand( _v2.positionScreen, _v3.positionScreen );
                    expand( _v3.positionScreen, _v1.positionScreen );

                }

                _bboxRect.add3Points( _v1.positionScreen.x, _v1.positionScreen.y,
                              _v2.positionScreen.x, _v2.positionScreen.y,
                              _v3.positionScreen.x, _v3.positionScreen.y );

                if ( _clipRect.intersects( _bboxRect ) === true ) {

                    renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material, scene );

                }

            } else if ( element instanceof THREE.RenderableFace4 ) {

                _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; _v4 = element.v4;

                _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
                _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
                _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
                _v4.positionScreen.x *= _canvasWidthHalf; _v4.positionScreen.y *= _canvasHeightHalf;

                _v5.positionScreen.copy( _v2.positionScreen );
                _v6.positionScreen.copy( _v4.positionScreen );

                if ( material.overdraw === true ) {

                    expand( _v1.positionScreen, _v2.positionScreen );
                    expand( _v2.positionScreen, _v4.positionScreen );
                    expand( _v4.positionScreen, _v1.positionScreen );

                    expand( _v3.positionScreen, _v5.positionScreen );
                    expand( _v3.positionScreen, _v6.positionScreen );

                }

                _bboxRect.addPoint( _v1.positionScreen.x, _v1.positionScreen.y );
                _bboxRect.addPoint( _v2.positionScreen.x, _v2.positionScreen.y );
                _bboxRect.addPoint( _v3.positionScreen.x, _v3.positionScreen.y );
                _bboxRect.addPoint( _v4.positionScreen.x, _v4.positionScreen.y );

                if ( _clipRect.intersects( _bboxRect ) === true ) {

                    renderFace4( _v1, _v2, _v3, _v4, _v5, _v6, element, material, scene );

                }

            }

            /* DEBUG
            _context.lineWidth = 1;
            _context.strokeStyle = 'rgba( 0, 255, 0, 0.5 )';
            _context.strokeRect( _bboxRect.getX(), _bboxRect.getY(), _bboxRect.getWidth(), _bboxRect.getHeight() );
            */

            _clearRect.addRectangle( _bboxRect );


        }

        /* DEBUG
        _context.lineWidth = 1;
        _context.strokeStyle = 'rgba( 255, 0, 0, 0.5 )';
        _context.strokeRect( _clearRect.getX(), _clearRect.getY(), _clearRect.getWidth(), _clearRect.getHeight() );
        */

        _context.setTransform( 1, 0, 0, 1, 0, 0 );

        //

        function calculateLights() {

            _ambientLight.setRGB( 0, 0, 0 );
            _directionalLights.setRGB( 0, 0, 0 );
            _pointLights.setRGB( 0, 0, 0 );

            for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {

                var light = _lights[ l ];
                var lightColor = light.color;

                if ( light instanceof THREE.AmbientLight ) {

                    _ambientLight.r += lightColor.r;
                    _ambientLight.g += lightColor.g;
                    _ambientLight.b += lightColor.b;

                } else if ( light instanceof THREE.DirectionalLight ) {

                    // for particles

                    _directionalLights.r += lightColor.r;
                    _directionalLights.g += lightColor.g;
                    _directionalLights.b += lightColor.b;

                } else if ( light instanceof THREE.PointLight ) {

                    // for particles

                    _pointLights.r += lightColor.r;
                    _pointLights.g += lightColor.g;
                    _pointLights.b += lightColor.b;

                }

            }

        }

        function calculateLight( position, normal, color ) {

            for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {

                var light = _lights[ l ];
                var lightColor = light.color;

                if ( light instanceof THREE.DirectionalLight ) {

                    var lightPosition = light.matrixWorld.getPosition().normalize();

                    var amount = normal.dot( lightPosition );

                    if ( amount <= 0 ) continue;

                    amount *= light.intensity;

                    color.r += lightColor.r * amount;
                    color.g += lightColor.g * amount;
                    color.b += lightColor.b * amount;

                } else if ( light instanceof THREE.PointLight ) {

                    var lightPosition = light.matrixWorld.getPosition();

                    var amount = normal.dot( _vector3.sub( lightPosition, position ).normalize() );

                    if ( amount <= 0 ) continue;

                    amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );

                    if ( amount == 0 ) continue;

                    amount *= light.intensity;

                    color.r += lightColor.r * amount;
                    color.g += lightColor.g * amount;
                    color.b += lightColor.b * amount;

                }

            }

        }

        function renderParticle( v1, element, material, scene ) {

            setOpacity( material.opacity );
            setBlending( material.blending );

            var width, height, scaleX, scaleY,
            bitmap, bitmapWidth, bitmapHeight;

            if ( material instanceof THREE.ParticleBasicMaterial ) {

                if ( material.map === null ) {

                    scaleX = element.object.scale.x;
                    scaleY = element.object.scale.y;

                    // TODO: Be able to disable this

                    scaleX *= element.scale.x * _canvasWidthHalf;
                    scaleY *= element.scale.y * _canvasHeightHalf;

                    _bboxRect.set( v1.x - scaleX, v1.y - scaleY, v1.x  + scaleX, v1.y + scaleY );

                    if ( _clipRect.intersects( _bboxRect ) === false ) {

                        return;

                    }

                    setFillStyle( material.color.getContextStyle() );

                    _context.save();
                    _context.translate( v1.x, v1.y );
                    _context.rotate( - element.rotation );
                    _context.scale( scaleX, scaleY );
                    _context.fillRect( -1, -1, 2, 2 );
                    _context.restore();

                } else {

                    bitmap = material.map.image;
                    bitmapWidth = bitmap.width >> 1;
                    bitmapHeight = bitmap.height >> 1;

                    scaleX = element.scale.x * _canvasWidthHalf;
                    scaleY = element.scale.y * _canvasHeightHalf;

                    width = scaleX * bitmapWidth;
                    height = scaleY * bitmapHeight;

                    // TODO: Rotations break this...

                    _bboxRect.set( v1.x - width, v1.y - height, v1.x  + width, v1.y + height );

                    if ( _clipRect.intersects( _bboxRect ) === false ) {

                        return;

                    }

                    _context.save();
                    _context.translate( v1.x, v1.y );
                    _context.rotate( - element.rotation );
                    _context.scale( scaleX, - scaleY );

                    _context.translate( - bitmapWidth, - bitmapHeight );
                    _context.drawImage( bitmap, 0, 0 );
                    _context.restore();

                }

                /* DEBUG
                setStrokeStyle( 'rgb(255,255,0)' );
                _context.beginPath();
                _context.moveTo( v1.x - 10, v1.y );
                _context.lineTo( v1.x + 10, v1.y );
                _context.moveTo( v1.x, v1.y - 10 );
                _context.lineTo( v1.x, v1.y + 10 );
                _context.stroke();
                */

            } else if ( material instanceof THREE.ParticleCanvasMaterial ) {

                width = element.scale.x * _canvasWidthHalf;
                height = element.scale.y * _canvasHeightHalf;

                _bboxRect.set( v1.x - width, v1.y - height, v1.x + width, v1.y + height );

                if ( _clipRect.intersects( _bboxRect ) === false ) {

                    return;

                }

                setStrokeStyle( material.color.getContextStyle() );
                setFillStyle( material.color.getContextStyle() );

                _context.save();
                _context.translate( v1.x, v1.y );
                _context.rotate( - element.rotation );
                _context.scale( width, height );

                material.program( _context );

                _context.restore();

            }

        }

        function renderLine( v1, v2, element, material, scene ) {

            setOpacity( material.opacity );
            setBlending( material.blending );

            _context.beginPath();
            _context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
            _context.lineTo( v2.positionScreen.x, v2.positionScreen.y );

            if ( material instanceof THREE.LineBasicMaterial ) {

                setLineWidth( material.linewidth );
                setLineCap( material.linecap );
                setLineJoin( material.linejoin );
                setStrokeStyle( material.color.getContextStyle() );

                _context.stroke();
                _bboxRect.inflate( material.linewidth * 2 );

            }

        }

        function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material, scene ) {

            _this.info.render.vertices += 3;
            _this.info.render.faces ++;

            setOpacity( material.opacity );
            setBlending( material.blending );

            _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
            _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
            _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;

            drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );

            if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null && material.map === null ) {

                if ( _enableLighting === true ) {

                    var diffuse = material.color;
                    var emissive = material.emissive;

                    if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 3 ) {

                        _color1.r = _color2.r = _color3.r = _ambientLight.r;
                        _color1.g = _color2.g = _color3.g = _ambientLight.g;
                        _color1.b = _color2.b = _color3.b = _ambientLight.b;

                        calculateLight( element.v1.positionWorld, element.vertexNormalsWorld[ 0 ], _color1 );
                        calculateLight( element.v2.positionWorld, element.vertexNormalsWorld[ 1 ], _color2 );
                        calculateLight( element.v3.positionWorld, element.vertexNormalsWorld[ 2 ], _color3 );

                        _color1.r = diffuse.r * _color1.r + emissive.r;
                        _color1.g = diffuse.g * _color1.g + emissive.g;
                        _color1.b = diffuse.b * _color1.b + emissive.b;

                        _color2.r = diffuse.r * _color2.r + emissive.r;
                        _color2.g = diffuse.g * _color2.g + emissive.g;
                        _color2.b = diffuse.b * _color2.b + emissive.b;

                        _color3.r = diffuse.r * _color3.r + emissive.r;
                        _color3.g = diffuse.g * _color3.g + emissive.g;
                        _color3.b = diffuse.b * _color3.b + emissive.b;

                        _color4.r = ( _color2.r + _color3.r ) * 0.5;
                        _color4.g = ( _color2.g + _color3.g ) * 0.5;
                        _color4.b = ( _color2.b + _color3.b ) * 0.5;

                        _image = getGradientTexture( _color1, _color2, _color3, _color4 );

                        clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );

                    } else {

                        _color.r = _ambientLight.r;
                        _color.g = _ambientLight.g;
                        _color.b = _ambientLight.b;

                        calculateLight( element.centroidWorld, element.normalWorld, _color );

                        _color.r = diffuse.r * _color.r + emissive.r;
                        _color.g = diffuse.g * _color.g + emissive.g;
                        _color.b = diffuse.b * _color.b + emissive.b;

                        material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color );

                    }

                } else {

                    material.wireframe === true ? strokePath( material.color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( material.color );

                }

            } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {

                if ( material.map !== null ) {

                    if ( material.map.mapping instanceof THREE.UVMapping ) {

                        _uvs = element.uvs[ 0 ];
                        patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].u, _uvs[ uv1 ].v, _uvs[ uv2 ].u, _uvs[ uv2 ].v, _uvs[ uv3 ].u, _uvs[ uv3 ].v, material.map );

                    }


                } else if ( material.envMap !== null ) {

                    if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) {

                        var cameraMatrix = camera.matrixWorldInverse;

                        _vector3.copy( element.vertexNormalsWorld[ uv1 ] );
                        _uv1x = ( _vector3.x * cameraMatrix.elements[0] + _vector3.y * cameraMatrix.elements[4] + _vector3.z * cameraMatrix.elements[8] ) * 0.5 + 0.5;
                        _uv1y = ( _vector3.x * cameraMatrix.elements[1] + _vector3.y * cameraMatrix.elements[5] + _vector3.z * cameraMatrix.elements[9] ) * 0.5 + 0.5;

                        _vector3.copy( element.vertexNormalsWorld[ uv2 ] );
                        _uv2x = ( _vector3.x * cameraMatrix.elements[0] + _vector3.y * cameraMatrix.elements[4] + _vector3.z * cameraMatrix.elements[8] ) * 0.5 + 0.5;
                        _uv2y = ( _vector3.x * cameraMatrix.elements[1] + _vector3.y * cameraMatrix.elements[5] + _vector3.z * cameraMatrix.elements[9] ) * 0.5 + 0.5;

                        _vector3.copy( element.vertexNormalsWorld[ uv3 ] );
                        _uv3x = ( _vector3.x * cameraMatrix.elements[0] + _vector3.y * cameraMatrix.elements[4] + _vector3.z * cameraMatrix.elements[8] ) * 0.5 + 0.5;
                        _uv3y = ( _vector3.x * cameraMatrix.elements[1] + _vector3.y * cameraMatrix.elements[5] + _vector3.z * cameraMatrix.elements[9] ) * 0.5 + 0.5;

                        patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );

                    }/* else if ( material.envMap.mapping == THREE.SphericalRefractionMapping ) {



                    }*/


                } else {

                    material.wireframe === true ? strokePath( material.color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( material.color );

                }

            } else if ( material instanceof THREE.MeshDepthMaterial ) {

                _near = camera.near;
                _far = camera.far;

                _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z, _near, _far );
                _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z, _near, _far );
                _color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z, _near, _far );

                _color4.r = ( _color2.r + _color3.r ) * 0.5;
                _color4.g = ( _color2.g + _color3.g ) * 0.5;
                _color4.b = ( _color2.b + _color3.b ) * 0.5;

                _image = getGradientTexture( _color1, _color2, _color3, _color4 );

                clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );

            } else if ( material instanceof THREE.MeshNormalMaterial ) {

                _color.r = normalToComponent( element.normalWorld.x );
                _color.g = normalToComponent( element.normalWorld.y );
                _color.b = normalToComponent( element.normalWorld.z );

                material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color );

            }

        }

        function renderFace4( v1, v2, v3, v4, v5, v6, element, material, scene ) {

            _this.info.render.vertices += 4;
            _this.info.render.faces ++;

            setOpacity( material.opacity );
            setBlending( material.blending );

            if ( ( material.map !== undefined && material.map !== null ) || ( material.envMap !== undefined && material.envMap !== null ) ) {

                // Let renderFace3() handle this

                renderFace3( v1, v2, v4, 0, 1, 3, element, material, scene );
                renderFace3( v5, v3, v6, 1, 2, 3, element, material, scene );

                return;

            }

            _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
            _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
            _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
            _v4x = v4.positionScreen.x; _v4y = v4.positionScreen.y;
            _v5x = v5.positionScreen.x; _v5y = v5.positionScreen.y;
            _v6x = v6.positionScreen.x; _v6y = v6.positionScreen.y;

            if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {

                if ( _enableLighting === true ) {

                    var diffuse = material.color;
                    var emissive = material.emissive;

                    if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 4 ) {

                        _color1.r = _color2.r = _color3.r = _color4.r = _ambientLight.r;
                        _color1.g = _color2.g = _color3.g = _color4.g = _ambientLight.g;
                        _color1.b = _color2.b = _color3.b = _color4.b = _ambientLight.b;

                        calculateLight( element.v1.positionWorld, element.vertexNormalsWorld[ 0 ], _color1 );
                        calculateLight( element.v2.positionWorld, element.vertexNormalsWorld[ 1 ], _color2 );
                        calculateLight( element.v4.positionWorld, element.vertexNormalsWorld[ 3 ], _color3 );
                        calculateLight( element.v3.positionWorld, element.vertexNormalsWorld[ 2 ], _color4 );

                        _color1.r = diffuse.r * _color1.r + emissive.r;
                        _color1.g = diffuse.g * _color1.g + emissive.g;
                        _color1.b = diffuse.b * _color1.b + emissive.b;

                        _color2.r = diffuse.r * _color2.r + emissive.r;
                        _color2.g = diffuse.g * _color2.g + emissive.g;
                        _color2.b = diffuse.b * _color2.b + emissive.b;

                        _color3.r = diffuse.r * _color3.r + emissive.r;
                        _color3.g = diffuse.g * _color3.g + emissive.g;
                        _color3.b = diffuse.b * _color3.b + emissive.b;

                        _color4.r = diffuse.r * _color4.r + emissive.r;
                        _color4.g = diffuse.g * _color4.g + emissive.g;
                        _color4.b = diffuse.b * _color4.b + emissive.b;

                        _image = getGradientTexture( _color1, _color2, _color3, _color4 );

                        // TODO: UVs are incorrect, v4->v3?

                        drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
                        clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );

                        drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
                        clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );

                    } else {

                        _color.r = _ambientLight.r;
                        _color.g = _ambientLight.g;
                        _color.b = _ambientLight.b;

                        calculateLight( element.centroidWorld, element.normalWorld, _color );

                        _color.r = diffuse.r * _color.r + emissive.r;
                        _color.g = diffuse.g * _color.g + emissive.g;
                        _color.b = diffuse.b * _color.b + emissive.b;

                        drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );

                        material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color );

                    }

                } else {

                    drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );

                    material.wireframe === true ? strokePath( material.color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( material.color );

                }

            } else if ( material instanceof THREE.MeshBasicMaterial ) {

                drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );

                material.wireframe === true ? strokePath( material.color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( material.color );

            } else if ( material instanceof THREE.MeshNormalMaterial ) {

                _color.r = normalToComponent( element.normalWorld.x );
                _color.g = normalToComponent( element.normalWorld.y );
                _color.b = normalToComponent( element.normalWorld.z );

                drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );

                material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color );

            } else if ( material instanceof THREE.MeshDepthMaterial ) {

                _near = camera.near;
                _far = camera.far;

                _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z, _near, _far );
                _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z, _near, _far );
                _color3.r = _color3.g = _color3.b = 1 - smoothstep( v4.positionScreen.z, _near, _far );
                _color4.r = _color4.g = _color4.b = 1 - smoothstep( v3.positionScreen.z, _near, _far );

                _image = getGradientTexture( _color1, _color2, _color3, _color4 );

                // TODO: UVs are incorrect, v4->v3?

                drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
                clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );

                drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
                clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );

            }

        }

        //

        function drawTriangle( x0, y0, x1, y1, x2, y2 ) {

            _context.beginPath();
            _context.moveTo( x0, y0 );
            _context.lineTo( x1, y1 );
            _context.lineTo( x2, y2 );
            _context.closePath();

        }

        function drawQuad( x0, y0, x1, y1, x2, y2, x3, y3 ) {

            _context.beginPath();
            _context.moveTo( x0, y0 );
            _context.lineTo( x1, y1 );
            _context.lineTo( x2, y2 );
            _context.lineTo( x3, y3 );
            _context.closePath();

        }

        function strokePath( color, linewidth, linecap, linejoin ) {

            setLineWidth( linewidth );
            setLineCap( linecap );
            setLineJoin( linejoin );
            setStrokeStyle( color.getContextStyle() );

            _context.stroke();

            _bboxRect.inflate( linewidth * 2 );

        }

        function fillPath( color ) {

            setFillStyle( color.getContextStyle() );
            _context.fill();

        }

        function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {

            if ( texture instanceof THREE.DataTexture || texture.image === undefined || texture.image.width == 0 ) return;

            if ( texture.needsUpdate === true ) {

                var repeatX = texture.wrapS == THREE.RepeatWrapping;
                var repeatY = texture.wrapT == THREE.RepeatWrapping;

                _patterns[ texture.id ] = _context.createPattern(
                    texture.image, repeatX === true && repeatY === true
                        ? 'repeat'
                        : repeatX === true && repeatY === false
                            ? 'repeat-x'
                            : repeatX === false && repeatY === true
                                ? 'repeat-y'
                                : 'no-repeat'
                );

                texture.needsUpdate = false;

            }

            _patterns[ texture.id ] === undefined
                ? setFillStyle( 'rgba(0,0,0,1)' )
                : setFillStyle( _patterns[ texture.id ] );

            // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120

            var a, b, c, d, e, f, det, idet,
            offsetX = texture.offset.x / texture.repeat.x,
            offsetY = texture.offset.y / texture.repeat.y,
            width = texture.image.width * texture.repeat.x,
            height = texture.image.height * texture.repeat.y;

            u0 = ( u0 + offsetX ) * width;
            v0 = ( 1.0 - v0 + offsetY ) * height;

            u1 = ( u1 + offsetX ) * width;
            v1 = ( 1.0 - v1 + offsetY ) * height;

            u2 = ( u2 + offsetX ) * width;
            v2 = ( 1.0 - v2 + offsetY ) * height;

            x1 -= x0; y1 -= y0;
            x2 -= x0; y2 -= y0;

            u1 -= u0; v1 -= v0;
            u2 -= u0; v2 -= v0;

            det = u1 * v2 - u2 * v1;

            if ( det === 0 ) {

                if ( _imagedatas[ texture.id ] === undefined ) {

                    var canvas = document.createElement( 'canvas' )
                    canvas.width = texture.image.width;
                    canvas.height = texture.image.height;

                    var context = canvas.getContext( '2d' );
                    context.drawImage( texture.image, 0, 0 );

                    _imagedatas[ texture.id ] = context.getImageData( 0, 0, texture.image.width, texture.image.height ).data;

                }

                var data = _imagedatas[ texture.id ];
                var index = ( Math.floor( u0 ) + Math.floor( v0 ) * texture.image.width ) * 4;

                _color.setRGB( data[ index ] / 255, data[ index + 1 ] / 255, data[ index + 2 ] / 255 );
                fillPath( _color );

                return;

            }

            idet = 1 / det;

            a = ( v2 * x1 - v1 * x2 ) * idet;
            b = ( v2 * y1 - v1 * y2 ) * idet;
            c = ( u1 * x2 - u2 * x1 ) * idet;
            d = ( u1 * y2 - u2 * y1 ) * idet;

            e = x0 - a * u0 - c * v0;
            f = y0 - b * u0 - d * v0;

            _context.save();
            _context.transform( a, b, c, d, e, f );
            _context.fill();
            _context.restore();

        }

        function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {

            // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120

            var a, b, c, d, e, f, det, idet,
            width = image.width - 1,
            height = image.height - 1;

            u0 *= width; v0 *= height;
            u1 *= width; v1 *= height;
            u2 *= width; v2 *= height;

            x1 -= x0; y1 -= y0;
            x2 -= x0; y2 -= y0;

            u1 -= u0; v1 -= v0;
            u2 -= u0; v2 -= v0;

            det = u1 * v2 - u2 * v1;

            idet = 1 / det;

            a = ( v2 * x1 - v1 * x2 ) * idet;
            b = ( v2 * y1 - v1 * y2 ) * idet;
            c = ( u1 * x2 - u2 * x1 ) * idet;
            d = ( u1 * y2 - u2 * y1 ) * idet;

            e = x0 - a * u0 - c * v0;
            f = y0 - b * u0 - d * v0;

            _context.save();
            _context.transform( a, b, c, d, e, f );
            _context.clip();
            _context.drawImage( image, 0, 0 );
            _context.restore();

        }

        function getGradientTexture( color1, color2, color3, color4 ) {

            // http://mrdoob.com/blog/post/710

            _pixelMapData[ 0 ] = ( color1.r * 255 ) | 0;
            _pixelMapData[ 1 ] = ( color1.g * 255 ) | 0;
            _pixelMapData[ 2 ] = ( color1.b * 255 ) | 0;

            _pixelMapData[ 4 ] = ( color2.r * 255 ) | 0;
            _pixelMapData[ 5 ] = ( color2.g * 255 ) | 0;
            _pixelMapData[ 6 ] = ( color2.b * 255 ) | 0;

            _pixelMapData[ 8 ] = ( color3.r * 255 ) | 0;
            _pixelMapData[ 9 ] = ( color3.g * 255 ) | 0;
            _pixelMapData[ 10 ] = ( color3.b * 255 ) | 0;

            _pixelMapData[ 12 ] = ( color4.r * 255 ) | 0;
            _pixelMapData[ 13 ] = ( color4.g * 255 ) | 0;
            _pixelMapData[ 14 ] = ( color4.b * 255 ) | 0;

            _pixelMapContext.putImageData( _pixelMapImage, 0, 0 );
            _gradientMapContext.drawImage( _pixelMap, 0, 0 );

            return _gradientMap;

        }

        function smoothstep( value, min, max ) {

            var x = ( value - min ) / ( max - min );
            return x * x * ( 3 - 2 * x );

        }

        function normalToComponent( normal ) {

            var component = ( normal + 1 ) * 0.5;
            return component < 0 ? 0 : ( component > 1 ? 1 : component );

        }

        // Hide anti-alias gaps

        function expand( v1, v2 ) {

            var x = v2.x - v1.x, y =  v2.y - v1.y,
            det = x * x + y * y, idet;

            if ( det === 0 ) return;

            idet = 1 / Math.sqrt( det );

            x *= idet; y *= idet;

            v2.x += x; v2.y += y;
            v1.x -= x; v1.y -= y;

        }
    };

    // Context cached methods.

    function setOpacity( value ) {

        if ( _contextGlobalAlpha !== value ) {

            _context.globalAlpha = value;
            _contextGlobalAlpha = value;

        }

    }

    function setBlending( value ) {

        if ( _contextGlobalCompositeOperation !== value ) {

            if ( value === THREE.NormalBlending ) {

                _context.globalCompositeOperation = 'source-over';

            } else if ( value === THREE.AdditiveBlending ) {

                _context.globalCompositeOperation = 'lighter';

            } else if ( value === THREE.SubtractiveBlending ) {

                _context.globalCompositeOperation = 'darker';

            }

            _contextGlobalCompositeOperation = value;

        }

    }

    function setLineWidth( value ) {

        if ( _contextLineWidth !== value ) {

            _context.lineWidth = value;
            _contextLineWidth = value;

        }

    }

    function setLineCap( value ) {

        // "butt", "round", "square"

        if ( _contextLineCap !== value ) {

            _context.lineCap = value;
            _contextLineCap = value;

        }

    }

    function setLineJoin( value ) {

        // "round", "bevel", "miter"

        if ( _contextLineJoin !== value ) {

            _context.lineJoin = value;
            _contextLineJoin = value;

        }

    }

    function setStrokeStyle( value ) {

        if ( _contextStrokeStyle !== value ) {

            _context.strokeStyle = value;
            _contextStrokeStyle = value;

        }

    }

    function setFillStyle( value ) {

        if ( _contextFillStyle !== value ) {

            _context.fillStyle = value;
            _contextFillStyle = value;

        }

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 */

THREE.ShaderChunk = {

    // FOG

    fog_pars_fragment: [

        "#ifdef USE_FOG",

            "uniform vec3 fogColor;",

            "#ifdef FOG_EXP2",

                "uniform float fogDensity;",

            "#else",

                "uniform float fogNear;",
                "uniform float fogFar;",

            "#endif",

        "#endif"

    ].join("\n"),

    fog_fragment: [

        "#ifdef USE_FOG",

            "float depth = gl_FragCoord.z / gl_FragCoord.w;",

            "#ifdef FOG_EXP2",

                "const float LOG2 = 1.442695;",
                "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
                "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",

            "#else",

                "float fogFactor = smoothstep( fogNear, fogFar, depth );",

            "#endif",

            "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",

        "#endif"

    ].join("\n"),

    // ENVIRONMENT MAP

    envmap_pars_fragment: [

        "#ifdef USE_ENVMAP",

            "uniform float reflectivity;",
            "uniform samplerCube envMap;",
            "uniform float flipEnvMap;",
            "uniform int combine;",

            "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",

                "uniform bool useRefract;",
                "uniform float refractionRatio;",

            "#else",

                "varying vec3 vReflect;",

            "#endif",

        "#endif"

    ].join("\n"),

    envmap_fragment: [

        "#ifdef USE_ENVMAP",

            "vec3 reflectVec;",

            "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",

                "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",

                "if ( useRefract ) {",

                    "reflectVec = refract( cameraToVertex, normal, refractionRatio );",

                "} else { ",

                    "reflectVec = reflect( cameraToVertex, normal );",

                "}",

            "#else",

                "reflectVec = vReflect;",

            "#endif",

            "#ifdef DOUBLE_SIDED",

                "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
                "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",

            "#else",

                "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",

            "#endif",

            "#ifdef GAMMA_INPUT",

                "cubeColor.xyz *= cubeColor.xyz;",

            "#endif",

            "if ( combine == 1 ) {",

                "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );",

            "} else {",

                "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );",

            "}",

        "#endif"

    ].join("\n"),

    envmap_pars_vertex: [

        "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",

            "varying vec3 vReflect;",

            "uniform float refractionRatio;",
            "uniform bool useRefract;",

        "#endif"

    ].join("\n"),

    worldpos_vertex : [

        "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )",

            "#ifdef USE_SKINNING",

                "vec4 mPosition = modelMatrix * skinned;",

            "#endif",

            "#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",

                "vec4 mPosition = modelMatrix * vec4( morphed, 1.0 );",

            "#endif",

            "#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",

                "vec4 mPosition = modelMatrix * vec4( position, 1.0 );",

            "#endif",

        "#endif"

    ].join("\n"),

    envmap_vertex : [

        "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",

            "vec3 nWorld = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;",

            "if ( useRefract ) {",

                "vReflect = refract( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ), refractionRatio );",

            "} else {",

                "vReflect = reflect( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ) );",

            "}",

        "#endif"

    ].join("\n"),

    // COLOR MAP (particles)

    map_particle_pars_fragment: [

        "#ifdef USE_MAP",

            "uniform sampler2D map;",

        "#endif"

    ].join("\n"),


    map_particle_fragment: [

        "#ifdef USE_MAP",

            "gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );",

        "#endif"

    ].join("\n"),

    // COLOR MAP (triangles)

    map_pars_vertex: [

        "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",

            "varying vec2 vUv;",
            "uniform vec4 offsetRepeat;",

        "#endif"

    ].join("\n"),

    map_pars_fragment: [

        "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",

            "varying vec2 vUv;",

        "#endif",

        "#ifdef USE_MAP",

            "uniform sampler2D map;",

        "#endif",

    ].join("\n"),

    map_vertex: [

        "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )",

            "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",

        "#endif"

    ].join("\n"),

    map_fragment: [

        "#ifdef USE_MAP",

            "#ifdef GAMMA_INPUT",

                "vec4 texelColor = texture2D( map, vUv );",
                "texelColor.xyz *= texelColor.xyz;",

                "gl_FragColor = gl_FragColor * texelColor;",

            "#else",

                "gl_FragColor = gl_FragColor * texture2D( map, vUv );",

            "#endif",

        "#endif"

    ].join("\n"),

    // LIGHT MAP

    lightmap_pars_fragment: [

        "#ifdef USE_LIGHTMAP",

            "varying vec2 vUv2;",
            "uniform sampler2D lightMap;",

        "#endif"

    ].join("\n"),

    lightmap_pars_vertex: [

        "#ifdef USE_LIGHTMAP",

            "varying vec2 vUv2;",

        "#endif"

    ].join("\n"),

    lightmap_fragment: [

        "#ifdef USE_LIGHTMAP",

            "gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );",

        "#endif"

    ].join("\n"),

    lightmap_vertex: [

        "#ifdef USE_LIGHTMAP",

            "vUv2 = uv2;",

        "#endif"

    ].join("\n"),

    // BUMP MAP

    bumpmap_pars_fragment: [

        "#ifdef USE_BUMPMAP",

            "uniform sampler2D bumpMap;",
            "uniform float bumpScale;",

            // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen
            //    http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html

            // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)

            "vec2 dHdxy_fwd() {",

                "vec2 dSTdx = dFdx( vUv );",
                "vec2 dSTdy = dFdy( vUv );",

                "float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
                "float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
                "float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",

                "return vec2( dBx, dBy );",

            "}",

            "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",

                "vec3 vSigmaX = dFdx( surf_pos );",
                "vec3 vSigmaY = dFdy( surf_pos );",
                "vec3 vN = surf_norm;",        // normalized

                "vec3 R1 = cross( vSigmaY, vN );",
                "vec3 R2 = cross( vN, vSigmaX );",

                "float fDet = dot( vSigmaX, R1 );",

                "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
                "return normalize( abs( fDet ) * surf_norm - vGrad );",

            "}",

        "#endif"

    ].join("\n"),

    // NORMAL MAP

    normalmap_pars_fragment: [

        "#ifdef USE_NORMALMAP",

            "uniform sampler2D normalMap;",
            "uniform vec2 normalScale;",

            // Per-Pixel Tangent Space Normal Mapping
            // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html

            "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {",

                "vec3 q0 = dFdx( eye_pos.xyz );",
                "vec3 q1 = dFdy( eye_pos.xyz );",
                "vec2 st0 = dFdx( vUv.st );",
                "vec2 st1 = dFdy( vUv.st );",

                "vec3 S = normalize(  q0 * st1.t - q1 * st0.t );",
                "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
                "vec3 N = normalize( surf_norm );",

                "vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;",
                "mapN.xy = normalScale * mapN.xy;",
                "mat3 tsn = mat3( S, T, N );",
                "return normalize( tsn * mapN );",

            "}",

        "#endif"

    ].join("\n"),

    // SPECULAR MAP

    specularmap_pars_fragment: [

        "#ifdef USE_SPECULARMAP",

            "uniform sampler2D specularMap;",

        "#endif"

    ].join("\n"),

    specularmap_fragment: [

        "float specularStrength;",

        "#ifdef USE_SPECULARMAP",

            "vec4 texelSpecular = texture2D( specularMap, vUv );",
            "specularStrength = texelSpecular.r;",

        "#else",

            "specularStrength = 1.0;",

        "#endif"

    ].join("\n"),

    // LIGHTS LAMBERT

    lights_lambert_pars_vertex: [

        "uniform vec3 ambient;",
        "uniform vec3 diffuse;",
        "uniform vec3 emissive;",

        "uniform vec3 ambientLightColor;",

        "#if MAX_DIR_LIGHTS > 0",

            "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
            "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",

        "#endif",

        "#if MAX_HEMI_LIGHTS > 0",

            "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
            "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
            "uniform vec3 hemisphereLightPosition[ MAX_HEMI_LIGHTS ];",

        "#endif",

        "#if MAX_POINT_LIGHTS > 0",

            "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
            "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
            "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
            "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
            "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
            "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
            "uniform float spotLightAngle[ MAX_SPOT_LIGHTS ];",
            "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",

        "#endif",

        "#ifdef WRAP_AROUND",

            "uniform vec3 wrapRGB;",

        "#endif"

    ].join("\n"),

    lights_lambert_vertex: [

        "vLightFront = vec3( 0.0 );",

        "#ifdef DOUBLE_SIDED",

            "vLightBack = vec3( 0.0 );",

        "#endif",

        "transformedNormal = normalize( transformedNormal );",

        "#if MAX_DIR_LIGHTS > 0",

        "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",

            "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
            "vec3 dirVector = normalize( lDirection.xyz );",

            "float dotProduct = dot( transformedNormal, dirVector );",
            "vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );",

            "#ifdef DOUBLE_SIDED",

                "vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",

                "#ifdef WRAP_AROUND",

                    "vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",

                "#endif",

            "#endif",

            "#ifdef WRAP_AROUND",

                "vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
                "directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );",

                "#ifdef DOUBLE_SIDED",

                    "directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );",

                "#endif",

            "#endif",

            "vLightFront += directionalLightColor[ i ] * directionalLightWeighting;",

            "#ifdef DOUBLE_SIDED",

                "vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;",

            "#endif",

        "}",

        "#endif",

        "#if MAX_POINT_LIGHTS > 0",

            "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",

                "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
                "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                "float lDistance = 1.0;",
                "if ( pointLightDistance[ i ] > 0.0 )",
                    "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",

                "lVector = normalize( lVector );",
                "float dotProduct = dot( transformedNormal, lVector );",

                "vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );",

                "#ifdef DOUBLE_SIDED",

                    "vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",

                    "#ifdef WRAP_AROUND",

                        "vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",

                    "#endif",

                "#endif",

                "#ifdef WRAP_AROUND",

                    "vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
                    "pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );",

                    "#ifdef DOUBLE_SIDED",

                        "pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );",

                    "#endif",

                "#endif",

                "vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;",

                "#ifdef DOUBLE_SIDED",

                    "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;",

                "#endif",

            "}",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",

                "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
                "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                "lVector = normalize( lVector );",

                "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - mPosition.xyz ) );",

                "if ( spotEffect > spotLightAngle[ i ] ) {",

                    "spotEffect = pow( spotEffect, spotLightExponent[ i ] );",

                    "float lDistance = 1.0;",
                    "if ( spotLightDistance[ i ] > 0.0 )",
                        "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",

                    "float dotProduct = dot( transformedNormal, lVector );",
                    "vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );",

                    "#ifdef DOUBLE_SIDED",

                        "vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",

                        "#ifdef WRAP_AROUND",

                            "vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",

                        "#endif",

                    "#endif",

                    "#ifdef WRAP_AROUND",

                        "vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
                        "spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );",

                        "#ifdef DOUBLE_SIDED",

                            "spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );",

                        "#endif",

                    "#endif",

                    "vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;",

                    "#ifdef DOUBLE_SIDED",

                        "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;",

                    "#endif",

                "}",

            "}",

        "#endif",

        "#if MAX_HEMI_LIGHTS > 0",

            "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",

                "vec4 lPosition = viewMatrix * vec4( hemisphereLightPosition[ i ], 1.0 );",
                "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                "lVector = normalize( lVector );",

                "float dotProduct = dot( transformedNormal, lVector );",

                "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
                "float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;",

                "vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",

                "#ifdef DOUBLE_SIDED",

                    "vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );",

                "#endif",

            "}",

        "#endif",

        "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;",

        "#ifdef DOUBLE_SIDED",

            "vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;",

        "#endif"

    ].join("\n"),

    // LIGHTS PHONG

    lights_phong_pars_vertex: [

        "#ifndef PHONG_PER_PIXEL",

        "#if MAX_POINT_LIGHTS > 0",

            "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
            "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

            "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
            "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",

            "varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];",

        "#endif",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",

            "varying vec3 vWorldPosition;",

        "#endif"

    ].join("\n"),


    lights_phong_vertex: [

        "#ifndef PHONG_PER_PIXEL",

        "#if MAX_POINT_LIGHTS > 0",

            "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",

                "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
                "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                "float lDistance = 1.0;",
                "if ( pointLightDistance[ i ] > 0.0 )",
                    "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",

                "vPointLight[ i ] = vec4( lVector, lDistance );",

            "}",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",

                "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
                "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                "float lDistance = 1.0;",
                "if ( spotLightDistance[ i ] > 0.0 )",
                    "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",

                "vSpotLight[ i ] = vec4( lVector, lDistance );",

            "}",

        "#endif",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",

            "vWorldPosition = mPosition.xyz;",

        "#endif"

    ].join("\n"),

    lights_phong_pars_fragment: [

        "uniform vec3 ambientLightColor;",

        "#if MAX_DIR_LIGHTS > 0",

            "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
            "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",

        "#endif",

        "#if MAX_HEMI_LIGHTS > 0",

            "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
            "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
            "uniform vec3 hemisphereLightPosition[ MAX_HEMI_LIGHTS ];",

        "#endif",

        "#if MAX_POINT_LIGHTS > 0",

            "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",

            "#ifdef PHONG_PER_PIXEL",

                "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
                "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

            "#else",

                "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",

            "#endif",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
            "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
            "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
            "uniform float spotLightAngle[ MAX_SPOT_LIGHTS ];",
            "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",

            "#ifdef PHONG_PER_PIXEL",

                "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",

            "#else",

                "varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];",

            "#endif",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )",

            "varying vec3 vWorldPosition;",

        "#endif",

        "#ifdef WRAP_AROUND",

            "uniform vec3 wrapRGB;",

        "#endif",

        "varying vec3 vViewPosition;",
        "varying vec3 vNormal;"

    ].join("\n"),

    lights_phong_fragment: [

        "vec3 normal = normalize( vNormal );",
        "vec3 viewPosition = normalize( vViewPosition );",

        "#ifdef DOUBLE_SIDED",

            "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );",

        "#endif",

        "#ifdef USE_NORMALMAP",

            "normal = perturbNormal2Arb( -viewPosition, normal );",

        "#elif defined( USE_BUMPMAP )",

            "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",

        "#endif",

        "#if MAX_POINT_LIGHTS > 0",

            "vec3 pointDiffuse  = vec3( 0.0 );",
            "vec3 pointSpecular = vec3( 0.0 );",

            "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",

                "#ifdef PHONG_PER_PIXEL",

                    "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
                    "vec3 lVector = lPosition.xyz + vViewPosition.xyz;",

                    "float lDistance = 1.0;",
                    "if ( pointLightDistance[ i ] > 0.0 )",
                        "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",

                    "lVector = normalize( lVector );",

                "#else",

                    "vec3 lVector = normalize( vPointLight[ i ].xyz );",
                    "float lDistance = vPointLight[ i ].w;",

                "#endif",

                // diffuse

                "float dotProduct = dot( normal, lVector );",

                "#ifdef WRAP_AROUND",

                    "float pointDiffuseWeightFull = max( dotProduct, 0.0 );",
                    "float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",

                    "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",

                "#else",

                    "float pointDiffuseWeight = max( dotProduct, 0.0 );",

                "#endif",

                "pointDiffuse  += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;",

                // specular

                "vec3 pointHalfVector = normalize( lVector + viewPosition );",
                "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
                "float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );",

                "#ifdef PHYSICALLY_BASED_SHADING",

                    // 2.0 => 2.0001 is hack to work around ANGLE bug

                    "float specularNormalization = ( shininess + 2.0001 ) / 8.0;",

                    "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );",
                    "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;",

                "#else",

                    "pointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;",

                "#endif",

            "}",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "vec3 spotDiffuse  = vec3( 0.0 );",
            "vec3 spotSpecular = vec3( 0.0 );",

            "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",

                "#ifdef PHONG_PER_PIXEL",

                    "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
                    "vec3 lVector = lPosition.xyz + vViewPosition.xyz;",

                    "float lDistance = 1.0;",
                    "if ( spotLightDistance[ i ] > 0.0 )",
                        "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",

                    "lVector = normalize( lVector );",

                "#else",

                    "vec3 lVector = normalize( vSpotLight[ i ].xyz );",
                    "float lDistance = vSpotLight[ i ].w;",

                "#endif",

                "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",

                "if ( spotEffect > spotLightAngle[ i ] ) {",

                    "spotEffect = pow( spotEffect, spotLightExponent[ i ] );",

                    // diffuse

                    "float dotProduct = dot( normal, lVector );",

                    "#ifdef WRAP_AROUND",

                        "float spotDiffuseWeightFull = max( dotProduct, 0.0 );",
                        "float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",

                        "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",

                    "#else",

                        "float spotDiffuseWeight = max( dotProduct, 0.0 );",

                    "#endif",

                    "spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;",

                    // specular

                    "vec3 spotHalfVector = normalize( lVector + viewPosition );",
                    "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
                    "float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );",

                    "#ifdef PHYSICALLY_BASED_SHADING",

                        // 2.0 => 2.0001 is hack to work around ANGLE bug

                        "float specularNormalization = ( shininess + 2.0001 ) / 8.0;",

                        "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );",
                        "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;",

                    "#else",

                        "spotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;",

                    "#endif",

                "}",

            "}",

        "#endif",

        "#if MAX_DIR_LIGHTS > 0",

            "vec3 dirDiffuse  = vec3( 0.0 );",
            "vec3 dirSpecular = vec3( 0.0 );" ,

            "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",

                "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
                "vec3 dirVector = normalize( lDirection.xyz );",

                // diffuse

                "float dotProduct = dot( normal, dirVector );",

                "#ifdef WRAP_AROUND",

                    "float dirDiffuseWeightFull = max( dotProduct, 0.0 );",
                    "float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",

                    "vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );",

                "#else",

                    "float dirDiffuseWeight = max( dotProduct, 0.0 );",

                "#endif",

                "dirDiffuse  += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;",

                // specular

                "vec3 dirHalfVector = normalize( dirVector + viewPosition );",
                "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
                "float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );",

                "#ifdef PHYSICALLY_BASED_SHADING",

                    /*
                    // fresnel term from skin shader
                    "const float F0 = 0.128;",

                    "float base = 1.0 - dot( viewPosition, dirHalfVector );",
                    "float exponential = pow( base, 5.0 );",

                    "float fresnel = exponential + F0 * ( 1.0 - exponential );",
                    */

                    /*
                    // fresnel term from fresnel shader
                    "const float mFresnelBias = 0.08;",
                    "const float mFresnelScale = 0.3;",
                    "const float mFresnelPower = 5.0;",

                    "float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );",
                    */

                    // 2.0 => 2.0001 is hack to work around ANGLE bug

                    "float specularNormalization = ( shininess + 2.0001 ) / 8.0;",

                    //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;",

                    "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
                    "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",

                "#else",

                    "dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;",

                "#endif",

            "}",

        "#endif",

        "#if MAX_HEMI_LIGHTS > 0",

            "vec3 hemiDiffuse  = vec3( 0.0 );",
            "vec3 hemiSpecular = vec3( 0.0 );" ,

            "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",

                "vec4 lPosition = viewMatrix * vec4( hemisphereLightPosition[ i ], 1.0 );",
                "vec3 lVector = normalize( lPosition.xyz + vViewPosition.xyz );",

                // diffuse

                "float dotProduct = dot( normal, lVector );",
                "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",

                "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",

                "hemiDiffuse += diffuse * hemiColor;",

                // specular (sky light)

                "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
                "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
                "float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );",

                // specular (ground light)

                "vec3 lVectorGround = normalize( -lPosition.xyz + vViewPosition.xyz );",

                "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
                "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
                "float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );",

                "#ifdef PHYSICALLY_BASED_SHADING",

                    "float dotProductGround = dot( normal, lVectorGround );",

                    // 2.0 => 2.0001 is hack to work around ANGLE bug

                    "float specularNormalization = ( shininess + 2.0001 ) / 8.0;",

                    "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );",
                    "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );",
                    "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",

                "#else",

                    "hemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;",

                "#endif",

            "}",

        "#endif",

        "vec3 totalDiffuse = vec3( 0.0 );",
        "vec3 totalSpecular = vec3( 0.0 );",

        "#if MAX_DIR_LIGHTS > 0",

            "totalDiffuse += dirDiffuse;",
            "totalSpecular += dirSpecular;",

        "#endif",

        "#if MAX_HEMI_LIGHTS > 0",

            "totalDiffuse += hemiDiffuse;",
            "totalSpecular += hemiSpecular;",

        "#endif",

        "#if MAX_POINT_LIGHTS > 0",

            "totalDiffuse += pointDiffuse;",
            "totalSpecular += pointSpecular;",

        "#endif",

        "#if MAX_SPOT_LIGHTS > 0",

            "totalDiffuse += spotDiffuse;",
            "totalSpecular += spotSpecular;",

        "#endif",

        "#ifdef METAL",

            "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );",

        "#else",

            "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;",

        "#endif"

    ].join("\n"),

    // VERTEX COLORS

    color_pars_fragment: [

        "#ifdef USE_COLOR",

            "varying vec3 vColor;",

        "#endif"

    ].join("\n"),


    color_fragment: [

        "#ifdef USE_COLOR",

            "gl_FragColor = gl_FragColor * vec4( vColor, opacity );",

        "#endif"

    ].join("\n"),

    color_pars_vertex: [

        "#ifdef USE_COLOR",

            "varying vec3 vColor;",

        "#endif"

    ].join("\n"),


    color_vertex: [

        "#ifdef USE_COLOR",

            "#ifdef GAMMA_INPUT",

                "vColor = color * color;",

            "#else",

                "vColor = color;",

            "#endif",

        "#endif"

    ].join("\n"),

    // SKINNING

    skinning_pars_vertex: [

        "#ifdef USE_SKINNING",

            "#ifdef BONE_TEXTURE",

                "uniform sampler2D boneTexture;",

                "mat4 getBoneMatrix( const in float i ) {",

                    "float j = i * 4.0;",
                    "float x = mod( j, N_BONE_PIXEL_X );",
                    "float y = floor( j / N_BONE_PIXEL_X );",

                    "const float dx = 1.0 / N_BONE_PIXEL_X;",
                    "const float dy = 1.0 / N_BONE_PIXEL_Y;",

                    "y = dy * ( y + 0.5 );",

                    "vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
                    "vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
                    "vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
                    "vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",

                    "mat4 bone = mat4( v1, v2, v3, v4 );",

                    "return bone;",

                "}",

            "#else",

                "uniform mat4 boneGlobalMatrices[ MAX_BONES ];",

                "mat4 getBoneMatrix( const in float i ) {",

                    "mat4 bone = boneGlobalMatrices[ int(i) ];",
                    "return bone;",

                "}",

            "#endif",

        "#endif"

    ].join("\n"),

    skinbase_vertex: [

        "#ifdef USE_SKINNING",

            "mat4 boneMatX = getBoneMatrix( skinIndex.x );",
            "mat4 boneMatY = getBoneMatrix( skinIndex.y );",

        "#endif"

    ].join("\n"),

    skinning_vertex: [

        "#ifdef USE_SKINNING",

            "#ifdef USE_MORPHTARGETS",

            "vec4 skinVertex = vec4( morphed, 1.0 );",

            "#else",

            "vec4 skinVertex = vec4( position, 1.0 );",

            "#endif",

            "vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
            "skinned       += boneMatY * skinVertex * skinWeight.y;",

        "#endif"

    ].join("\n"),

    // MORPHING

    morphtarget_pars_vertex: [

        "#ifdef USE_MORPHTARGETS",

            "#ifndef USE_MORPHNORMALS",

            "uniform float morphTargetInfluences[ 8 ];",

            "#else",

            "uniform float morphTargetInfluences[ 4 ];",

            "#endif",

        "#endif"

    ].join("\n"),

    morphtarget_vertex: [

        "#ifdef USE_MORPHTARGETS",

            "vec3 morphed = vec3( 0.0 );",
            "morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];",
            "morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];",
            "morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];",
            "morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];",

            "#ifndef USE_MORPHNORMALS",

            "morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];",
            "morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];",
            "morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];",
            "morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];",

            "#endif",

            "morphed += position;",

        "#endif"

    ].join("\n"),

    default_vertex : [

        "vec4 mvPosition;",

        "#ifdef USE_SKINNING",

            "mvPosition = modelViewMatrix * skinned;",

        "#endif",

        "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )",

            "mvPosition = modelViewMatrix * vec4( morphed, 1.0 );",

        "#endif",

        "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )",

            "mvPosition = modelViewMatrix * vec4( position, 1.0 );",

        "#endif",

        "gl_Position = projectionMatrix * mvPosition;",

    ].join("\n"),

    morphnormal_vertex: [

        "#ifdef USE_MORPHNORMALS",

            "vec3 morphedNormal = vec3( 0.0 );",

            "morphedNormal +=  ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];",
            "morphedNormal +=  ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];",
            "morphedNormal +=  ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];",
            "morphedNormal +=  ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];",

            "morphedNormal += normal;",

        "#endif"

    ].join("\n"),

    skinnormal_vertex: [

        "#ifdef USE_SKINNING",

            "mat4 skinMatrix = skinWeight.x * boneMatX;",
            "skinMatrix     += skinWeight.y * boneMatY;",

            "#ifdef USE_MORPHNORMALS",

            "vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );",

            "#else",

            "vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );",

            "#endif",

        "#endif"

    ].join("\n"),

    defaultnormal_vertex: [

        "vec3 objectNormal;",

        "#ifdef USE_SKINNING",

            "objectNormal = skinnedNormal.xyz;",

        "#endif",

        "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )",

            "objectNormal = morphedNormal;",

        "#endif",

        "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )",

            "objectNormal = normal;",

        "#endif",

        "#ifdef FLIP_SIDED",

            "objectNormal = -objectNormal;",

        "#endif",

        "vec3 transformedNormal = normalMatrix * objectNormal;",

    ].join("\n"),

    // SHADOW MAP

    // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples
    //  http://spidergl.org/example.php?id=6
    //     http://fabiensanglard.net/shadowmapping

    shadowmap_pars_fragment: [

        "#ifdef USE_SHADOWMAP",

            "uniform sampler2D shadowMap[ MAX_SHADOWS ];",
            "uniform vec2 shadowMapSize[ MAX_SHADOWS ];",

            "uniform float shadowDarkness[ MAX_SHADOWS ];",
            "uniform float shadowBias[ MAX_SHADOWS ];",

            "varying vec4 vShadowCoord[ MAX_SHADOWS ];",

            "float unpackDepth( const in vec4 rgba_depth ) {",

                "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
                "float depth = dot( rgba_depth, bit_shift );",
                "return depth;",

            "}",

        "#endif"

    ].join("\n"),

    shadowmap_fragment: [

        "#ifdef USE_SHADOWMAP",

            "#ifdef SHADOWMAP_DEBUG",

                "vec3 frustumColors[3];",
                "frustumColors[0] = vec3( 1.0, 0.5, 0.0 );",
                "frustumColors[1] = vec3( 0.0, 1.0, 0.8 );",
                "frustumColors[2] = vec3( 0.0, 0.5, 1.0 );",

            "#endif",

            "#ifdef SHADOWMAP_CASCADE",

                "int inFrustumCount = 0;",

            "#endif",

            "float fDepth;",
            "vec3 shadowColor = vec3( 1.0 );",

            "for( int i = 0; i < MAX_SHADOWS; i ++ ) {",

                "vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;",

                // "if ( something && something )"          breaks ATI OpenGL shader compiler
                // "if ( all( something, something ) )"  using this instead

                "bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );",
                "bool inFrustum = all( inFrustumVec );",

                // don't shadow pixels outside of light frustum
                // use just first frustum (for cascades)
                // don't shadow pixels behind far plane of light frustum

                "#ifdef SHADOWMAP_CASCADE",

                    "inFrustumCount += int( inFrustum );",
                    "bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );",

                "#else",

                    "bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );",

                "#endif",

                "bool frustumTest = all( frustumTestVec );",

                "if ( frustumTest ) {",

                    "shadowCoord.z += shadowBias[ i ];",

                    "#ifdef SHADOWMAP_SOFT",

                        // Percentage-close filtering
                        // (9 pixel kernel)
                        // http://fabiensanglard.net/shadowmappingPCF/

                        "float shadow = 0.0;",

                        /*
                        // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
                        // must enroll loop manually

                        "for ( float y = -1.25; y <= 1.25; y += 1.25 )",
                            "for ( float x = -1.25; x <= 1.25; x += 1.25 ) {",

                                "vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );",

                                // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup
                                //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );",

                                "float fDepth = unpackDepth( rgbaDepth );",

                                "if ( fDepth < shadowCoord.z )",
                                    "shadow += 1.0;",

                        "}",

                        "shadow /= 9.0;",

                        */

                        "const float shadowDelta = 1.0 / 9.0;",

                        "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
                        "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",

                        "float dx0 = -1.25 * xPixelOffset;",
                        "float dy0 = -1.25 * yPixelOffset;",
                        "float dx1 = 1.25 * xPixelOffset;",
                        "float dy1 = 1.25 * yPixelOffset;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
                        "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",

                        "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",

                    "#else",

                        "vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );",
                        "float fDepth = unpackDepth( rgbaDepth );",

                        "if ( fDepth < shadowCoord.z )",

                            // spot with multiple shadows is darker

                            "shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );",

                            // spot with multiple shadows has the same color as single shadow spot

                            //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );",

                    "#endif",

                "}",


                "#ifdef SHADOWMAP_DEBUG",

                    "#ifdef SHADOWMAP_CASCADE",

                        "if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];",

                    "#else",

                        "if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];",

                    "#endif",

                "#endif",

            "}",

            "#ifdef GAMMA_OUTPUT",

                "shadowColor *= shadowColor;",

            "#endif",

            "gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;",

        "#endif"

    ].join("\n"),

    shadowmap_pars_vertex: [

        "#ifdef USE_SHADOWMAP",

            "varying vec4 vShadowCoord[ MAX_SHADOWS ];",
            "uniform mat4 shadowMatrix[ MAX_SHADOWS ];",

        "#endif"

    ].join("\n"),

    shadowmap_vertex: [

        "#ifdef USE_SHADOWMAP",

            "for( int i = 0; i < MAX_SHADOWS; i ++ ) {",

                "vShadowCoord[ i ] = shadowMatrix[ i ] * mPosition;",

            "}",

        "#endif"

    ].join("\n"),

    // ALPHATEST

    alphatest_fragment: [

        "#ifdef ALPHATEST",

            "if ( gl_FragColor.a < ALPHATEST ) discard;",

        "#endif"

    ].join("\n"),

    // LINEAR SPACE

    linear_to_gamma_fragment: [

        "#ifdef GAMMA_OUTPUT",

            "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",

        "#endif"

    ].join("\n"),


};

THREE.UniformsUtils = {

    merge: function ( uniforms ) {

        var u, p, tmp, merged = {};

        for ( u = 0; u < uniforms.length; u ++ ) {

            tmp = this.clone( uniforms[ u ] );

            for ( p in tmp ) {

                merged[ p ] = tmp[ p ];

            }

        }

        return merged;

    },

    clone: function ( uniforms_src ) {

        var u, p, parameter, parameter_src, uniforms_dst = {};

        for ( u in uniforms_src ) {

            uniforms_dst[ u ] = {};

            for ( p in uniforms_src[ u ] ) {

                parameter_src = uniforms_src[ u ][ p ];

                if ( parameter_src instanceof THREE.Color ||
                     parameter_src instanceof THREE.Vector2 ||
                     parameter_src instanceof THREE.Vector3 ||
                     parameter_src instanceof THREE.Vector4 ||
                     parameter_src instanceof THREE.Matrix4 ||
                     parameter_src instanceof THREE.Texture ) {

                    uniforms_dst[ u ][ p ] = parameter_src.clone();

                } else if ( parameter_src instanceof Array ) {

                    uniforms_dst[ u ][ p ] = parameter_src.slice();

                } else {

                    uniforms_dst[ u ][ p ] = parameter_src;

                }

            }

        }

        return uniforms_dst;

    }

};

THREE.UniformsLib = {

    common: {

        "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
        "opacity" : { type: "f", value: 1.0 },

        "map" : { type: "t", value: null },
        "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },

        "lightMap" : { type: "t", value: null },
        "specularMap" : { type: "t", value: null },

        "envMap" : { type: "t", value: null },
        "flipEnvMap" : { type: "f", value: -1 },
        "useRefract" : { type: "i", value: 0 },
        "reflectivity" : { type: "f", value: 1.0 },
        "refractionRatio" : { type: "f", value: 0.98 },
        "combine" : { type: "i", value: 0 },

        "morphTargetInfluences" : { type: "f", value: 0 }

    },

    bump: {

        "bumpMap" : { type: "t", value: null },
        "bumpScale" : { type: "f", value: 1 }

    },

    normalmap: {

        "normalMap" : { type: "t", value: null },
        "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }
    },

    fog : {

        "fogDensity" : { type: "f", value: 0.00025 },
        "fogNear" : { type: "f", value: 1 },
        "fogFar" : { type: "f", value: 2000 },
        "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }

    },

    lights: {

        "ambientLightColor" : { type: "fv", value: [] },

        "directionalLightDirection" : { type: "fv", value: [] },
        "directionalLightColor" : { type: "fv", value: [] },

        "hemisphereLightPosition" : { type: "fv", value: [] },
        "hemisphereLightSkyColor" : { type: "fv", value: [] },
        "hemisphereLightGroundColor" : { type: "fv", value: [] },

        "pointLightColor" : { type: "fv", value: [] },
        "pointLightPosition" : { type: "fv", value: [] },
        "pointLightDistance" : { type: "fv1", value: [] },

        "spotLightColor" : { type: "fv", value: [] },
        "spotLightPosition" : { type: "fv", value: [] },
        "spotLightDirection" : { type: "fv", value: [] },
        "spotLightDistance" : { type: "fv1", value: [] },
        "spotLightAngle" : { type: "fv1", value: [] },
        "spotLightExponent" : { type: "fv1", value: [] }

    },

    particle: {

        "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
        "opacity" : { type: "f", value: 1.0 },
        "size" : { type: "f", value: 1.0 },
        "scale" : { type: "f", value: 1.0 },
        "map" : { type: "t", value: null },

        "fogDensity" : { type: "f", value: 0.00025 },
        "fogNear" : { type: "f", value: 1 },
        "fogFar" : { type: "f", value: 2000 },
        "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }

    },

    shadowmap: {

        "shadowMap": { type: "tv", value: [] },
        "shadowMapSize": { type: "v2v", value: [] },

        "shadowBias" : { type: "fv1", value: [] },
        "shadowDarkness": { type: "fv1", value: [] },

        "shadowMatrix" : { type: "m4v", value: [] },

    }

};

THREE.ShaderLib = {

    'depth': {

        uniforms: {

            "mNear": { type: "f", value: 1.0 },
            "mFar" : { type: "f", value: 2000.0 },
            "opacity" : { type: "f", value: 1.0 }

        },

        vertexShader: [

            "void main() {",

                "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

            "}"

        ].join("\n"),

        fragmentShader: [

            "uniform float mNear;",
            "uniform float mFar;",
            "uniform float opacity;",

            "void main() {",

                "float depth = gl_FragCoord.z / gl_FragCoord.w;",
                "float color = 1.0 - smoothstep( mNear, mFar, depth );",
                "gl_FragColor = vec4( vec3( color ), opacity );",

            "}"

        ].join("\n")

    },

    'normal': {

        uniforms: {

            "opacity" : { type: "f", value: 1.0 }

        },

        vertexShader: [

            "varying vec3 vNormal;",

            "void main() {",

                "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
                "vNormal = normalMatrix * normal;",

                "gl_Position = projectionMatrix * mvPosition;",

            "}"

        ].join("\n"),

        fragmentShader: [

            "uniform float opacity;",
            "varying vec3 vNormal;",

            "void main() {",

                "gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",

            "}"

        ].join("\n")

    },

    'basic': {

        uniforms: THREE.UniformsUtils.merge( [

            THREE.UniformsLib[ "common" ],
            THREE.UniformsLib[ "fog" ],
            THREE.UniformsLib[ "shadowmap" ]

        ] ),

        vertexShader: [

            THREE.ShaderChunk[ "map_pars_vertex" ],
            THREE.ShaderChunk[ "lightmap_pars_vertex" ],
            THREE.ShaderChunk[ "envmap_pars_vertex" ],
            THREE.ShaderChunk[ "color_pars_vertex" ],
            THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
            THREE.ShaderChunk[ "skinning_pars_vertex" ],
            THREE.ShaderChunk[ "shadowmap_pars_vertex" ],

            "void main() {",

                THREE.ShaderChunk[ "map_vertex" ],
                THREE.ShaderChunk[ "lightmap_vertex" ],
                THREE.ShaderChunk[ "color_vertex" ],

                "#ifdef USE_ENVMAP",

                THREE.ShaderChunk[ "morphnormal_vertex" ],
                THREE.ShaderChunk[ "skinbase_vertex" ],
                THREE.ShaderChunk[ "skinnormal_vertex" ],
                THREE.ShaderChunk[ "defaultnormal_vertex" ],

                "#endif",

                THREE.ShaderChunk[ "morphtarget_vertex" ],
                THREE.ShaderChunk[ "skinning_vertex" ],
                THREE.ShaderChunk[ "default_vertex" ],

                THREE.ShaderChunk[ "worldpos_vertex" ],
                THREE.ShaderChunk[ "envmap_vertex" ],
                THREE.ShaderChunk[ "shadowmap_vertex" ],

            "}"

        ].join("\n"),

        fragmentShader: [

            "uniform vec3 diffuse;",
            "uniform float opacity;",

            THREE.ShaderChunk[ "color_pars_fragment" ],
            THREE.ShaderChunk[ "map_pars_fragment" ],
            THREE.ShaderChunk[ "lightmap_pars_fragment" ],
            THREE.ShaderChunk[ "envmap_pars_fragment" ],
            THREE.ShaderChunk[ "fog_pars_fragment" ],
            THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
            THREE.ShaderChunk[ "specularmap_pars_fragment" ],

            "void main() {",

                "gl_FragColor = vec4( diffuse, opacity );",

                THREE.ShaderChunk[ "map_fragment" ],
                THREE.ShaderChunk[ "alphatest_fragment" ],
                THREE.ShaderChunk[ "specularmap_fragment" ],
                THREE.ShaderChunk[ "lightmap_fragment" ],
                THREE.ShaderChunk[ "color_fragment" ],
                THREE.ShaderChunk[ "envmap_fragment" ],
                THREE.ShaderChunk[ "shadowmap_fragment" ],

                THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

                THREE.ShaderChunk[ "fog_fragment" ],

            "}"

        ].join("\n")

    },

    'lambert': {

        uniforms: THREE.UniformsUtils.merge( [

            THREE.UniformsLib[ "common" ],
            THREE.UniformsLib[ "fog" ],
            THREE.UniformsLib[ "lights" ],
            THREE.UniformsLib[ "shadowmap" ],

            {
                "ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
                "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
                "wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
            }

        ] ),

        vertexShader: [

            "#define LAMBERT",

            "varying vec3 vLightFront;",

            "#ifdef DOUBLE_SIDED",

                "varying vec3 vLightBack;",

            "#endif",

            THREE.ShaderChunk[ "map_pars_vertex" ],
            THREE.ShaderChunk[ "lightmap_pars_vertex" ],
            THREE.ShaderChunk[ "envmap_pars_vertex" ],
            THREE.ShaderChunk[ "lights_lambert_pars_vertex" ],
            THREE.ShaderChunk[ "color_pars_vertex" ],
            THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
            THREE.ShaderChunk[ "skinning_pars_vertex" ],
            THREE.ShaderChunk[ "shadowmap_pars_vertex" ],

            "void main() {",

                THREE.ShaderChunk[ "map_vertex" ],
                THREE.ShaderChunk[ "lightmap_vertex" ],
                THREE.ShaderChunk[ "color_vertex" ],

                THREE.ShaderChunk[ "morphnormal_vertex" ],
                THREE.ShaderChunk[ "skinbase_vertex" ],
                THREE.ShaderChunk[ "skinnormal_vertex" ],
                THREE.ShaderChunk[ "defaultnormal_vertex" ],

                THREE.ShaderChunk[ "morphtarget_vertex" ],
                THREE.ShaderChunk[ "skinning_vertex" ],
                THREE.ShaderChunk[ "default_vertex" ],

                THREE.ShaderChunk[ "worldpos_vertex" ],
                THREE.ShaderChunk[ "envmap_vertex" ],
                THREE.ShaderChunk[ "lights_lambert_vertex" ],
                THREE.ShaderChunk[ "shadowmap_vertex" ],

            "}"

        ].join("\n"),

        fragmentShader: [

            "uniform float opacity;",

            "varying vec3 vLightFront;",

            "#ifdef DOUBLE_SIDED",

                "varying vec3 vLightBack;",

            "#endif",

            THREE.ShaderChunk[ "color_pars_fragment" ],
            THREE.ShaderChunk[ "map_pars_fragment" ],
            THREE.ShaderChunk[ "lightmap_pars_fragment" ],
            THREE.ShaderChunk[ "envmap_pars_fragment" ],
            THREE.ShaderChunk[ "fog_pars_fragment" ],
            THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
            THREE.ShaderChunk[ "specularmap_pars_fragment" ],

            "void main() {",

                "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",

                THREE.ShaderChunk[ "map_fragment" ],
                THREE.ShaderChunk[ "alphatest_fragment" ],
                THREE.ShaderChunk[ "specularmap_fragment" ],

                "#ifdef DOUBLE_SIDED",

                    //"float isFront = float( gl_FrontFacing );",
                    //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;",

                    "if ( gl_FrontFacing )",
                        "gl_FragColor.xyz *= vLightFront;",
                    "else",
                        "gl_FragColor.xyz *= vLightBack;",

                "#else",

                    "gl_FragColor.xyz *= vLightFront;",

                "#endif",

                THREE.ShaderChunk[ "lightmap_fragment" ],
                THREE.ShaderChunk[ "color_fragment" ],
                THREE.ShaderChunk[ "envmap_fragment" ],
                THREE.ShaderChunk[ "shadowmap_fragment" ],

                THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

                THREE.ShaderChunk[ "fog_fragment" ],

            "}"

        ].join("\n")

    },

    'phong': {

        uniforms: THREE.UniformsUtils.merge( [

            THREE.UniformsLib[ "common" ],
            THREE.UniformsLib[ "bump" ],
            THREE.UniformsLib[ "normalmap" ],
            THREE.UniformsLib[ "fog" ],
            THREE.UniformsLib[ "lights" ],
            THREE.UniformsLib[ "shadowmap" ],

            {
                "ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
                "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
                "specular" : { type: "c", value: new THREE.Color( 0x111111 ) },
                "shininess": { type: "f", value: 30 },
                "wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
            }

        ] ),

        vertexShader: [

            "#define PHONG",

            "varying vec3 vViewPosition;",
            "varying vec3 vNormal;",

            THREE.ShaderChunk[ "map_pars_vertex" ],
            THREE.ShaderChunk[ "lightmap_pars_vertex" ],
            THREE.ShaderChunk[ "envmap_pars_vertex" ],
            THREE.ShaderChunk[ "lights_phong_pars_vertex" ],
            THREE.ShaderChunk[ "color_pars_vertex" ],
            THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
            THREE.ShaderChunk[ "skinning_pars_vertex" ],
            THREE.ShaderChunk[ "shadowmap_pars_vertex" ],

            "void main() {",

                THREE.ShaderChunk[ "map_vertex" ],
                THREE.ShaderChunk[ "lightmap_vertex" ],
                THREE.ShaderChunk[ "color_vertex" ],

                THREE.ShaderChunk[ "morphnormal_vertex" ],
                THREE.ShaderChunk[ "skinbase_vertex" ],
                THREE.ShaderChunk[ "skinnormal_vertex" ],
                THREE.ShaderChunk[ "defaultnormal_vertex" ],

                "vNormal = transformedNormal;",

                THREE.ShaderChunk[ "morphtarget_vertex" ],
                THREE.ShaderChunk[ "skinning_vertex" ],
                THREE.ShaderChunk[ "default_vertex" ],

                "vViewPosition = -mvPosition.xyz;",

                THREE.ShaderChunk[ "worldpos_vertex" ],
                THREE.ShaderChunk[ "envmap_vertex" ],
                THREE.ShaderChunk[ "lights_phong_vertex" ],
                THREE.ShaderChunk[ "shadowmap_vertex" ],

            "}"

        ].join("\n"),

        fragmentShader: [

            "uniform vec3 diffuse;",
            "uniform float opacity;",

            "uniform vec3 ambient;",
            "uniform vec3 emissive;",
            "uniform vec3 specular;",
            "uniform float shininess;",

            THREE.ShaderChunk[ "color_pars_fragment" ],
            THREE.ShaderChunk[ "map_pars_fragment" ],
            THREE.ShaderChunk[ "lightmap_pars_fragment" ],
            THREE.ShaderChunk[ "envmap_pars_fragment" ],
            THREE.ShaderChunk[ "fog_pars_fragment" ],
            THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
            THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
            THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
            THREE.ShaderChunk[ "normalmap_pars_fragment" ],
            THREE.ShaderChunk[ "specularmap_pars_fragment" ],

            "void main() {",

                "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",

                THREE.ShaderChunk[ "map_fragment" ],
                THREE.ShaderChunk[ "alphatest_fragment" ],
                THREE.ShaderChunk[ "specularmap_fragment" ],

                THREE.ShaderChunk[ "lights_phong_fragment" ],

                THREE.ShaderChunk[ "lightmap_fragment" ],
                THREE.ShaderChunk[ "color_fragment" ],
                THREE.ShaderChunk[ "envmap_fragment" ],
                THREE.ShaderChunk[ "shadowmap_fragment" ],

                THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

                THREE.ShaderChunk[ "fog_fragment" ],

            "}"

        ].join("\n")

    },

    'particle_basic': {

        uniforms:  THREE.UniformsUtils.merge( [

            THREE.UniformsLib[ "particle" ],
            THREE.UniformsLib[ "shadowmap" ]

        ] ),

        vertexShader: [

            "uniform float size;",
            "uniform float scale;",

            THREE.ShaderChunk[ "color_pars_vertex" ],
            THREE.ShaderChunk[ "shadowmap_pars_vertex" ],

            "void main() {",

                THREE.ShaderChunk[ "color_vertex" ],

                "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",

                "#ifdef USE_SIZEATTENUATION",
                    "gl_PointSize = size * ( scale / length( mvPosition.xyz ) );",
                "#else",
                    "gl_PointSize = size;",
                "#endif",

                "gl_Position = projectionMatrix * mvPosition;",

                THREE.ShaderChunk[ "worldpos_vertex" ],
                THREE.ShaderChunk[ "shadowmap_vertex" ],

            "}"

        ].join("\n"),

        fragmentShader: [

            "uniform vec3 psColor;",
            "uniform float opacity;",

            THREE.ShaderChunk[ "color_pars_fragment" ],
            THREE.ShaderChunk[ "map_particle_pars_fragment" ],
            THREE.ShaderChunk[ "fog_pars_fragment" ],
            THREE.ShaderChunk[ "shadowmap_pars_fragment" ],

            "void main() {",

                "gl_FragColor = vec4( psColor, opacity );",

                THREE.ShaderChunk[ "map_particle_fragment" ],
                THREE.ShaderChunk[ "alphatest_fragment" ],
                THREE.ShaderChunk[ "color_fragment" ],
                THREE.ShaderChunk[ "shadowmap_fragment" ],
                THREE.ShaderChunk[ "fog_fragment" ],

            "}"

        ].join("\n")

    },

    // Depth encoding into RGBA texture
    //     based on SpiderGL shadow map example
    //         http://spidergl.org/example.php?id=6
    //     originally from
    //        http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD
    //     see also here:
    //        http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/

    'depthRGBA': {

        uniforms: {},

        vertexShader: [

            THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
            THREE.ShaderChunk[ "skinning_pars_vertex" ],

            "void main() {",

                THREE.ShaderChunk[ "skinbase_vertex" ],
                THREE.ShaderChunk[ "morphtarget_vertex" ],
                THREE.ShaderChunk[ "skinning_vertex" ],
                THREE.ShaderChunk[ "default_vertex" ],

            "}"

        ].join("\n"),

        fragmentShader: [

            "vec4 pack_depth( const in float depth ) {",

                "const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );",
                "const vec4 bit_mask  = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );",
                "vec4 res = fract( depth * bit_shift );",
                "res -= res.xxyz * bit_mask;",
                "return res;",

            "}",

            "void main() {",

                "gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );",

                //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );",
                //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );",
                //"gl_FragData[ 0 ] = pack_depth( z );",
                //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );",

            "}"

        ].join("\n")

    }

};
/**
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author szimek / https://github.com/szimek/
 */

THREE.WebGLRenderer = function ( parameters ) {

    console.log( 'THREE.WebGLRenderer', THREE.REVISION );

    parameters = parameters || {};

    var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),

    _precision = parameters.precision !== undefined ? parameters.precision : 'highp',

    _alpha = parameters.alpha !== undefined ? parameters.alpha : true,
    _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
    _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
    _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
    _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,

    _clearColor = parameters.clearColor !== undefined ? new THREE.Color( parameters.clearColor ) : new THREE.Color( 0x000000 ),
    _clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0,

    _maxLights = parameters.maxLights !== undefined ? parameters.maxLights : 4;

    // public properties

    this.domElement = _canvas;
    this.context = null;

    // clearing

    this.autoClear = true;
    this.autoClearColor = true;
    this.autoClearDepth = true;
    this.autoClearStencil = true;

    // scene graph

    this.sortObjects = true;

    this.autoUpdateObjects = true;
    this.autoUpdateScene = true;

    // physically based shading

    this.gammaInput = false;
    this.gammaOutput = false;
    this.physicallyBasedShading = false;

    // shadow map

    this.shadowMapEnabled = false;
    this.shadowMapAutoUpdate = true;
    this.shadowMapSoft = true;
    this.shadowMapCullFrontFaces = true;
    this.shadowMapDebug = false;
    this.shadowMapCascade = false;

    // morphs

    this.maxMorphTargets = 8;
    this.maxMorphNormals = 4;

    // flags

    this.autoScaleCubemaps = true;

    // custom render plugins

    this.renderPluginsPre = [];
    this.renderPluginsPost = [];

    // info

    this.info = {

        memory: {

            programs: 0,
            geometries: 0,
            textures: 0

        },

        render: {

            calls: 0,
            vertices: 0,
            faces: 0,
            points: 0

        }

    };

    // internal properties

    var _this = this,

    _programs = [],
    _programs_counter = 0,

    // internal state cache

    _currentProgram = null,
    _currentFramebuffer = null,
    _currentMaterialId = -1,
    _currentGeometryGroupHash = null,
    _currentCamera = null,
    _geometryGroupCounter = 0,

    _usedTextureUnits = 0,

    // GL state cache

    _oldDoubleSided = -1,
    _oldFlipSided = -1,

    _oldBlending = -1,

    _oldBlendEquation = -1,
    _oldBlendSrc = -1,
    _oldBlendDst = -1,

    _oldDepthTest = -1,
    _oldDepthWrite = -1,

    _oldPolygonOffset = null,
    _oldPolygonOffsetFactor = null,
    _oldPolygonOffsetUnits = null,

    _oldLineWidth = null,

    _viewportX = 0,
    _viewportY = 0,
    _viewportWidth = 0,
    _viewportHeight = 0,
    _currentWidth = 0,
    _currentHeight = 0,

    // frustum

    _frustum = new THREE.Frustum(),

     // camera matrices cache

    _projScreenMatrix = new THREE.Matrix4(),
    _projScreenMatrixPS = new THREE.Matrix4(),

    _vector3 = new THREE.Vector4(),

    // light arrays cache

    _direction = new THREE.Vector3(),

    _lightsNeedUpdate = true,

    _lights = {

        ambient: [ 0, 0, 0 ],
        directional: { length: 0, colors: new Array(), positions: new Array() },
        point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() },
        spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), angles: new Array(), exponents: new Array() },
        hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }

    };

    // initialize

    var _gl;

    var _glExtensionTextureFloat;
    var _glExtensionStandardDerivatives;
    var _glExtensionTextureFilterAnisotropic;
    var _glExtensionCompressedTextureS3TC;

    initGL();

    setDefaultGLState();

    this.context = _gl;

    // GPU capabilities

    var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
    var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
    var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
    var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );

    var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;

    var _supportsVertexTextures = ( _maxVertexTextures > 0 );
    var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;

    var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];

    // API

    this.getContext = function () {

        return _gl;

    };

    this.supportsVertexTextures = function () {

        return _supportsVertexTextures;

    };

    this.getMaxAnisotropy  = function () {

        return _maxAnisotropy;

    };

    this.setSize = function ( width, height ) {

        _canvas.width = width;
        _canvas.height = height;

        this.setViewport( 0, 0, _canvas.width, _canvas.height );

    };

    this.setViewport = function ( x, y, width, height ) {

        _viewportX = x !== undefined ? x : 0;
        _viewportY = y !== undefined ? y : 0;

        _viewportWidth = width !== undefined ? width : _canvas.width;
        _viewportHeight = height !== undefined ? height : _canvas.height;

        _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );

    };

    this.setScissor = function ( x, y, width, height ) {

        _gl.scissor( x, y, width, height );

    };

    this.enableScissorTest = function ( enable ) {

        enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );

    };

    // Clearing

    this.setClearColorHex = function ( hex, alpha ) {

        _clearColor.setHex( hex );
        _clearAlpha = alpha;

        _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );

    };

    this.setClearColor = function ( color, alpha ) {

        _clearColor.copy( color );
        _clearAlpha = alpha;

        _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );

    };

    this.getClearColor = function () {

        return _clearColor;

    };

    this.getClearAlpha = function () {

        return _clearAlpha;

    };

    this.clear = function ( color, depth, stencil ) {

        var bits = 0;

        if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
        if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
        if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;

        _gl.clear( bits );

    };

    this.clearTarget = function ( renderTarget, color, depth, stencil ) {

        this.setRenderTarget( renderTarget );
        this.clear( color, depth, stencil );

    };

    // Plugins

    this.addPostPlugin = function ( plugin ) {

        plugin.init( this );
        this.renderPluginsPost.push( plugin );

    };

    this.addPrePlugin = function ( plugin ) {

        plugin.init( this );
        this.renderPluginsPre.push( plugin );

    };

    // Deallocation

    this.deallocateObject = function ( object ) {

        if ( ! object.__webglInit ) return;

        object.__webglInit = false;

        delete object._modelViewMatrix;
        delete object._normalMatrix;

        delete object._normalMatrixArray;
        delete object._modelViewMatrixArray;
        delete object._modelMatrixArray;

        if ( object instanceof THREE.Mesh ) {

            for ( var g in object.geometry.geometryGroups ) {

                deleteMeshBuffers( object.geometry.geometryGroups[ g ] );

            }

        } else if ( object instanceof THREE.Ribbon ) {

            deleteRibbonBuffers( object.geometry );

        } else if ( object instanceof THREE.Line ) {

            deleteLineBuffers( object.geometry );

        } else if ( object instanceof THREE.ParticleSystem ) {

            deleteParticleBuffers( object.geometry );

        }

    };

    this.deallocateTexture = function ( texture ) {

        if ( ! texture.__webglInit ) return;

        texture.__webglInit = false;
        _gl.deleteTexture( texture.__webglTexture );

        _this.info.memory.textures --;

    };

    this.deallocateRenderTarget = function ( renderTarget ) {

        if ( !renderTarget || ! renderTarget.__webglTexture ) return;

        _gl.deleteTexture( renderTarget.__webglTexture );

        if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {

            for ( var i = 0; i < 6; i ++ ) {

                _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
                _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );

            }

        } else {

            _gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
            _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );

        }

    };

    this.deallocateMaterial = function ( material ) {

        var program = material.program;

        if ( ! program ) return;

        material.program = undefined;

        // only deallocate GL program if this was the last use of shared program
        // assumed there is only single copy of any program in the _programs list
        // (that's how it's constructed)

        var i, il, programInfo;
        var deleteProgram = false;

        for ( i = 0, il = _programs.length; i < il; i ++ ) {

            programInfo = _programs[ i ];

            if ( programInfo.program === program ) {

                programInfo.usedTimes --;

                if ( programInfo.usedTimes === 0 ) {

                    deleteProgram = true;

                }

                break;

            }

        }

        if ( deleteProgram ) {

            // avoid using array.splice, this is costlier than creating new array from scratch

            var newPrograms = [];

            for ( i = 0, il = _programs.length; i < il; i ++ ) {

                programInfo = _programs[ i ];

                if ( programInfo.program !== program ) {

                    newPrograms.push( programInfo );

                }

            }

            _programs = newPrograms;

            _gl.deleteProgram( program );

            _this.info.memory.programs --;

        }

    };

    // Rendering

    this.updateShadowMap = function ( scene, camera ) {

        _currentProgram = null;
        _oldBlending = -1;
        _oldDepthTest = -1;
        _oldDepthWrite = -1;
        _currentGeometryGroupHash = -1;
        _currentMaterialId = -1;
        _lightsNeedUpdate = true;
        _oldDoubleSided = -1;
        _oldFlipSided = -1;

        this.shadowMapPlugin.update( scene, camera );

    };

    // Internal functions

    // Buffer allocation

    function createParticleBuffers ( geometry ) {

        geometry.__webglVertexBuffer = _gl.createBuffer();
        geometry.__webglColorBuffer = _gl.createBuffer();

        _this.info.memory.geometries ++;

    };

    function createLineBuffers ( geometry ) {

        geometry.__webglVertexBuffer = _gl.createBuffer();
        geometry.__webglColorBuffer = _gl.createBuffer();

        _this.info.memory.geometries ++;

    };

    function createRibbonBuffers ( geometry ) {

        geometry.__webglVertexBuffer = _gl.createBuffer();
        geometry.__webglColorBuffer = _gl.createBuffer();

        _this.info.memory.geometries ++;

    };

    function createMeshBuffers ( geometryGroup ) {

        geometryGroup.__webglVertexBuffer = _gl.createBuffer();
        geometryGroup.__webglNormalBuffer = _gl.createBuffer();
        geometryGroup.__webglTangentBuffer = _gl.createBuffer();
        geometryGroup.__webglColorBuffer = _gl.createBuffer();
        geometryGroup.__webglUVBuffer = _gl.createBuffer();
        geometryGroup.__webglUV2Buffer = _gl.createBuffer();

        geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
        geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();

        geometryGroup.__webglFaceBuffer = _gl.createBuffer();
        geometryGroup.__webglLineBuffer = _gl.createBuffer();

        var m, ml;

        if ( geometryGroup.numMorphTargets ) {

            geometryGroup.__webglMorphTargetsBuffers = [];

            for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {

                geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );

            }

        }

        if ( geometryGroup.numMorphNormals ) {

            geometryGroup.__webglMorphNormalsBuffers = [];

            for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {

                geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() );

            }

        }

        _this.info.memory.geometries ++;

    };

    // Buffer deallocation

    function deleteParticleBuffers ( geometry ) {

        _gl.deleteBuffer( geometry.__webglVertexBuffer );
        _gl.deleteBuffer( geometry.__webglColorBuffer );

        _this.info.memory.geometries --;

    };

    function deleteLineBuffers ( geometry ) {

        _gl.deleteBuffer( geometry.__webglVertexBuffer );
        _gl.deleteBuffer( geometry.__webglColorBuffer );

        _this.info.memory.geometries --;

    };

    function deleteRibbonBuffers ( geometry ) {

        _gl.deleteBuffer( geometry.__webglVertexBuffer );
        _gl.deleteBuffer( geometry.__webglColorBuffer );

        _this.info.memory.geometries --;

    };

    function deleteMeshBuffers ( geometryGroup ) {

        _gl.deleteBuffer( geometryGroup.__webglVertexBuffer );
        _gl.deleteBuffer( geometryGroup.__webglNormalBuffer );
        _gl.deleteBuffer( geometryGroup.__webglTangentBuffer );
        _gl.deleteBuffer( geometryGroup.__webglColorBuffer );
        _gl.deleteBuffer( geometryGroup.__webglUVBuffer );
        _gl.deleteBuffer( geometryGroup.__webglUV2Buffer );

        _gl.deleteBuffer( geometryGroup.__webglSkinIndicesBuffer );
        _gl.deleteBuffer( geometryGroup.__webglSkinWeightsBuffer );

        _gl.deleteBuffer( geometryGroup.__webglFaceBuffer );
        _gl.deleteBuffer( geometryGroup.__webglLineBuffer );

        var m, ml;

        if ( geometryGroup.numMorphTargets ) {

            for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {

                _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );

            }

        }

        if ( geometryGroup.numMorphNormals ) {

            for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {

                _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );

            }

        }


        if ( geometryGroup.__webglCustomAttributesList ) {

            for ( var id in geometryGroup.__webglCustomAttributesList ) {

                _gl.deleteBuffer( geometryGroup.__webglCustomAttributesList[ id ].buffer );

            }

        }

        _this.info.memory.geometries --;

    };

    // Buffer initialization

    function initCustomAttributes ( geometry, object ) {

        var nvertices = geometry.vertices.length;

        var material = object.material;

        if ( material.attributes ) {

            if ( geometry.__webglCustomAttributesList === undefined ) {

                geometry.__webglCustomAttributesList = [];

            }

            for ( var a in material.attributes ) {

                var attribute = material.attributes[ a ];

                if( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {

                    attribute.__webglInitialized = true;

                    var size = 1;        // "f" and "i"

                    if ( attribute.type === "v2" ) size = 2;
                    else if ( attribute.type === "v3" ) size = 3;
                    else if ( attribute.type === "v4" ) size = 4;
                    else if ( attribute.type === "c"  ) size = 3;

                    attribute.size = size;

                    attribute.array = new Float32Array( nvertices * size );

                    attribute.buffer = _gl.createBuffer();
                    attribute.buffer.belongsToAttribute = a;

                    attribute.needsUpdate = true;

                }

                geometry.__webglCustomAttributesList.push( attribute );

            }

        }

    };

    function initParticleBuffers ( geometry, object ) {

        var nvertices = geometry.vertices.length;

        geometry.__vertexArray = new Float32Array( nvertices * 3 );
        geometry.__colorArray = new Float32Array( nvertices * 3 );

        geometry.__sortArray = [];

        geometry.__webglParticleCount = nvertices;

        initCustomAttributes ( geometry, object );

    };

    function initLineBuffers ( geometry, object ) {

        var nvertices = geometry.vertices.length;

        geometry.__vertexArray = new Float32Array( nvertices * 3 );
        geometry.__colorArray = new Float32Array( nvertices * 3 );

        geometry.__webglLineCount = nvertices;

        initCustomAttributes ( geometry, object );

    };

    function initRibbonBuffers ( geometry ) {

        var nvertices = geometry.vertices.length;

        geometry.__vertexArray = new Float32Array( nvertices * 3 );
        geometry.__colorArray = new Float32Array( nvertices * 3 );

        geometry.__webglVertexCount = nvertices;

    };

    function initMeshBuffers ( geometryGroup, object ) {

        var geometry = object.geometry,
            faces3 = geometryGroup.faces3,
            faces4 = geometryGroup.faces4,

            nvertices = faces3.length * 3 + faces4.length * 4,
            ntris     = faces3.length * 1 + faces4.length * 2,
            nlines    = faces3.length * 3 + faces4.length * 4,

            material = getBufferMaterial( object, geometryGroup ),

            uvType = bufferGuessUVType( material ),
            normalType = bufferGuessNormalType( material ),
            vertexColorType = bufferGuessVertexColorType( material );

        //console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material );

        geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );

        if ( normalType ) {

            geometryGroup.__normalArray = new Float32Array( nvertices * 3 );

        }

        if ( geometry.hasTangents ) {

            geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );

        }

        if ( vertexColorType ) {

            geometryGroup.__colorArray = new Float32Array( nvertices * 3 );

        }

        if ( uvType ) {

            if ( geometry.faceUvs.length > 0 || geometry.faceVertexUvs.length > 0 ) {

                geometryGroup.__uvArray = new Float32Array( nvertices * 2 );

            }

            if ( geometry.faceUvs.length > 1 || geometry.faceVertexUvs.length > 1 ) {

                geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );

            }

        }

        if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {

            geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
            geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );

        }

        geometryGroup.__faceArray = new Uint16Array( ntris * 3 );
        geometryGroup.__lineArray = new Uint16Array( nlines * 2 );

        var m, ml;

        if ( geometryGroup.numMorphTargets ) {

            geometryGroup.__morphTargetsArrays = [];

            for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {

                geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );

            }

        }

        if ( geometryGroup.numMorphNormals ) {

            geometryGroup.__morphNormalsArrays = [];

            for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {

                geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) );

            }

        }

        geometryGroup.__webglFaceCount = ntris * 3;
        geometryGroup.__webglLineCount = nlines * 2;


        // custom attributes

        if ( material.attributes ) {

            if ( geometryGroup.__webglCustomAttributesList === undefined ) {

                geometryGroup.__webglCustomAttributesList = [];

            }

            for ( var a in material.attributes ) {

                // Do a shallow copy of the attribute object so different geometryGroup chunks use different
                // attribute buffers which are correctly indexed in the setMeshBuffers function

                var originalAttribute = material.attributes[ a ];

                var attribute = {};

                for ( var property in originalAttribute ) {

                    attribute[ property ] = originalAttribute[ property ];

                }

                if( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {

                    attribute.__webglInitialized = true;

                    var size = 1;        // "f" and "i"

                    if( attribute.type === "v2" ) size = 2;
                    else if( attribute.type === "v3" ) size = 3;
                    else if( attribute.type === "v4" ) size = 4;
                    else if( attribute.type === "c"  ) size = 3;

                    attribute.size = size;

                    attribute.array = new Float32Array( nvertices * size );

                    attribute.buffer = _gl.createBuffer();
                    attribute.buffer.belongsToAttribute = a;

                    originalAttribute.needsUpdate = true;
                    attribute.__original = originalAttribute;

                }

                geometryGroup.__webglCustomAttributesList.push( attribute );

            }

        }

        geometryGroup.__inittedArrays = true;

    };

    function getBufferMaterial( object, geometryGroup ) {

        if ( object.material && ! ( object.material instanceof THREE.MeshFaceMaterial ) ) {

            return object.material;

        } else if ( geometryGroup.materialIndex >= 0 ) {

            return object.geometry.materials[ geometryGroup.materialIndex ];

        }

    };

    function materialNeedsSmoothNormals ( material ) {

        return material && material.shading !== undefined && material.shading === THREE.SmoothShading;

    };

    function bufferGuessNormalType ( material ) {

        // only MeshBasicMaterial and MeshDepthMaterial don't need normals

        if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) {

            return false;

        }

        if ( materialNeedsSmoothNormals( material ) ) {

            return THREE.SmoothShading;

        } else {

            return THREE.FlatShading;

        }

    };

    function bufferGuessVertexColorType ( material ) {

        if ( material.vertexColors ) {

            return material.vertexColors;

        }

        return false;

    };

    function bufferGuessUVType ( material ) {

        // material must use some texture to require uvs

        if ( material.map || material.lightMap || material.bumpMap || material.normalMap || material.specularMap || material instanceof THREE.ShaderMaterial ) {

            return true;

        }

        return false;

    };

    //

    function initDirectBuffers( geometry ) {

        var a, attribute, type;

        for ( a in geometry.attributes ) {

            if ( a === "index" ) {

                type = _gl.ELEMENT_ARRAY_BUFFER;

            } else {

                type = _gl.ARRAY_BUFFER;

            }

            attribute = geometry.attributes[ a ];

            attribute.buffer = _gl.createBuffer();

            _gl.bindBuffer( type, attribute.buffer );
            _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW );

        }

    };

    // Buffer setting

    function setParticleBuffers ( geometry, hint, object ) {

        var v, c, vertex, offset, index, color,

        vertices = geometry.vertices,
        vl = vertices.length,

        colors = geometry.colors,
        cl = colors.length,

        vertexArray = geometry.__vertexArray,
        colorArray = geometry.__colorArray,

        sortArray = geometry.__sortArray,

        dirtyVertices = geometry.verticesNeedUpdate,
        dirtyElements = geometry.elementsNeedUpdate,
        dirtyColors = geometry.colorsNeedUpdate,

        customAttributes = geometry.__webglCustomAttributesList,
        i, il,
        a, ca, cal, value,
        customAttribute;

        if ( object.sortParticles ) {

            _projScreenMatrixPS.copy( _projScreenMatrix );
            _projScreenMatrixPS.multiplySelf( object.matrixWorld );

            for ( v = 0; v < vl; v ++ ) {

                vertex = vertices[ v ];

                _vector3.copy( vertex );
                _projScreenMatrixPS.multiplyVector3( _vector3 );

                sortArray[ v ] = [ _vector3.z, v ];

            }

            sortArray.sort( function( a, b ) { return b[ 0 ] - a[ 0 ]; } );

            for ( v = 0; v < vl; v ++ ) {

                vertex = vertices[ sortArray[v][1] ];

                offset = v * 3;

                vertexArray[ offset ]     = vertex.x;
                vertexArray[ offset + 1 ] = vertex.y;
                vertexArray[ offset + 2 ] = vertex.z;

            }

            for ( c = 0; c < cl; c ++ ) {

                offset = c * 3;

                color = colors[ sortArray[c][1] ];

                colorArray[ offset ]     = color.r;
                colorArray[ offset + 1 ] = color.g;
                colorArray[ offset + 2 ] = color.b;

            }

            if ( customAttributes ) {

                for ( i = 0, il = customAttributes.length; i < il; i ++ ) {

                    customAttribute = customAttributes[ i ];

                    if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue;

                    offset = 0;

                    cal = customAttribute.value.length;

                    if ( customAttribute.size === 1 ) {

                        for ( ca = 0; ca < cal; ca ++ ) {

                            index = sortArray[ ca ][ 1 ];

                            customAttribute.array[ ca ] = customAttribute.value[ index ];

                        }

                    } else if ( customAttribute.size === 2 ) {

                        for ( ca = 0; ca < cal; ca ++ ) {

                            index = sortArray[ ca ][ 1 ];

                            value = customAttribute.value[ index ];

                            customAttribute.array[ offset ]     = value.x;
                            customAttribute.array[ offset + 1 ] = value.y;

                            offset += 2;

                        }

                    } else if ( customAttribute.size === 3 ) {

                        if ( customAttribute.type === "c" ) {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                index = sortArray[ ca ][ 1 ];

                                value = customAttribute.value[ index ];

                                customAttribute.array[ offset ]     = value.r;
                                customAttribute.array[ offset + 1 ] = value.g;
                                customAttribute.array[ offset + 2 ] = value.b;

                                offset += 3;

                            }

                        } else {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                index = sortArray[ ca ][ 1 ];

                                value = customAttribute.value[ index ];

                                customAttribute.array[ offset ]     = value.x;
                                customAttribute.array[ offset + 1 ] = value.y;
                                customAttribute.array[ offset + 2 ] = value.z;

                                offset += 3;

                            }

                        }

                    } else if ( customAttribute.size === 4 ) {

                        for ( ca = 0; ca < cal; ca ++ ) {

                            index = sortArray[ ca ][ 1 ];

                            value = customAttribute.value[ index ];

                            customAttribute.array[ offset ]      = value.x;
                            customAttribute.array[ offset + 1  ] = value.y;
                            customAttribute.array[ offset + 2  ] = value.z;
                            customAttribute.array[ offset + 3  ] = value.w;

                            offset += 4;

                        }

                    }

                }

            }

        } else {

            if ( dirtyVertices ) {

                for ( v = 0; v < vl; v ++ ) {

                    vertex = vertices[ v ];

                    offset = v * 3;

                    vertexArray[ offset ]     = vertex.x;
                    vertexArray[ offset + 1 ] = vertex.y;
                    vertexArray[ offset + 2 ] = vertex.z;

                }

            }

            if ( dirtyColors ) {

                for ( c = 0; c < cl; c ++ ) {

                    color = colors[ c ];

                    offset = c * 3;

                    colorArray[ offset ]     = color.r;
                    colorArray[ offset + 1 ] = color.g;
                    colorArray[ offset + 2 ] = color.b;

                }

            }

            if ( customAttributes ) {

                for ( i = 0, il = customAttributes.length; i < il; i ++ ) {

                    customAttribute = customAttributes[ i ];

                    if ( customAttribute.needsUpdate &&
                         ( customAttribute.boundTo === undefined ||
                           customAttribute.boundTo === "vertices") ) {

                        cal = customAttribute.value.length;

                        offset = 0;

                        if ( customAttribute.size === 1 ) {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                customAttribute.array[ ca ] = customAttribute.value[ ca ];

                            }

                        } else if ( customAttribute.size === 2 ) {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                value = customAttribute.value[ ca ];

                                customAttribute.array[ offset ]     = value.x;
                                customAttribute.array[ offset + 1 ] = value.y;

                                offset += 2;

                            }

                        } else if ( customAttribute.size === 3 ) {

                            if ( customAttribute.type === "c" ) {

                                for ( ca = 0; ca < cal; ca ++ ) {

                                    value = customAttribute.value[ ca ];

                                    customAttribute.array[ offset ]     = value.r;
                                    customAttribute.array[ offset + 1 ] = value.g;
                                    customAttribute.array[ offset + 2 ] = value.b;

                                    offset += 3;

                                }

                            } else {

                                for ( ca = 0; ca < cal; ca ++ ) {

                                    value = customAttribute.value[ ca ];

                                    customAttribute.array[ offset ]     = value.x;
                                    customAttribute.array[ offset + 1 ] = value.y;
                                    customAttribute.array[ offset + 2 ] = value.z;

                                    offset += 3;

                                }

                            }

                        } else if ( customAttribute.size === 4 ) {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                value = customAttribute.value[ ca ];

                                customAttribute.array[ offset ]      = value.x;
                                customAttribute.array[ offset + 1  ] = value.y;
                                customAttribute.array[ offset + 2  ] = value.z;
                                customAttribute.array[ offset + 3  ] = value.w;

                                offset += 4;

                            }

                        }

                    }

                }

            }

        }

        if ( dirtyVertices || object.sortParticles ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );

        }

        if ( dirtyColors || object.sortParticles ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );

        }

        if ( customAttributes ) {

            for ( i = 0, il = customAttributes.length; i < il; i ++ ) {

                customAttribute = customAttributes[ i ];

                if ( customAttribute.needsUpdate || object.sortParticles ) {

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
                    _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );

                }

            }

        }


    };

    function setLineBuffers ( geometry, hint ) {

        var v, c, vertex, offset, color,

        vertices = geometry.vertices,
        colors = geometry.colors,
        vl = vertices.length,
        cl = colors.length,

        vertexArray = geometry.__vertexArray,
        colorArray = geometry.__colorArray,

        dirtyVertices = geometry.verticesNeedUpdate,
        dirtyColors = geometry.colorsNeedUpdate,

        customAttributes = geometry.__webglCustomAttributesList,

        i, il,
        a, ca, cal, value,
        customAttribute;

        if ( dirtyVertices ) {

            for ( v = 0; v < vl; v ++ ) {

                vertex = vertices[ v ];

                offset = v * 3;

                vertexArray[ offset ]     = vertex.x;
                vertexArray[ offset + 1 ] = vertex.y;
                vertexArray[ offset + 2 ] = vertex.z;

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );

        }

        if ( dirtyColors ) {

            for ( c = 0; c < cl; c ++ ) {

                color = colors[ c ];

                offset = c * 3;

                colorArray[ offset ]     = color.r;
                colorArray[ offset + 1 ] = color.g;
                colorArray[ offset + 2 ] = color.b;

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );

        }

        if ( customAttributes ) {

            for ( i = 0, il = customAttributes.length; i < il; i ++ ) {

                customAttribute = customAttributes[ i ];

                if ( customAttribute.needsUpdate &&
                     ( customAttribute.boundTo === undefined ||
                       customAttribute.boundTo === "vertices" ) ) {

                    offset = 0;

                    cal = customAttribute.value.length;

                    if ( customAttribute.size === 1 ) {

                        for ( ca = 0; ca < cal; ca ++ ) {

                            customAttribute.array[ ca ] = customAttribute.value[ ca ];

                        }

                    } else if ( customAttribute.size === 2 ) {

                        for ( ca = 0; ca < cal; ca ++ ) {

                            value = customAttribute.value[ ca ];

                            customAttribute.array[ offset ]     = value.x;
                            customAttribute.array[ offset + 1 ] = value.y;

                            offset += 2;

                        }

                    } else if ( customAttribute.size === 3 ) {

                        if ( customAttribute.type === "c" ) {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                value = customAttribute.value[ ca ];

                                customAttribute.array[ offset ]     = value.r;
                                customAttribute.array[ offset + 1 ] = value.g;
                                customAttribute.array[ offset + 2 ] = value.b;

                                offset += 3;

                            }

                        } else {

                            for ( ca = 0; ca < cal; ca ++ ) {

                                value = customAttribute.value[ ca ];

                                customAttribute.array[ offset ]     = value.x;
                                customAttribute.array[ offset + 1 ] = value.y;
                                customAttribute.array[ offset + 2 ] = value.z;

                                offset += 3;

                            }

                        }

                    } else if ( customAttribute.size === 4 ) {

                        for ( ca = 0; ca < cal; ca ++ ) {

                            value = customAttribute.value[ ca ];

                            customAttribute.array[ offset ]      = value.x;
                            customAttribute.array[ offset + 1  ] = value.y;
                            customAttribute.array[ offset + 2  ] = value.z;
                            customAttribute.array[ offset + 3  ] = value.w;

                            offset += 4;

                        }

                    }

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
                    _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );

                }

            }

        }

    };

    function setRibbonBuffers ( geometry, hint ) {

        var v, c, vertex, offset, color,

        vertices = geometry.vertices,
        colors = geometry.colors,
        vl = vertices.length,
        cl = colors.length,

        vertexArray = geometry.__vertexArray,
        colorArray = geometry.__colorArray,

        dirtyVertices = geometry.verticesNeedUpdate,
        dirtyColors = geometry.colorsNeedUpdate;

        if ( dirtyVertices ) {

            for ( v = 0; v < vl; v ++ ) {

                vertex = vertices[ v ];

                offset = v * 3;

                vertexArray[ offset ]     = vertex.x;
                vertexArray[ offset + 1 ] = vertex.y;
                vertexArray[ offset + 2 ] = vertex.z;

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );

        }

        if ( dirtyColors ) {

            for ( c = 0; c < cl; c ++ ) {

                color = colors[ c ];

                offset = c * 3;

                colorArray[ offset ]     = color.r;
                colorArray[ offset + 1 ] = color.g;
                colorArray[ offset + 2 ] = color.b;

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );

        }

    };

    function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {

        if ( ! geometryGroup.__inittedArrays ) {

            // console.log( object );
            return;

        }

        var normalType = bufferGuessNormalType( material ),
        vertexColorType = bufferGuessVertexColorType( material ),
        uvType = bufferGuessUVType( material ),

        needsSmoothNormals = ( normalType === THREE.SmoothShading );

        var f, fl, fi, face,
        vertexNormals, faceNormal, normal,
        vertexColors, faceColor,
        vertexTangents,
        uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4,
        c1, c2, c3, c4,
        sw1, sw2, sw3, sw4,
        si1, si2, si3, si4,
        sa1, sa2, sa3, sa4,
        sb1, sb2, sb3, sb4,
        m, ml, i, il,
        vn, uvi, uv2i,
        vk, vkl, vka,
        nka, chf, faceVertexNormals,
        a,

        vertexIndex = 0,

        offset = 0,
        offset_uv = 0,
        offset_uv2 = 0,
        offset_face = 0,
        offset_normal = 0,
        offset_tangent = 0,
        offset_line = 0,
        offset_color = 0,
        offset_skin = 0,
        offset_morphTarget = 0,
        offset_custom = 0,
        offset_customSrc = 0,

        value,

        vertexArray = geometryGroup.__vertexArray,
        uvArray = geometryGroup.__uvArray,
        uv2Array = geometryGroup.__uv2Array,
        normalArray = geometryGroup.__normalArray,
        tangentArray = geometryGroup.__tangentArray,
        colorArray = geometryGroup.__colorArray,

        skinIndexArray = geometryGroup.__skinIndexArray,
        skinWeightArray = geometryGroup.__skinWeightArray,

        morphTargetsArrays = geometryGroup.__morphTargetsArrays,
        morphNormalsArrays = geometryGroup.__morphNormalsArrays,

        customAttributes = geometryGroup.__webglCustomAttributesList,
        customAttribute,

        faceArray = geometryGroup.__faceArray,
        lineArray = geometryGroup.__lineArray,

        geometry = object.geometry, // this is shared for all chunks

        dirtyVertices = geometry.verticesNeedUpdate,
        dirtyElements = geometry.elementsNeedUpdate,
        dirtyUvs = geometry.uvsNeedUpdate,
        dirtyNormals = geometry.normalsNeedUpdate,
        dirtyTangents = geometry.tangentsNeedUpdate,
        dirtyColors = geometry.colorsNeedUpdate,
        dirtyMorphTargets = geometry.morphTargetsNeedUpdate,

        vertices = geometry.vertices,
        chunk_faces3 = geometryGroup.faces3,
        chunk_faces4 = geometryGroup.faces4,
        obj_faces = geometry.faces,

        obj_uvs  = geometry.faceVertexUvs[ 0 ],
        obj_uvs2 = geometry.faceVertexUvs[ 1 ],

        obj_colors = geometry.colors,

        obj_skinIndices = geometry.skinIndices,
        obj_skinWeights = geometry.skinWeights,

        morphTargets = geometry.morphTargets,
        morphNormals = geometry.morphNormals;

        if ( dirtyVertices ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces3[ f ] ];

                v1 = vertices[ face.a ];
                v2 = vertices[ face.b ];
                v3 = vertices[ face.c ];

                vertexArray[ offset ]     = v1.x;
                vertexArray[ offset + 1 ] = v1.y;
                vertexArray[ offset + 2 ] = v1.z;

                vertexArray[ offset + 3 ] = v2.x;
                vertexArray[ offset + 4 ] = v2.y;
                vertexArray[ offset + 5 ] = v2.z;

                vertexArray[ offset + 6 ] = v3.x;
                vertexArray[ offset + 7 ] = v3.y;
                vertexArray[ offset + 8 ] = v3.z;

                offset += 9;

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces4[ f ] ];

                v1 = vertices[ face.a ];
                v2 = vertices[ face.b ];
                v3 = vertices[ face.c ];
                v4 = vertices[ face.d ];

                vertexArray[ offset ]     = v1.x;
                vertexArray[ offset + 1 ] = v1.y;
                vertexArray[ offset + 2 ] = v1.z;

                vertexArray[ offset + 3 ] = v2.x;
                vertexArray[ offset + 4 ] = v2.y;
                vertexArray[ offset + 5 ] = v2.z;

                vertexArray[ offset + 6 ] = v3.x;
                vertexArray[ offset + 7 ] = v3.y;
                vertexArray[ offset + 8 ] = v3.z;

                vertexArray[ offset + 9 ]  = v4.x;
                vertexArray[ offset + 10 ] = v4.y;
                vertexArray[ offset + 11 ] = v4.z;

                offset += 12;

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );

        }

        if ( dirtyMorphTargets ) {

            for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {

                offset_morphTarget = 0;

                for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                    chf = chunk_faces3[ f ];
                    face = obj_faces[ chf ];

                    // morph positions

                    v1 = morphTargets[ vk ].vertices[ face.a ];
                    v2 = morphTargets[ vk ].vertices[ face.b ];
                    v3 = morphTargets[ vk ].vertices[ face.c ];

                    vka = morphTargetsArrays[ vk ];

                    vka[ offset_morphTarget ]       = v1.x;
                    vka[ offset_morphTarget + 1 ] = v1.y;
                    vka[ offset_morphTarget + 2 ] = v1.z;

                    vka[ offset_morphTarget + 3 ] = v2.x;
                    vka[ offset_morphTarget + 4 ] = v2.y;
                    vka[ offset_morphTarget + 5 ] = v2.z;

                    vka[ offset_morphTarget + 6 ] = v3.x;
                    vka[ offset_morphTarget + 7 ] = v3.y;
                    vka[ offset_morphTarget + 8 ] = v3.z;

                    // morph normals

                    if ( material.morphNormals ) {

                        if ( needsSmoothNormals ) {

                            faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];

                            n1 = faceVertexNormals.a;
                            n2 = faceVertexNormals.b;
                            n3 = faceVertexNormals.c;

                        } else {

                            n1 = morphNormals[ vk ].faceNormals[ chf ];
                            n2 = n1;
                            n3 = n1;

                        }

                        nka = morphNormalsArrays[ vk ];

                        nka[ offset_morphTarget ]       = n1.x;
                        nka[ offset_morphTarget + 1 ] = n1.y;
                        nka[ offset_morphTarget + 2 ] = n1.z;

                        nka[ offset_morphTarget + 3 ] = n2.x;
                        nka[ offset_morphTarget + 4 ] = n2.y;
                        nka[ offset_morphTarget + 5 ] = n2.z;

                        nka[ offset_morphTarget + 6 ] = n3.x;
                        nka[ offset_morphTarget + 7 ] = n3.y;
                        nka[ offset_morphTarget + 8 ] = n3.z;

                    }

                    //

                    offset_morphTarget += 9;

                }

                for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                    chf = chunk_faces4[ f ];
                    face = obj_faces[ chf ];

                    // morph positions

                    v1 = morphTargets[ vk ].vertices[ face.a ];
                    v2 = morphTargets[ vk ].vertices[ face.b ];
                    v3 = morphTargets[ vk ].vertices[ face.c ];
                    v4 = morphTargets[ vk ].vertices[ face.d ];

                    vka = morphTargetsArrays[ vk ];

                    vka[ offset_morphTarget ]       = v1.x;
                    vka[ offset_morphTarget + 1 ] = v1.y;
                    vka[ offset_morphTarget + 2 ] = v1.z;

                    vka[ offset_morphTarget + 3 ] = v2.x;
                    vka[ offset_morphTarget + 4 ] = v2.y;
                    vka[ offset_morphTarget + 5 ] = v2.z;

                    vka[ offset_morphTarget + 6 ] = v3.x;
                    vka[ offset_morphTarget + 7 ] = v3.y;
                    vka[ offset_morphTarget + 8 ] = v3.z;

                    vka[ offset_morphTarget + 9 ]  = v4.x;
                    vka[ offset_morphTarget + 10 ] = v4.y;
                    vka[ offset_morphTarget + 11 ] = v4.z;

                    // morph normals

                    if ( material.morphNormals ) {

                        if ( needsSmoothNormals ) {

                            faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];

                            n1 = faceVertexNormals.a;
                            n2 = faceVertexNormals.b;
                            n3 = faceVertexNormals.c;
                            n4 = faceVertexNormals.d;

                        } else {

                            n1 = morphNormals[ vk ].faceNormals[ chf ];
                            n2 = n1;
                            n3 = n1;
                            n4 = n1;

                        }

                        nka = morphNormalsArrays[ vk ];

                        nka[ offset_morphTarget ]       = n1.x;
                        nka[ offset_morphTarget + 1 ] = n1.y;
                        nka[ offset_morphTarget + 2 ] = n1.z;

                        nka[ offset_morphTarget + 3 ] = n2.x;
                        nka[ offset_morphTarget + 4 ] = n2.y;
                        nka[ offset_morphTarget + 5 ] = n2.z;

                        nka[ offset_morphTarget + 6 ] = n3.x;
                        nka[ offset_morphTarget + 7 ] = n3.y;
                        nka[ offset_morphTarget + 8 ] = n3.z;

                        nka[ offset_morphTarget + 9 ]  = n4.x;
                        nka[ offset_morphTarget + 10 ] = n4.y;
                        nka[ offset_morphTarget + 11 ] = n4.z;

                    }

                    //

                    offset_morphTarget += 12;

                }

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
                _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );

                if ( material.morphNormals ) {

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );
                    _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );

                }

            }

        }

        if ( obj_skinWeights.length ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces3[ f ]    ];

                // weights

                sw1 = obj_skinWeights[ face.a ];
                sw2 = obj_skinWeights[ face.b ];
                sw3 = obj_skinWeights[ face.c ];

                skinWeightArray[ offset_skin ]     = sw1.x;
                skinWeightArray[ offset_skin + 1 ] = sw1.y;
                skinWeightArray[ offset_skin + 2 ] = sw1.z;
                skinWeightArray[ offset_skin + 3 ] = sw1.w;

                skinWeightArray[ offset_skin + 4 ] = sw2.x;
                skinWeightArray[ offset_skin + 5 ] = sw2.y;
                skinWeightArray[ offset_skin + 6 ] = sw2.z;
                skinWeightArray[ offset_skin + 7 ] = sw2.w;

                skinWeightArray[ offset_skin + 8 ]  = sw3.x;
                skinWeightArray[ offset_skin + 9 ]  = sw3.y;
                skinWeightArray[ offset_skin + 10 ] = sw3.z;
                skinWeightArray[ offset_skin + 11 ] = sw3.w;

                // indices

                si1 = obj_skinIndices[ face.a ];
                si2 = obj_skinIndices[ face.b ];
                si3 = obj_skinIndices[ face.c ];

                skinIndexArray[ offset_skin ]     = si1.x;
                skinIndexArray[ offset_skin + 1 ] = si1.y;
                skinIndexArray[ offset_skin + 2 ] = si1.z;
                skinIndexArray[ offset_skin + 3 ] = si1.w;

                skinIndexArray[ offset_skin + 4 ] = si2.x;
                skinIndexArray[ offset_skin + 5 ] = si2.y;
                skinIndexArray[ offset_skin + 6 ] = si2.z;
                skinIndexArray[ offset_skin + 7 ] = si2.w;

                skinIndexArray[ offset_skin + 8 ]  = si3.x;
                skinIndexArray[ offset_skin + 9 ]  = si3.y;
                skinIndexArray[ offset_skin + 10 ] = si3.z;
                skinIndexArray[ offset_skin + 11 ] = si3.w;

                offset_skin += 12;

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces4[ f ] ];

                // weights

                sw1 = obj_skinWeights[ face.a ];
                sw2 = obj_skinWeights[ face.b ];
                sw3 = obj_skinWeights[ face.c ];
                sw4 = obj_skinWeights[ face.d ];

                skinWeightArray[ offset_skin ]     = sw1.x;
                skinWeightArray[ offset_skin + 1 ] = sw1.y;
                skinWeightArray[ offset_skin + 2 ] = sw1.z;
                skinWeightArray[ offset_skin + 3 ] = sw1.w;

                skinWeightArray[ offset_skin + 4 ] = sw2.x;
                skinWeightArray[ offset_skin + 5 ] = sw2.y;
                skinWeightArray[ offset_skin + 6 ] = sw2.z;
                skinWeightArray[ offset_skin + 7 ] = sw2.w;

                skinWeightArray[ offset_skin + 8 ]  = sw3.x;
                skinWeightArray[ offset_skin + 9 ]  = sw3.y;
                skinWeightArray[ offset_skin + 10 ] = sw3.z;
                skinWeightArray[ offset_skin + 11 ] = sw3.w;

                skinWeightArray[ offset_skin + 12 ] = sw4.x;
                skinWeightArray[ offset_skin + 13 ] = sw4.y;
                skinWeightArray[ offset_skin + 14 ] = sw4.z;
                skinWeightArray[ offset_skin + 15 ] = sw4.w;

                // indices

                si1 = obj_skinIndices[ face.a ];
                si2 = obj_skinIndices[ face.b ];
                si3 = obj_skinIndices[ face.c ];
                si4 = obj_skinIndices[ face.d ];

                skinIndexArray[ offset_skin ]     = si1.x;
                skinIndexArray[ offset_skin + 1 ] = si1.y;
                skinIndexArray[ offset_skin + 2 ] = si1.z;
                skinIndexArray[ offset_skin + 3 ] = si1.w;

                skinIndexArray[ offset_skin + 4 ] = si2.x;
                skinIndexArray[ offset_skin + 5 ] = si2.y;
                skinIndexArray[ offset_skin + 6 ] = si2.z;
                skinIndexArray[ offset_skin + 7 ] = si2.w;

                skinIndexArray[ offset_skin + 8 ]  = si3.x;
                skinIndexArray[ offset_skin + 9 ]  = si3.y;
                skinIndexArray[ offset_skin + 10 ] = si3.z;
                skinIndexArray[ offset_skin + 11 ] = si3.w;

                skinIndexArray[ offset_skin + 12 ] = si4.x;
                skinIndexArray[ offset_skin + 13 ] = si4.y;
                skinIndexArray[ offset_skin + 14 ] = si4.z;
                skinIndexArray[ offset_skin + 15 ] = si4.w;

                offset_skin += 16;

            }

            if ( offset_skin > 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
                _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
                _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );

            }

        }

        if ( dirtyColors && vertexColorType ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces3[ f ]    ];

                vertexColors = face.vertexColors;
                faceColor = face.color;

                if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) {

                    c1 = vertexColors[ 0 ];
                    c2 = vertexColors[ 1 ];
                    c3 = vertexColors[ 2 ];

                } else {

                    c1 = faceColor;
                    c2 = faceColor;
                    c3 = faceColor;

                }

                colorArray[ offset_color ]     = c1.r;
                colorArray[ offset_color + 1 ] = c1.g;
                colorArray[ offset_color + 2 ] = c1.b;

                colorArray[ offset_color + 3 ] = c2.r;
                colorArray[ offset_color + 4 ] = c2.g;
                colorArray[ offset_color + 5 ] = c2.b;

                colorArray[ offset_color + 6 ] = c3.r;
                colorArray[ offset_color + 7 ] = c3.g;
                colorArray[ offset_color + 8 ] = c3.b;

                offset_color += 9;

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces4[ f ] ];

                vertexColors = face.vertexColors;
                faceColor = face.color;

                if ( vertexColors.length === 4 && vertexColorType === THREE.VertexColors ) {

                    c1 = vertexColors[ 0 ];
                    c2 = vertexColors[ 1 ];
                    c3 = vertexColors[ 2 ];
                    c4 = vertexColors[ 3 ];

                } else {

                    c1 = faceColor;
                    c2 = faceColor;
                    c3 = faceColor;
                    c4 = faceColor;

                }

                colorArray[ offset_color ]     = c1.r;
                colorArray[ offset_color + 1 ] = c1.g;
                colorArray[ offset_color + 2 ] = c1.b;

                colorArray[ offset_color + 3 ] = c2.r;
                colorArray[ offset_color + 4 ] = c2.g;
                colorArray[ offset_color + 5 ] = c2.b;

                colorArray[ offset_color + 6 ] = c3.r;
                colorArray[ offset_color + 7 ] = c3.g;
                colorArray[ offset_color + 8 ] = c3.b;

                colorArray[ offset_color + 9 ]  = c4.r;
                colorArray[ offset_color + 10 ] = c4.g;
                colorArray[ offset_color + 11 ] = c4.b;

                offset_color += 12;

            }

            if ( offset_color > 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
                _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );

            }

        }

        if ( dirtyTangents && geometry.hasTangents ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces3[ f ]    ];

                vertexTangents = face.vertexTangents;

                t1 = vertexTangents[ 0 ];
                t2 = vertexTangents[ 1 ];
                t3 = vertexTangents[ 2 ];

                tangentArray[ offset_tangent ]     = t1.x;
                tangentArray[ offset_tangent + 1 ] = t1.y;
                tangentArray[ offset_tangent + 2 ] = t1.z;
                tangentArray[ offset_tangent + 3 ] = t1.w;

                tangentArray[ offset_tangent + 4 ] = t2.x;
                tangentArray[ offset_tangent + 5 ] = t2.y;
                tangentArray[ offset_tangent + 6 ] = t2.z;
                tangentArray[ offset_tangent + 7 ] = t2.w;

                tangentArray[ offset_tangent + 8 ]  = t3.x;
                tangentArray[ offset_tangent + 9 ]  = t3.y;
                tangentArray[ offset_tangent + 10 ] = t3.z;
                tangentArray[ offset_tangent + 11 ] = t3.w;

                offset_tangent += 12;

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces4[ f ] ];

                vertexTangents = face.vertexTangents;

                t1 = vertexTangents[ 0 ];
                t2 = vertexTangents[ 1 ];
                t3 = vertexTangents[ 2 ];
                t4 = vertexTangents[ 3 ];

                tangentArray[ offset_tangent ]     = t1.x;
                tangentArray[ offset_tangent + 1 ] = t1.y;
                tangentArray[ offset_tangent + 2 ] = t1.z;
                tangentArray[ offset_tangent + 3 ] = t1.w;

                tangentArray[ offset_tangent + 4 ] = t2.x;
                tangentArray[ offset_tangent + 5 ] = t2.y;
                tangentArray[ offset_tangent + 6 ] = t2.z;
                tangentArray[ offset_tangent + 7 ] = t2.w;

                tangentArray[ offset_tangent + 8 ]  = t3.x;
                tangentArray[ offset_tangent + 9 ]  = t3.y;
                tangentArray[ offset_tangent + 10 ] = t3.z;
                tangentArray[ offset_tangent + 11 ] = t3.w;

                tangentArray[ offset_tangent + 12 ] = t4.x;
                tangentArray[ offset_tangent + 13 ] = t4.y;
                tangentArray[ offset_tangent + 14 ] = t4.z;
                tangentArray[ offset_tangent + 15 ] = t4.w;

                offset_tangent += 16;

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );

        }

        if ( dirtyNormals && normalType ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces3[ f ]    ];

                vertexNormals = face.vertexNormals;
                faceNormal = face.normal;

                if ( vertexNormals.length === 3 && needsSmoothNormals ) {

                    for ( i = 0; i < 3; i ++ ) {

                        vn = vertexNormals[ i ];

                        normalArray[ offset_normal ]     = vn.x;
                        normalArray[ offset_normal + 1 ] = vn.y;
                        normalArray[ offset_normal + 2 ] = vn.z;

                        offset_normal += 3;

                    }

                } else {

                    for ( i = 0; i < 3; i ++ ) {

                        normalArray[ offset_normal ]     = faceNormal.x;
                        normalArray[ offset_normal + 1 ] = faceNormal.y;
                        normalArray[ offset_normal + 2 ] = faceNormal.z;

                        offset_normal += 3;

                    }

                }

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces4[ f ] ];

                vertexNormals = face.vertexNormals;
                faceNormal = face.normal;

                if ( vertexNormals.length === 4 && needsSmoothNormals ) {

                    for ( i = 0; i < 4; i ++ ) {

                        vn = vertexNormals[ i ];

                        normalArray[ offset_normal ]     = vn.x;
                        normalArray[ offset_normal + 1 ] = vn.y;
                        normalArray[ offset_normal + 2 ] = vn.z;

                        offset_normal += 3;

                    }

                } else {

                    for ( i = 0; i < 4; i ++ ) {

                        normalArray[ offset_normal ]     = faceNormal.x;
                        normalArray[ offset_normal + 1 ] = faceNormal.y;
                        normalArray[ offset_normal + 2 ] = faceNormal.z;

                        offset_normal += 3;

                    }

                }

            }

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );

        }

        if ( dirtyUvs && obj_uvs && uvType ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                fi = chunk_faces3[ f ];

                face = obj_faces[ fi ];
                uv = obj_uvs[ fi ];

                if ( uv === undefined ) continue;

                for ( i = 0; i < 3; i ++ ) {

                    uvi = uv[ i ];

                    uvArray[ offset_uv ]     = uvi.u;
                    uvArray[ offset_uv + 1 ] = uvi.v;

                    offset_uv += 2;

                }

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                fi = chunk_faces4[ f ];

                face = obj_faces[ fi ];
                uv = obj_uvs[ fi ];

                if ( uv === undefined ) continue;

                for ( i = 0; i < 4; i ++ ) {

                    uvi = uv[ i ];

                    uvArray[ offset_uv ]     = uvi.u;
                    uvArray[ offset_uv + 1 ] = uvi.v;

                    offset_uv += 2;

                }

            }

            if ( offset_uv > 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
                _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );

            }

        }

        if ( dirtyUvs && obj_uvs2 && uvType ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                fi = chunk_faces3[ f ];

                face = obj_faces[ fi ];
                uv2 = obj_uvs2[ fi ];

                if ( uv2 === undefined ) continue;

                for ( i = 0; i < 3; i ++ ) {

                    uv2i = uv2[ i ];

                    uv2Array[ offset_uv2 ]     = uv2i.u;
                    uv2Array[ offset_uv2 + 1 ] = uv2i.v;

                    offset_uv2 += 2;

                }

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                fi = chunk_faces4[ f ];

                face = obj_faces[ fi ];
                uv2 = obj_uvs2[ fi ];

                if ( uv2 === undefined ) continue;

                for ( i = 0; i < 4; i ++ ) {

                    uv2i = uv2[ i ];

                    uv2Array[ offset_uv2 ]     = uv2i.u;
                    uv2Array[ offset_uv2 + 1 ] = uv2i.v;

                    offset_uv2 += 2;

                }

            }

            if ( offset_uv2 > 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
                _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );

            }

        }

        if ( dirtyElements ) {

            for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces3[ f ]    ];

                faceArray[ offset_face ]      = vertexIndex;
                faceArray[ offset_face + 1 ] = vertexIndex + 1;
                faceArray[ offset_face + 2 ] = vertexIndex + 2;

                offset_face += 3;

                lineArray[ offset_line ]     = vertexIndex;
                lineArray[ offset_line + 1 ] = vertexIndex + 1;

                lineArray[ offset_line + 2 ] = vertexIndex;
                lineArray[ offset_line + 3 ] = vertexIndex + 2;

                lineArray[ offset_line + 4 ] = vertexIndex + 1;
                lineArray[ offset_line + 5 ] = vertexIndex + 2;

                offset_line += 6;

                vertexIndex += 3;

            }

            for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                face = obj_faces[ chunk_faces4[ f ] ];

                faceArray[ offset_face ]     = vertexIndex;
                faceArray[ offset_face + 1 ] = vertexIndex + 1;
                faceArray[ offset_face + 2 ] = vertexIndex + 3;

                faceArray[ offset_face + 3 ] = vertexIndex + 1;
                faceArray[ offset_face + 4 ] = vertexIndex + 2;
                faceArray[ offset_face + 5 ] = vertexIndex + 3;

                offset_face += 6;

                lineArray[ offset_line ]     = vertexIndex;
                lineArray[ offset_line + 1 ] = vertexIndex + 1;

                lineArray[ offset_line + 2 ] = vertexIndex;
                lineArray[ offset_line + 3 ] = vertexIndex + 3;

                lineArray[ offset_line + 4 ] = vertexIndex + 1;
                lineArray[ offset_line + 5 ] = vertexIndex + 2;

                lineArray[ offset_line + 6 ] = vertexIndex + 2;
                lineArray[ offset_line + 7 ] = vertexIndex + 3;

                offset_line += 8;

                vertexIndex += 4;

            }

            _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
            _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );

            _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
            _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );

        }

        if ( customAttributes ) {

            for ( i = 0, il = customAttributes.length; i < il; i ++ ) {

                customAttribute = customAttributes[ i ];

                if ( ! customAttribute.__original.needsUpdate ) continue;

                offset_custom = 0;
                offset_customSrc = 0;

                if ( customAttribute.size === 1 ) {

                    if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces3[ f ]    ];

                            customAttribute.array[ offset_custom ]        = customAttribute.value[ face.a ];
                            customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
                            customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];

                            offset_custom += 3;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces4[ f ] ];

                            customAttribute.array[ offset_custom ]        = customAttribute.value[ face.a ];
                            customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
                            customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
                            customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ];

                            offset_custom += 4;

                        }

                    } else if ( customAttribute.boundTo === "faces" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces3[ f ] ];

                            customAttribute.array[ offset_custom ]        = value;
                            customAttribute.array[ offset_custom + 1 ] = value;
                            customAttribute.array[ offset_custom + 2 ] = value;

                            offset_custom += 3;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces4[ f ] ];

                            customAttribute.array[ offset_custom ]        = value;
                            customAttribute.array[ offset_custom + 1 ] = value;
                            customAttribute.array[ offset_custom + 2 ] = value;
                            customAttribute.array[ offset_custom + 3 ] = value;

                            offset_custom += 4;

                        }

                    }

                } else if ( customAttribute.size === 2 ) {

                    if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces3[ f ]    ];

                            v1 = customAttribute.value[ face.a ];
                            v2 = customAttribute.value[ face.b ];
                            v3 = customAttribute.value[ face.c ];

                            customAttribute.array[ offset_custom ]        = v1.x;
                            customAttribute.array[ offset_custom + 1 ] = v1.y;

                            customAttribute.array[ offset_custom + 2 ] = v2.x;
                            customAttribute.array[ offset_custom + 3 ] = v2.y;

                            customAttribute.array[ offset_custom + 4 ] = v3.x;
                            customAttribute.array[ offset_custom + 5 ] = v3.y;

                            offset_custom += 6;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces4[ f ] ];

                            v1 = customAttribute.value[ face.a ];
                            v2 = customAttribute.value[ face.b ];
                            v3 = customAttribute.value[ face.c ];
                            v4 = customAttribute.value[ face.d ];

                            customAttribute.array[ offset_custom ]        = v1.x;
                            customAttribute.array[ offset_custom + 1 ] = v1.y;

                            customAttribute.array[ offset_custom + 2 ] = v2.x;
                            customAttribute.array[ offset_custom + 3 ] = v2.y;

                            customAttribute.array[ offset_custom + 4 ] = v3.x;
                            customAttribute.array[ offset_custom + 5 ] = v3.y;

                            customAttribute.array[ offset_custom + 6 ] = v4.x;
                            customAttribute.array[ offset_custom + 7 ] = v4.y;

                            offset_custom += 8;

                        }

                    } else if ( customAttribute.boundTo === "faces" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces3[ f ] ];

                            v1 = value;
                            v2 = value;
                            v3 = value;

                            customAttribute.array[ offset_custom ]        = v1.x;
                            customAttribute.array[ offset_custom + 1 ] = v1.y;

                            customAttribute.array[ offset_custom + 2 ] = v2.x;
                            customAttribute.array[ offset_custom + 3 ] = v2.y;

                            customAttribute.array[ offset_custom + 4 ] = v3.x;
                            customAttribute.array[ offset_custom + 5 ] = v3.y;

                            offset_custom += 6;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces4[ f ] ];

                            v1 = value;
                            v2 = value;
                            v3 = value;
                            v4 = value;

                            customAttribute.array[ offset_custom ]        = v1.x;
                            customAttribute.array[ offset_custom + 1 ] = v1.y;

                            customAttribute.array[ offset_custom + 2 ] = v2.x;
                            customAttribute.array[ offset_custom + 3 ] = v2.y;

                            customAttribute.array[ offset_custom + 4 ] = v3.x;
                            customAttribute.array[ offset_custom + 5 ] = v3.y;

                            customAttribute.array[ offset_custom + 6 ] = v4.x;
                            customAttribute.array[ offset_custom + 7 ] = v4.y;

                            offset_custom += 8;

                        }

                    }

                } else if ( customAttribute.size === 3 ) {

                    var pp;

                    if ( customAttribute.type === "c" ) {

                        pp = [ "r", "g", "b" ];

                    } else {

                        pp = [ "x", "y", "z" ];

                    }

                    if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces3[ f ]    ];

                            v1 = customAttribute.value[ face.a ];
                            v2 = customAttribute.value[ face.b ];
                            v3 = customAttribute.value[ face.c ];

                            customAttribute.array[ offset_custom ]        = v1[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];

                            offset_custom += 9;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces4[ f ] ];

                            v1 = customAttribute.value[ face.a ];
                            v2 = customAttribute.value[ face.b ];
                            v3 = customAttribute.value[ face.c ];
                            v4 = customAttribute.value[ face.d ];

                            customAttribute.array[ offset_custom  ]     = v1[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];

                            offset_custom += 12;

                        }

                    } else if ( customAttribute.boundTo === "faces" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces3[ f ] ];

                            v1 = value;
                            v2 = value;
                            v3 = value;

                            customAttribute.array[ offset_custom ]        = v1[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];

                            offset_custom += 9;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces4[ f ] ];

                            v1 = value;
                            v2 = value;
                            v3 = value;
                            v4 = value;

                            customAttribute.array[ offset_custom  ]     = v1[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];

                            offset_custom += 12;

                        }

                    } else if ( customAttribute.boundTo === "faceVertices" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces3[ f ] ];

                            v1 = value[ 0 ];
                            v2 = value[ 1 ];
                            v3 = value[ 2 ];

                            customAttribute.array[ offset_custom ]        = v1[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];

                            offset_custom += 9;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces4[ f ] ];

                            v1 = value[ 0 ];
                            v2 = value[ 1 ];
                            v3 = value[ 2 ];
                            v4 = value[ 3 ];

                            customAttribute.array[ offset_custom  ]     = v1[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 1  ] = v1[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 2  ] = v1[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 3  ] = v2[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 4  ] = v2[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 5  ] = v2[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 6  ] = v3[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 7  ] = v3[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 8  ] = v3[ pp[ 2 ] ];

                            customAttribute.array[ offset_custom + 9  ] = v4[ pp[ 0 ] ];
                            customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
                            customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];

                            offset_custom += 12;

                        }

                    }

                } else if ( customAttribute.size === 4 ) {

                    if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces3[ f ]    ];

                            v1 = customAttribute.value[ face.a ];
                            v2 = customAttribute.value[ face.b ];
                            v3 = customAttribute.value[ face.c ];

                            customAttribute.array[ offset_custom  ]     = v1.x;
                            customAttribute.array[ offset_custom + 1  ] = v1.y;
                            customAttribute.array[ offset_custom + 2  ] = v1.z;
                            customAttribute.array[ offset_custom + 3  ] = v1.w;

                            customAttribute.array[ offset_custom + 4  ] = v2.x;
                            customAttribute.array[ offset_custom + 5  ] = v2.y;
                            customAttribute.array[ offset_custom + 6  ] = v2.z;
                            customAttribute.array[ offset_custom + 7  ] = v2.w;

                            customAttribute.array[ offset_custom + 8  ] = v3.x;
                            customAttribute.array[ offset_custom + 9  ] = v3.y;
                            customAttribute.array[ offset_custom + 10 ] = v3.z;
                            customAttribute.array[ offset_custom + 11 ] = v3.w;

                            offset_custom += 12;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            face = obj_faces[ chunk_faces4[ f ] ];

                            v1 = customAttribute.value[ face.a ];
                            v2 = customAttribute.value[ face.b ];
                            v3 = customAttribute.value[ face.c ];
                            v4 = customAttribute.value[ face.d ];

                            customAttribute.array[ offset_custom  ]     = v1.x;
                            customAttribute.array[ offset_custom + 1  ] = v1.y;
                            customAttribute.array[ offset_custom + 2  ] = v1.z;
                            customAttribute.array[ offset_custom + 3  ] = v1.w;

                            customAttribute.array[ offset_custom + 4  ] = v2.x;
                            customAttribute.array[ offset_custom + 5  ] = v2.y;
                            customAttribute.array[ offset_custom + 6  ] = v2.z;
                            customAttribute.array[ offset_custom + 7  ] = v2.w;

                            customAttribute.array[ offset_custom + 8  ] = v3.x;
                            customAttribute.array[ offset_custom + 9  ] = v3.y;
                            customAttribute.array[ offset_custom + 10 ] = v3.z;
                            customAttribute.array[ offset_custom + 11 ] = v3.w;

                            customAttribute.array[ offset_custom + 12 ] = v4.x;
                            customAttribute.array[ offset_custom + 13 ] = v4.y;
                            customAttribute.array[ offset_custom + 14 ] = v4.z;
                            customAttribute.array[ offset_custom + 15 ] = v4.w;

                            offset_custom += 16;

                        }

                    } else if ( customAttribute.boundTo === "faces" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces3[ f ] ];

                            v1 = value;
                            v2 = value;
                            v3 = value;

                            customAttribute.array[ offset_custom  ]     = v1.x;
                            customAttribute.array[ offset_custom + 1  ] = v1.y;
                            customAttribute.array[ offset_custom + 2  ] = v1.z;
                            customAttribute.array[ offset_custom + 3  ] = v1.w;

                            customAttribute.array[ offset_custom + 4  ] = v2.x;
                            customAttribute.array[ offset_custom + 5  ] = v2.y;
                            customAttribute.array[ offset_custom + 6  ] = v2.z;
                            customAttribute.array[ offset_custom + 7  ] = v2.w;

                            customAttribute.array[ offset_custom + 8  ] = v3.x;
                            customAttribute.array[ offset_custom + 9  ] = v3.y;
                            customAttribute.array[ offset_custom + 10 ] = v3.z;
                            customAttribute.array[ offset_custom + 11 ] = v3.w;

                            offset_custom += 12;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces4[ f ] ];

                            v1 = value;
                            v2 = value;
                            v3 = value;
                            v4 = value;

                            customAttribute.array[ offset_custom  ]     = v1.x;
                            customAttribute.array[ offset_custom + 1  ] = v1.y;
                            customAttribute.array[ offset_custom + 2  ] = v1.z;
                            customAttribute.array[ offset_custom + 3  ] = v1.w;

                            customAttribute.array[ offset_custom + 4  ] = v2.x;
                            customAttribute.array[ offset_custom + 5  ] = v2.y;
                            customAttribute.array[ offset_custom + 6  ] = v2.z;
                            customAttribute.array[ offset_custom + 7  ] = v2.w;

                            customAttribute.array[ offset_custom + 8  ] = v3.x;
                            customAttribute.array[ offset_custom + 9  ] = v3.y;
                            customAttribute.array[ offset_custom + 10 ] = v3.z;
                            customAttribute.array[ offset_custom + 11 ] = v3.w;

                            customAttribute.array[ offset_custom + 12 ] = v4.x;
                            customAttribute.array[ offset_custom + 13 ] = v4.y;
                            customAttribute.array[ offset_custom + 14 ] = v4.z;
                            customAttribute.array[ offset_custom + 15 ] = v4.w;

                            offset_custom += 16;

                        }

                    } else if ( customAttribute.boundTo === "faceVertices" ) {

                        for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces3[ f ] ];

                            v1 = value[ 0 ];
                            v2 = value[ 1 ];
                            v3 = value[ 2 ];

                            customAttribute.array[ offset_custom  ]     = v1.x;
                            customAttribute.array[ offset_custom + 1  ] = v1.y;
                            customAttribute.array[ offset_custom + 2  ] = v1.z;
                            customAttribute.array[ offset_custom + 3  ] = v1.w;

                            customAttribute.array[ offset_custom + 4  ] = v2.x;
                            customAttribute.array[ offset_custom + 5  ] = v2.y;
                            customAttribute.array[ offset_custom + 6  ] = v2.z;
                            customAttribute.array[ offset_custom + 7  ] = v2.w;

                            customAttribute.array[ offset_custom + 8  ] = v3.x;
                            customAttribute.array[ offset_custom + 9  ] = v3.y;
                            customAttribute.array[ offset_custom + 10 ] = v3.z;
                            customAttribute.array[ offset_custom + 11 ] = v3.w;

                            offset_custom += 12;

                        }

                        for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {

                            value = customAttribute.value[ chunk_faces4[ f ] ];

                            v1 = value[ 0 ];
                            v2 = value[ 1 ];
                            v3 = value[ 2 ];
                            v4 = value[ 3 ];

                            customAttribute.array[ offset_custom  ]     = v1.x;
                            customAttribute.array[ offset_custom + 1  ] = v1.y;
                            customAttribute.array[ offset_custom + 2  ] = v1.z;
                            customAttribute.array[ offset_custom + 3  ] = v1.w;

                            customAttribute.array[ offset_custom + 4  ] = v2.x;
                            customAttribute.array[ offset_custom + 5  ] = v2.y;
                            customAttribute.array[ offset_custom + 6  ] = v2.z;
                            customAttribute.array[ offset_custom + 7  ] = v2.w;

                            customAttribute.array[ offset_custom + 8  ] = v3.x;
                            customAttribute.array[ offset_custom + 9  ] = v3.y;
                            customAttribute.array[ offset_custom + 10 ] = v3.z;
                            customAttribute.array[ offset_custom + 11 ] = v3.w;

                            customAttribute.array[ offset_custom + 12 ] = v4.x;
                            customAttribute.array[ offset_custom + 13 ] = v4.y;
                            customAttribute.array[ offset_custom + 14 ] = v4.z;
                            customAttribute.array[ offset_custom + 15 ] = v4.w;

                            offset_custom += 16;

                        }

                    }

                }

                _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
                _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );

            }

        }

        if ( dispose ) {

            delete geometryGroup.__inittedArrays;
            delete geometryGroup.__colorArray;
            delete geometryGroup.__normalArray;
            delete geometryGroup.__tangentArray;
            delete geometryGroup.__uvArray;
            delete geometryGroup.__uv2Array;
            delete geometryGroup.__faceArray;
            delete geometryGroup.__vertexArray;
            delete geometryGroup.__lineArray;
            delete geometryGroup.__skinIndexArray;
            delete geometryGroup.__skinWeightArray;

        }

    };

    function setDirectBuffers ( geometry, hint, dispose ) {

        var attributes = geometry.attributes;

        var index = attributes[ "index" ];
        var position = attributes[ "position" ];
        var normal = attributes[ "normal" ];
        var uv = attributes[ "uv" ];
        var color = attributes[ "color" ];
        var tangent = attributes[ "tangent" ];

        if ( geometry.elementsNeedUpdate && index !== undefined ) {

            _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
            _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, index.array, hint );

        }

        if ( geometry.verticesNeedUpdate && position !== undefined ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, position.array, hint );

        }

        if ( geometry.normalsNeedUpdate && normal !== undefined ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, normal.buffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, normal.array, hint );

        }

        if ( geometry.uvsNeedUpdate && uv !== undefined ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, uv.buffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, uv.array, hint );

        }

        if ( geometry.colorsNeedUpdate && color !== undefined ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, color.array, hint );

        }

        if ( geometry.tangentsNeedUpdate && tangent !== undefined ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, tangent.buffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, tangent.array, hint );

        }

        if ( dispose ) {

            for ( var i in geometry.attributes ) {

                delete geometry.attributes[ i ].array;

            }

        }

    };

    // Buffer rendering

    this.renderBufferImmediate = function ( object, program, material ) {

        if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
        if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
        if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
        if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();

        if ( object.hasPositions ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
            _gl.enableVertexAttribArray( program.attributes.position );
            _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.hasNormals ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );

            if ( material.shading === THREE.FlatShading ) {

                var nx, ny, nz,
                    nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
                    normalArray,
                    i, il = object.count * 3;

                for( i = 0; i < il; i += 9 ) {

                    normalArray = object.normalArray;

                    nax  = normalArray[ i ];
                    nay  = normalArray[ i + 1 ];
                    naz  = normalArray[ i + 2 ];

                    nbx  = normalArray[ i + 3 ];
                    nby  = normalArray[ i + 4 ];
                    nbz  = normalArray[ i + 5 ];

                    ncx  = normalArray[ i + 6 ];
                    ncy  = normalArray[ i + 7 ];
                    ncz  = normalArray[ i + 8 ];

                    nx = ( nax + nbx + ncx ) / 3;
                    ny = ( nay + nby + ncy ) / 3;
                    nz = ( naz + nbz + ncz ) / 3;

                    normalArray[ i ]      = nx;
                    normalArray[ i + 1 ] = ny;
                    normalArray[ i + 2 ] = nz;

                    normalArray[ i + 3 ] = nx;
                    normalArray[ i + 4 ] = ny;
                    normalArray[ i + 5 ] = nz;

                    normalArray[ i + 6 ] = nx;
                    normalArray[ i + 7 ] = ny;
                    normalArray[ i + 8 ] = nz;

                }

            }

            _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
            _gl.enableVertexAttribArray( program.attributes.normal );
            _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.hasUvs && material.map ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
            _gl.enableVertexAttribArray( program.attributes.uv );
            _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
            _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
            _gl.enableVertexAttribArray( program.attributes.color );
            _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );

        }

        _gl.drawArrays( _gl.TRIANGLES, 0, object.count );

        object.count = 0;

    };

    this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {

        if ( material.visible === false ) return;

        var program, attributes, linewidth, primitives, a, attribute;

        program = setProgram( camera, lights, fog, material, object );

        attributes = program.attributes;

        var updateBuffers = false,
            wireframeBit = material.wireframe ? 1 : 0,
            geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;

        if ( geometryHash !== _currentGeometryGroupHash ) {

            _currentGeometryGroupHash = geometryHash;
            updateBuffers = true;

        }

        // render mesh

        if ( object instanceof THREE.Mesh ) {

            var offsets = geometry.offsets;

            // if there is more than 1 chunk
            // must set attribute pointers to use new offsets for each chunk
            // even if geometry and materials didn't change

            if ( offsets.length > 1 ) updateBuffers = true;

            for ( var i = 0, il = offsets.length; i < il; ++ i ) {

                var startIndex = offsets[ i ].index;

                if ( updateBuffers ) {

                    // vertices

                    var position = geometry.attributes[ "position" ];
                    var positionSize = position.itemSize;

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer );
                    _gl.vertexAttribPointer( attributes.position, positionSize, _gl.FLOAT, false, 0, startIndex * positionSize * 4 ); // 4 bytes per Float32

                    // normals

                    var normal = geometry.attributes[ "normal" ];

                    if ( attributes.normal >= 0 && normal ) {

                        var normalSize = normal.itemSize;

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, normal.buffer );
                        _gl.vertexAttribPointer( attributes.normal, normalSize, _gl.FLOAT, false, 0, startIndex * normalSize * 4 );

                    }

                    // uvs

                    var uv = geometry.attributes[ "uv" ];

                    if ( attributes.uv >= 0 && uv ) {

                        if ( uv.buffer ) {

                            var uvSize = uv.itemSize;

                            _gl.bindBuffer( _gl.ARRAY_BUFFER, uv.buffer );
                            _gl.vertexAttribPointer( attributes.uv, uvSize, _gl.FLOAT, false, 0, startIndex * uvSize * 4 );

                            _gl.enableVertexAttribArray( attributes.uv );

                        } else {

                            _gl.disableVertexAttribArray( attributes.uv );

                        }

                    }

                    // colors

                    var color = geometry.attributes[ "color" ];

                    if ( attributes.color >= 0 && color ) {

                        var colorSize = color.itemSize;

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer );
                        _gl.vertexAttribPointer( attributes.color, colorSize, _gl.FLOAT, false, 0, startIndex * colorSize * 4 );

                    }

                    // tangents

                    var tangent = geometry.attributes[ "tangent" ];

                    if ( attributes.tangent >= 0 && tangent ) {

                        var tangentSize = tangent.itemSize;

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, tangent.buffer );
                        _gl.vertexAttribPointer( attributes.tangent, tangentSize, _gl.FLOAT, false, 0, startIndex * tangentSize * 4 );

                    }

                    // indices

                    var index = geometry.attributes[ "index" ];

                    _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );

                }

                // render indexed triangles

                _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16

                _this.info.render.calls ++;
                _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
                _this.info.render.faces += offsets[ i ].count / 3;

            }

        // render particles

        } else if ( object instanceof THREE.ParticleSystem ) {

            if ( updateBuffers ) {

                // vertices

                var position = geometry.attributes[ "position" ];
                var positionSize = position.itemSize;

                _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer );
                _gl.vertexAttribPointer( attributes.position, positionSize, _gl.FLOAT, false, 0, 0 );

                // colors

                var color = geometry.attributes[ "color" ];

                if ( attributes.color >= 0 && color ) {

                    var colorSize = color.itemSize;

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer );
                    _gl.vertexAttribPointer( attributes.color, colorSize, _gl.FLOAT, false, 0, 0 );

                }

                // render particles

                _gl.drawArrays( _gl.POINTS, 0, position.numItems / 3 );

                _this.info.render.calls ++;
                _this.info.render.points += position.numItems / 3;

            }

        }

    };

    this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {

        if ( material.visible === false ) return;

        var program, attributes, linewidth, primitives, a, attribute, i, il;

        program = setProgram( camera, lights, fog, material, object );

        attributes = program.attributes;

        var updateBuffers = false,
            wireframeBit = material.wireframe ? 1 : 0,
            geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;

        if ( geometryGroupHash !== _currentGeometryGroupHash ) {

            _currentGeometryGroupHash = geometryGroupHash;
            updateBuffers = true;

        }

        // vertices

        if ( !material.morphTargets && attributes.position >= 0 ) {

            if ( updateBuffers ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
                _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );

            }

        } else {

            if ( object.morphTargetBase ) {

                setupMorphTargets( material, geometryGroup, object );

            }

        }


        if ( updateBuffers ) {

            // custom attributes

            // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers

            if ( geometryGroup.__webglCustomAttributesList ) {

                for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {

                    attribute = geometryGroup.__webglCustomAttributesList[ i ];

                    if( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
                        _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );

                    }

                }

            }


            // colors

            if ( attributes.color >= 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
                _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );

            }

            // normals

            if ( attributes.normal >= 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
                _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );

            }

            // tangents

            if ( attributes.tangent >= 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
                _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );

            }

            // uvs

            if ( attributes.uv >= 0 ) {

                if ( geometryGroup.__webglUVBuffer ) {

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
                    _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );

                    _gl.enableVertexAttribArray( attributes.uv );

                } else {

                    _gl.disableVertexAttribArray( attributes.uv );

                }

            }

            if ( attributes.uv2 >= 0 ) {

                if ( geometryGroup.__webglUV2Buffer ) {

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
                    _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );

                    _gl.enableVertexAttribArray( attributes.uv2 );

                } else {

                    _gl.disableVertexAttribArray( attributes.uv2 );

                }

            }

            if ( material.skinning &&
                 attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
                _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
                _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );

            }

        }

        // render mesh

        if ( object instanceof THREE.Mesh ) {

            // wireframe

            if ( material.wireframe ) {

                setLineWidth( material.wireframeLinewidth );

                if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
                _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 );

            // triangles

            } else {

                if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
                _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );

            }

            _this.info.render.calls ++;
            _this.info.render.vertices += geometryGroup.__webglFaceCount;
            _this.info.render.faces += geometryGroup.__webglFaceCount / 3;

        // render lines

        } else if ( object instanceof THREE.Line ) {

            primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;

            setLineWidth( material.linewidth );

            _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount );

            _this.info.render.calls ++;

        // render particles

        } else if ( object instanceof THREE.ParticleSystem ) {

            _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );

            _this.info.render.calls ++;
            _this.info.render.points += geometryGroup.__webglParticleCount;

        // render ribbon

        } else if ( object instanceof THREE.Ribbon ) {

            _gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webglVertexCount );

            _this.info.render.calls ++;

        }

    };

    function setupMorphTargets ( material, geometryGroup, object ) {

        // set base

        var attributes = material.program.attributes;

        if ( object.morphTargetBase !== -1 ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
            _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );

        } else if ( attributes.position >= 0 ) {

            _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
            _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );

        }

        if ( object.morphTargetForcedOrder.length ) {

            // set forced order

            var m = 0;
            var order = object.morphTargetForcedOrder;
            var influences = object.morphTargetInfluences;

            while ( m < material.numSupportedMorphTargets && m < order.length ) {

                _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
                _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );

                if ( material.morphNormals ) {

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );
                    _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );

                }

                object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];

                m ++;
            }

        } else {

            // find the most influencing

            var influence, activeInfluenceIndices = [];
            var influences = object.morphTargetInfluences;
            var i, il = influences.length;

            for ( i = 0; i < il; i ++ ) {

                influence = influences[ i ];

                if ( influence > 0 ) {

                    activeInfluenceIndices.push( [ i, influence ] );

                }

            }

            if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {

                activeInfluenceIndices.sort( numericalSort );
                activeInfluenceIndices.length = material.numSupportedMorphTargets;

            } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {

                activeInfluenceIndices.sort( numericalSort );

            } else if ( activeInfluenceIndices.length === 0 ) {

                activeInfluenceIndices.push( [ 0, 0 ] );

            };

            var influenceIndex, m = 0;

            while ( m < material.numSupportedMorphTargets ) {

                if ( activeInfluenceIndices[ m ] ) {

                    influenceIndex = activeInfluenceIndices[ m ][ 0 ];

                    _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );

                    _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );

                    if ( material.morphNormals ) {

                        _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );
                        _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );

                    }

                    object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];

                } else {

                    _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );

                    if ( material.morphNormals ) {

                        _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );

                    }

                    object.__webglMorphTargetInfluences[ m ] = 0;

                }

                m ++;

            }

        }

        // load updated influences uniform

        if ( material.program.uniforms.morphTargetInfluences !== null ) {

            _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );

        }

    };

    // Sorting

    function painterSort ( a, b ) {

        return b.z - a.z;

    };

    function numericalSort ( a, b ) {

        return b[ 1 ] - a[ 1 ];

    };


    // Rendering

    this.render = function ( scene, camera, renderTarget, forceClear ) {

        if ( camera instanceof THREE.Camera === false ) {

            console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
            return;

        }

        var i, il,

        webglObject, object,
        renderList,

        lights = scene.__lights,
        fog = scene.fog;

        // reset caching for this frame

        _currentMaterialId = -1;
        _lightsNeedUpdate = true;

        // update scene graph

        if ( this.autoUpdateScene ) scene.updateMatrixWorld();

        // update camera matrices and frustum

        if ( camera.parent === undefined ) camera.updateMatrixWorld();

        if ( ! camera._viewMatrixArray ) camera._viewMatrixArray = new Float32Array( 16 );
        if ( ! camera._projectionMatrixArray ) camera._projectionMatrixArray = new Float32Array( 16 );

        camera.matrixWorldInverse.getInverse( camera.matrixWorld );

        camera.matrixWorldInverse.flattenToArray( camera._viewMatrixArray );
        camera.projectionMatrix.flattenToArray( camera._projectionMatrixArray );

        _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
        _frustum.setFromMatrix( _projScreenMatrix );

        // update WebGL objects

        if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );

        // custom render plugins (pre pass)

        renderPlugins( this.renderPluginsPre, scene, camera );

        //

        _this.info.render.calls = 0;
        _this.info.render.vertices = 0;
        _this.info.render.faces = 0;
        _this.info.render.points = 0;

        this.setRenderTarget( renderTarget );

        if ( this.autoClear || forceClear ) {

            this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );

        }

        // set matrices for regular objects (frustum culled)

        renderList = scene.__webglObjects;

        for ( i = 0, il = renderList.length; i < il; i ++ ) {

            webglObject = renderList[ i ];
            object = webglObject.object;

            webglObject.render = false;

            if ( object.visible ) {

                if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.contains( object ) ) {

                    //object.matrixWorld.flattenToArray( object._modelMatrixArray );

                    setupMatrices( object, camera );

                    unrollBufferMaterial( webglObject );

                    webglObject.render = true;

                    if ( this.sortObjects === true ) {

                        if ( object.renderDepth !== null ) {

                            webglObject.z = object.renderDepth;

                        } else {

                            _vector3.copy( object.matrixWorld.getPosition() );
                            _projScreenMatrix.multiplyVector3( _vector3 );

                            webglObject.z = _vector3.z;

                        }

                    }

                }

            }

        }

        if ( this.sortObjects ) {

            renderList.sort( painterSort );

        }

        // set matrices for immediate objects

        renderList = scene.__webglObjectsImmediate;

        for ( i = 0, il = renderList.length; i < il; i ++ ) {

            webglObject = renderList[ i ];
            object = webglObject.object;

            if ( object.visible ) {

                /*
                if ( object.matrixAutoUpdate ) {

                    object.matrixWorld.flattenToArray( object._modelMatrixArray );

                }
                */

                setupMatrices( object, camera );

                unrollImmediateBufferMaterial( webglObject );

            }

        }

        if ( scene.overrideMaterial ) {

            var material = scene.overrideMaterial;

            this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
            this.setDepthTest( material.depthTest );
            this.setDepthWrite( material.depthWrite );
            setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

            renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material );
            renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material );

        } else {

            // opaque pass (front-to-back order)

            this.setBlending( THREE.NormalBlending );

            renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false );
            renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false );

            // transparent pass (back-to-front order)

            renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true );
            renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true );

        }

        // custom render plugins (post pass)

        renderPlugins( this.renderPluginsPost, scene, camera );


        // Generate mipmap if we're using any kind of mipmap filtering

        if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {

            updateRenderTargetMipmap( renderTarget );

        }

        // Ensure depth buffer writing is enabled so it can be cleared on next render

        this.setDepthTest( true );
        this.setDepthWrite( true );

        // _gl.finish();

    };

    function renderPlugins( plugins, scene, camera ) {

        if ( ! plugins.length ) return;

        for ( var i = 0, il = plugins.length; i < il; i ++ ) {

            // reset state for plugin (to start from clean slate)

            _currentProgram = null;
            _currentCamera = null;

            _oldBlending = -1;
            _oldDepthTest = -1;
            _oldDepthWrite = -1;
            _oldDoubleSided = -1;
            _oldFlipSided = -1;
            _currentGeometryGroupHash = -1;
            _currentMaterialId = -1;

            _lightsNeedUpdate = true;

            plugins[ i ].render( scene, camera, _currentWidth, _currentHeight );

            // reset state after plugin (anything could have changed)

            _currentProgram = null;
            _currentCamera = null;

            _oldBlending = -1;
            _oldDepthTest = -1;
            _oldDepthWrite = -1;
            _oldDoubleSided = -1;
            _oldFlipSided = -1;
            _currentGeometryGroupHash = -1;
            _currentMaterialId = -1;

            _lightsNeedUpdate = true;

        }

    };

    function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {

        var webglObject, object, buffer, material, start, end, delta;

        if ( reverse ) {

            start = renderList.length - 1;
            end = -1;
            delta = -1;

        } else {

            start = 0;
            end = renderList.length;
            delta = 1;
        }

        for ( var i = start; i !== end; i += delta ) {

            webglObject = renderList[ i ];

            if ( webglObject.render ) {

                object = webglObject.object;
                buffer = webglObject.buffer;

                if ( overrideMaterial ) {

                    material = overrideMaterial;

                } else {

                    material = webglObject[ materialType ];

                    if ( ! material ) continue;

                    if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );

                    _this.setDepthTest( material.depthTest );
                    _this.setDepthWrite( material.depthWrite );
                    setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

                }

                _this.setMaterialFaces( material );

                if ( buffer instanceof THREE.BufferGeometry ) {

                    _this.renderBufferDirect( camera, lights, fog, material, buffer, object );

                } else {

                    _this.renderBuffer( camera, lights, fog, material, buffer, object );

                }

            }

        }

    };

    function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {

        var webglObject, object, material, program;

        for ( var i = 0, il = renderList.length; i < il; i ++ ) {

            webglObject = renderList[ i ];
            object = webglObject.object;

            if ( object.visible ) {

                if ( overrideMaterial ) {

                    material = overrideMaterial;

                } else {

                    material = webglObject[ materialType ];

                    if ( ! material ) continue;

                    if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );

                    _this.setDepthTest( material.depthTest );
                    _this.setDepthWrite( material.depthWrite );
                    setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

                }

                _this.renderImmediateObject( camera, lights, fog, material, object );

            }

        }

    };

    this.renderImmediateObject = function ( camera, lights, fog, material, object ) {

        var program = setProgram( camera, lights, fog, material, object );

        _currentGeometryGroupHash = -1;

        _this.setMaterialFaces( material );

        if ( object.immediateRenderCallback ) {

            object.immediateRenderCallback( program, _gl, _frustum );

        } else {

            object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } );

        }

    };

    function unrollImmediateBufferMaterial ( globject ) {

        var object = globject.object,
            material = object.material;

        if ( material.transparent ) {

            globject.transparent = material;
            globject.opaque = null;

        } else {

            globject.opaque = material;
            globject.transparent = null;

        }

    };

    function unrollBufferMaterial ( globject ) {

        var object = globject.object,
            buffer = globject.buffer,
            material, materialIndex, meshMaterial;

        meshMaterial = object.material;

        if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {

            materialIndex = buffer.materialIndex;

            if ( materialIndex >= 0 ) {

                material = object.geometry.materials[ materialIndex ];

                if ( material.transparent ) {

                    globject.transparent = material;
                    globject.opaque = null;

                } else {

                    globject.opaque = material;
                    globject.transparent = null;

                }

            }

        } else {

            material = meshMaterial;

            if ( material ) {

                if ( material.transparent ) {

                    globject.transparent = material;
                    globject.opaque = null;

                } else {

                    globject.opaque = material;
                    globject.transparent = null;

                }

            }

        }

    };

    // Geometry splitting

    function sortFacesByMaterial ( geometry ) {

        var f, fl, face, materialIndex, vertices,
            materialHash, groupHash,
            hash_map = {};

        var numMorphTargets = geometry.morphTargets.length;
        var numMorphNormals = geometry.morphNormals.length;

        geometry.geometryGroups = {};

        for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

            face = geometry.faces[ f ];
            materialIndex = face.materialIndex;

            materialHash = ( materialIndex !== undefined ) ? materialIndex : -1;

            if ( hash_map[ materialHash ] === undefined ) {

                hash_map[ materialHash ] = { 'hash': materialHash, 'counter': 0 };

            }

            groupHash = hash_map[ materialHash ].hash + '_' + hash_map[ materialHash ].counter;

            if ( geometry.geometryGroups[ groupHash ] === undefined ) {

                geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };

            }

            vertices = face instanceof THREE.Face3 ? 3 : 4;

            if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) {

                hash_map[ materialHash ].counter += 1;
                groupHash = hash_map[ materialHash ].hash + '_' + hash_map[ materialHash ].counter;

                if ( geometry.geometryGroups[ groupHash ] === undefined ) {

                    geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };

                }

            }

            if ( face instanceof THREE.Face3 ) {

                geometry.geometryGroups[ groupHash ].faces3.push( f );

            } else {

                geometry.geometryGroups[ groupHash ].faces4.push( f );

            }

            geometry.geometryGroups[ groupHash ].vertices += vertices;

        }

        geometry.geometryGroupsList = [];

        for ( var g in geometry.geometryGroups ) {

            geometry.geometryGroups[ g ].id = _geometryGroupCounter ++;

            geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] );

        }

    };

    // Objects refresh

    this.initWebGLObjects = function ( scene ) {

        if ( !scene.__webglObjects ) {

            scene.__webglObjects = [];
            scene.__webglObjectsImmediate = [];
            scene.__webglSprites = [];
            scene.__webglFlares = [];

        }

        while ( scene.__objectsAdded.length ) {

            addObject( scene.__objectsAdded[ 0 ], scene );
            scene.__objectsAdded.splice( 0, 1 );

        }

        while ( scene.__objectsRemoved.length ) {

            removeObject( scene.__objectsRemoved[ 0 ], scene );
            scene.__objectsRemoved.splice( 0, 1 );

        }

        // update must be called after objects adding / removal

        for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {

            updateObject( scene.__webglObjects[ o ].object );

        }

    };

    // Objects adding

    function addObject ( object, scene ) {

        var g, geometry, geometryGroup;

        if ( ! object.__webglInit ) {

            object.__webglInit = true;

            object._modelViewMatrix = new THREE.Matrix4();
            object._normalMatrix = new THREE.Matrix3();

            if ( object instanceof THREE.Mesh ) {

                geometry = object.geometry;

                if ( geometry instanceof THREE.Geometry ) {

                    if ( geometry.geometryGroups === undefined ) {

                        sortFacesByMaterial( geometry );

                    }

                    // create separate VBOs per geometry chunk

                    for ( g in geometry.geometryGroups ) {

                        geometryGroup = geometry.geometryGroups[ g ];

                        // initialise VBO on the first access

                        if ( ! geometryGroup.__webglVertexBuffer ) {

                            createMeshBuffers( geometryGroup );
                            initMeshBuffers( geometryGroup, object );

                            geometry.verticesNeedUpdate = true;
                            geometry.morphTargetsNeedUpdate = true;
                            geometry.elementsNeedUpdate = true;
                            geometry.uvsNeedUpdate = true;
                            geometry.normalsNeedUpdate = true;
                            geometry.tangentsNeedUpdate = true;
                            geometry.colorsNeedUpdate = true;

                        }

                    }

                } else if ( geometry instanceof THREE.BufferGeometry ) {

                    initDirectBuffers( geometry );

                }

            } else if ( object instanceof THREE.Ribbon ) {

                geometry = object.geometry;

                if( ! geometry.__webglVertexBuffer ) {

                    createRibbonBuffers( geometry );
                    initRibbonBuffers( geometry );

                    geometry.verticesNeedUpdate = true;
                    geometry.colorsNeedUpdate = true;

                }

            } else if ( object instanceof THREE.Line ) {

                geometry = object.geometry;

                if( ! geometry.__webglVertexBuffer ) {

                    createLineBuffers( geometry );
                    initLineBuffers( geometry, object );

                    geometry.verticesNeedUpdate = true;
                    geometry.colorsNeedUpdate = true;

                }

            } else if ( object instanceof THREE.ParticleSystem ) {

                geometry = object.geometry;

                if ( ! geometry.__webglVertexBuffer ) {

                    if ( geometry instanceof THREE.Geometry ) {

                        createParticleBuffers( geometry );
                        initParticleBuffers( geometry, object );

                        geometry.verticesNeedUpdate = true;
                        geometry.colorsNeedUpdate = true;

                    } else if ( geometry instanceof THREE.BufferGeometry ) {

                        initDirectBuffers( geometry );

                    }


                }

            }

        }

        if ( ! object.__webglActive ) {

            if ( object instanceof THREE.Mesh ) {

                geometry = object.geometry;

                if ( geometry instanceof THREE.BufferGeometry ) {

                    addBuffer( scene.__webglObjects, geometry, object );

                } else {

                    for ( g in geometry.geometryGroups ) {

                        geometryGroup = geometry.geometryGroups[ g ];

                        addBuffer( scene.__webglObjects, geometryGroup, object );

                    }

                }

            } else if ( object instanceof THREE.Ribbon ||
                        object instanceof THREE.Line ||
                        object instanceof THREE.ParticleSystem ) {

                geometry = object.geometry;
                addBuffer( scene.__webglObjects, geometry, object );

            } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {

                addBufferImmediate( scene.__webglObjectsImmediate, object );

            } else if ( object instanceof THREE.Sprite ) {

                scene.__webglSprites.push( object );

            } else if ( object instanceof THREE.LensFlare ) {

                scene.__webglFlares.push( object );

            }

            object.__webglActive = true;

        }

    };

    function addBuffer ( objlist, buffer, object ) {

        objlist.push(
            {
                buffer: buffer,
                object: object,
                opaque: null,
                transparent: null
            }
        );

    };

    function addBufferImmediate ( objlist, object ) {

        objlist.push(
            {
                object: object,
                opaque: null,
                transparent: null
            }
        );

    };

    // Objects updates

    function updateObject ( object ) {

        var geometry = object.geometry,
            geometryGroup, customAttributesDirty, material;

        if ( object instanceof THREE.Mesh ) {

            if ( geometry instanceof THREE.BufferGeometry ) {

                if ( geometry.verticesNeedUpdate || geometry.elementsNeedUpdate ||
                     geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
                     geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate ) {

                    setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic );

                }

                geometry.verticesNeedUpdate = false;
                geometry.elementsNeedUpdate = false;
                geometry.uvsNeedUpdate = false;
                geometry.normalsNeedUpdate = false;
                geometry.colorsNeedUpdate = false;
                geometry.tangentsNeedUpdate = false;

            } else {

                // check all geometry groups

                for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {

                    geometryGroup = geometry.geometryGroupsList[ i ];

                    material = getBufferMaterial( object, geometryGroup );

                    customAttributesDirty = material.attributes && areCustomAttributesDirty( material );

                    if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
                         geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
                         geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {

                        setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material );

                    }

                }

                geometry.verticesNeedUpdate = false;
                geometry.morphTargetsNeedUpdate = false;
                geometry.elementsNeedUpdate = false;
                geometry.uvsNeedUpdate = false;
                geometry.normalsNeedUpdate = false;
                geometry.colorsNeedUpdate = false;
                geometry.tangentsNeedUpdate = false;

                material.attributes && clearCustomAttributes( material );

            }

        } else if ( object instanceof THREE.Ribbon ) {

            if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate ) {

                setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW );

            }

            geometry.verticesNeedUpdate = false;
            geometry.colorsNeedUpdate = false;

        } else if ( object instanceof THREE.Line ) {

            material = getBufferMaterial( object, geometryGroup );

            customAttributesDirty = material.attributes && areCustomAttributesDirty( material );

            if ( geometry.verticesNeedUpdate ||  geometry.colorsNeedUpdate || customAttributesDirty ) {

                setLineBuffers( geometry, _gl.DYNAMIC_DRAW );

            }

            geometry.verticesNeedUpdate = false;
            geometry.colorsNeedUpdate = false;

            material.attributes && clearCustomAttributes( material );

        } else if ( object instanceof THREE.ParticleSystem ) {

            if ( geometry instanceof THREE.BufferGeometry ) {

                if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate ) {

                    setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic );

                }

                geometry.verticesNeedUpdate = false;
                geometry.colorsNeedUpdate = false;

            } else {

                material = getBufferMaterial( object, geometryGroup );

                customAttributesDirty = material.attributes && areCustomAttributesDirty( material );

                if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) {

                    setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );

                }

                geometry.verticesNeedUpdate = false;
                geometry.colorsNeedUpdate = false;

                material.attributes && clearCustomAttributes( material );

            }

        }

    };

    // Objects updates - custom attributes check

    function areCustomAttributesDirty ( material ) {

        for ( var a in material.attributes ) {

            if ( material.attributes[ a ].needsUpdate ) return true;

        }

        return false;

    };

    function clearCustomAttributes ( material ) {

        for ( var a in material.attributes ) {

            material.attributes[ a ].needsUpdate = false;

        }

    };

    // Objects removal

    function removeObject ( object, scene ) {

        if ( object instanceof THREE.Mesh  ||
             object instanceof THREE.ParticleSystem ||
             object instanceof THREE.Ribbon ||
             object instanceof THREE.Line ) {

            removeInstances( scene.__webglObjects, object );

        } else if ( object instanceof THREE.Sprite ) {

            removeInstancesDirect( scene.__webglSprites, object );

        } else if ( object instanceof THREE.LensFlare ) {

            removeInstancesDirect( scene.__webglFlares, object );

        } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {

            removeInstances( scene.__webglObjectsImmediate, object );

        }

        object.__webglActive = false;

    };

    function removeInstances ( objlist, object ) {

        for ( var o = objlist.length - 1; o >= 0; o -- ) {

            if ( objlist[ o ].object === object ) {

                objlist.splice( o, 1 );

            }

        }

    };

    function removeInstancesDirect ( objlist, object ) {

        for ( var o = objlist.length - 1; o >= 0; o -- ) {

            if ( objlist[ o ] === object ) {

                objlist.splice( o, 1 );

            }

        }

    };

    // Materials

    this.initMaterial = function ( material, lights, fog, object ) {

        var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;

        if ( material instanceof THREE.MeshDepthMaterial ) {

            shaderID = 'depth';

        } else if ( material instanceof THREE.MeshNormalMaterial ) {

            shaderID = 'normal';

        } else if ( material instanceof THREE.MeshBasicMaterial ) {

            shaderID = 'basic';

        } else if ( material instanceof THREE.MeshLambertMaterial ) {

            shaderID = 'lambert';

        } else if ( material instanceof THREE.MeshPhongMaterial ) {

            shaderID = 'phong';

        } else if ( material instanceof THREE.LineBasicMaterial ) {

            shaderID = 'basic';

        } else if ( material instanceof THREE.ParticleBasicMaterial ) {

            shaderID = 'particle_basic';

        }

        if ( shaderID ) {

            setMaterialShaders( material, THREE.ShaderLib[ shaderID ] );

        }

        // heuristics to create shader parameters according to lights in the scene
        // (not to blow over maxLights budget)

        maxLightCount = allocateLights( lights );

        maxShadows = allocateShadows( lights );

        maxBones = allocateBones( object );

        parameters = {

            map: !!material.map,
            envMap: !!material.envMap,
            lightMap: !!material.lightMap,
            bumpMap: !!material.bumpMap,
            normalMap: !!material.normalMap,
            specularMap: !!material.specularMap,

            vertexColors: material.vertexColors,

            fog: fog,
            useFog: material.fog,

            sizeAttenuation: material.sizeAttenuation,

            skinning: material.skinning,
            maxBones: maxBones,
            useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture,
            boneTextureWidth: object && object.boneTextureWidth,
            boneTextureHeight: object && object.boneTextureHeight,

            morphTargets: material.morphTargets,
            morphNormals: material.morphNormals,
            maxMorphTargets: this.maxMorphTargets,
            maxMorphNormals: this.maxMorphNormals,

            maxDirLights: maxLightCount.directional,
            maxPointLights: maxLightCount.point,
            maxSpotLights: maxLightCount.spot,
            maxHemiLights: maxLightCount.hemi,

            maxShadows: maxShadows,
            shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow,
            shadowMapSoft: this.shadowMapSoft,
            shadowMapDebug: this.shadowMapDebug,
            shadowMapCascade: this.shadowMapCascade,

            alphaTest: material.alphaTest,
            metal: material.metal,
            perPixel: material.perPixel,
            wrapAround: material.wrapAround,
            doubleSided: material.side === THREE.DoubleSide,
            flipSided: material.side === THREE.BackSide

        };

        material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, parameters );

        var attributes = material.program.attributes;

        if ( attributes.position >= 0 ) _gl.enableVertexAttribArray( attributes.position );
        if ( attributes.color >= 0 ) _gl.enableVertexAttribArray( attributes.color );
        if ( attributes.normal >= 0 ) _gl.enableVertexAttribArray( attributes.normal );
        if ( attributes.tangent >= 0 ) _gl.enableVertexAttribArray( attributes.tangent );

        if ( material.skinning &&
             attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {

            _gl.enableVertexAttribArray( attributes.skinIndex );
            _gl.enableVertexAttribArray( attributes.skinWeight );

        }

        if ( material.attributes ) {

            for ( a in material.attributes ) {

                if( attributes[ a ] !== undefined && attributes[ a ] >= 0 ) _gl.enableVertexAttribArray( attributes[ a ] );

            }

        }

        if ( material.morphTargets ) {

            material.numSupportedMorphTargets = 0;

            var id, base = "morphTarget";

            for ( i = 0; i < this.maxMorphTargets; i ++ ) {

                id = base + i;

                if ( attributes[ id ] >= 0 ) {

                    _gl.enableVertexAttribArray( attributes[ id ] );
                    material.numSupportedMorphTargets ++;

                }

            }

        }

        if ( material.morphNormals ) {

            material.numSupportedMorphNormals = 0;

            var id, base = "morphNormal";

            for ( i = 0; i < this.maxMorphNormals; i ++ ) {

                id = base + i;

                if ( attributes[ id ] >= 0 ) {

                    _gl.enableVertexAttribArray( attributes[ id ] );
                    material.numSupportedMorphNormals ++;

                }

            }

        }

        material.uniformsList = [];

        for ( u in material.uniforms ) {

            material.uniformsList.push( [ material.uniforms[ u ], u ] );

        }

    };

    function setMaterialShaders( material, shaders ) {

        material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
        material.vertexShader = shaders.vertexShader;
        material.fragmentShader = shaders.fragmentShader;

    };

    function setProgram( camera, lights, fog, material, object ) {

        _usedTextureUnits = 0;

        if ( material.needsUpdate ) {

            if ( material.program ) _this.deallocateMaterial( material );

            _this.initMaterial( material, lights, fog, object );
            material.needsUpdate = false;

        }

        if ( material.morphTargets ) {

            if ( ! object.__webglMorphTargetInfluences ) {

                object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );

            }

        }

        var refreshMaterial = false;

        var program = material.program,
            p_uniforms = program.uniforms,
            m_uniforms = material.uniforms;

        if ( program !== _currentProgram ) {

            _gl.useProgram( program );
            _currentProgram = program;

            refreshMaterial = true;

        }

        if ( material.id !== _currentMaterialId ) {

            _currentMaterialId = material.id;
            refreshMaterial = true;

        }

        if ( refreshMaterial || camera !== _currentCamera ) {

            _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera._projectionMatrixArray );

            if ( camera !== _currentCamera ) _currentCamera = camera;

        }

        // skinning uniforms must be set even if material didn't change
        // auto-setting of texture unit for bone texture must go before other textures
        // not sure why, but otherwise weird things happen

        if ( material.skinning ) {

            if ( _supportsBoneTextures && object.useVertexTexture ) {

                if ( p_uniforms.boneTexture !== null ) {

                    var textureUnit = getTextureUnit();

                    _gl.uniform1i( p_uniforms.boneTexture, textureUnit );
                    _this.setTexture( object.boneTexture, textureUnit );

                }

            } else {

                if ( p_uniforms.boneGlobalMatrices !== null ) {

                    _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );

                }

            }

        }

        if ( refreshMaterial ) {

            // refresh uniforms common to several materials

            if ( fog && material.fog ) {

                refreshUniformsFog( m_uniforms, fog );

            }

            if ( material instanceof THREE.MeshPhongMaterial ||
                 material instanceof THREE.MeshLambertMaterial ||
                 material.lights ) {

                if ( _lightsNeedUpdate ) {

                    setupLights( program, lights );
                    _lightsNeedUpdate = false;

                }

                refreshUniformsLights( m_uniforms, _lights );

            }

            if ( material instanceof THREE.MeshBasicMaterial ||
                 material instanceof THREE.MeshLambertMaterial ||
                 material instanceof THREE.MeshPhongMaterial ) {

                refreshUniformsCommon( m_uniforms, material );

            }

            // refresh single material specific uniforms

            if ( material instanceof THREE.LineBasicMaterial ) {

                refreshUniformsLine( m_uniforms, material );

            } else if ( material instanceof THREE.ParticleBasicMaterial ) {

                refreshUniformsParticle( m_uniforms, material );

            } else if ( material instanceof THREE.MeshPhongMaterial ) {

                refreshUniformsPhong( m_uniforms, material );

            } else if ( material instanceof THREE.MeshLambertMaterial ) {

                refreshUniformsLambert( m_uniforms, material );

            } else if ( material instanceof THREE.MeshDepthMaterial ) {

                m_uniforms.mNear.value = camera.near;
                m_uniforms.mFar.value = camera.far;
                m_uniforms.opacity.value = material.opacity;

            } else if ( material instanceof THREE.MeshNormalMaterial ) {

                m_uniforms.opacity.value = material.opacity;

            }

            if ( object.receiveShadow && ! material._shadowPass ) {

                refreshUniformsShadow( m_uniforms, lights );

            }

            // load common uniforms

            loadUniformsGeneric( program, material.uniformsList );

            // load material specific uniforms
            // (shader material also gets them for the sake of genericity)

            if ( material instanceof THREE.ShaderMaterial ||
                 material instanceof THREE.MeshPhongMaterial ||
                 material.envMap ) {

                if ( p_uniforms.cameraPosition !== null ) {

                    var position = camera.matrixWorld.getPosition();
                    _gl.uniform3f( p_uniforms.cameraPosition, position.x, position.y, position.z );

                }

            }

            if ( material instanceof THREE.MeshPhongMaterial ||
                 material instanceof THREE.MeshLambertMaterial ||
                 material instanceof THREE.ShaderMaterial ||
                 material.skinning ) {

                if ( p_uniforms.viewMatrix !== null ) {

                    _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera._viewMatrixArray );

                }

            }

        }

        loadUniformsMatrices( p_uniforms, object );

        if ( p_uniforms.modelMatrix !== null ) {

            _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );

        }

        return program;

    };

    // Uniforms (refresh uniforms objects)

    function refreshUniformsCommon ( uniforms, material ) {

        uniforms.opacity.value = material.opacity;

        if ( _this.gammaInput ) {

            uniforms.diffuse.value.copyGammaToLinear( material.color );

        } else {

            uniforms.diffuse.value = material.color;

        }

        uniforms.map.value = material.map;
        uniforms.lightMap.value = material.lightMap;
        uniforms.specularMap.value = material.specularMap;

        if ( material.bumpMap ) {

            uniforms.bumpMap.value = material.bumpMap;
            uniforms.bumpScale.value = material.bumpScale;

        }

        if ( material.normalMap ) {

            uniforms.normalMap.value = material.normalMap;
            uniforms.normalScale.value.copy( material.normalScale );

        }

        // uv repeat and offset setting priorities
        //    1. color map
        //    2. specular map
        //    3. normal map
        //    4. bump map

        var uvScaleMap;

        if ( material.map ) {

            uvScaleMap = material.map;

        } else if ( material.specularMap ) {

            uvScaleMap = material.specularMap;

        } else if ( material.normalMap ) {

            uvScaleMap = material.normalMap;

        } else if ( material.bumpMap ) {

            uvScaleMap = material.bumpMap;

        }

        if ( uvScaleMap !== undefined ) {

            var offset = uvScaleMap.offset;
            var repeat = uvScaleMap.repeat;

            uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );

        }

        uniforms.envMap.value = material.envMap;
        uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;

        if ( _this.gammaInput ) {

            //uniforms.reflectivity.value = material.reflectivity * material.reflectivity;
            uniforms.reflectivity.value = material.reflectivity;

        } else {

            uniforms.reflectivity.value = material.reflectivity;

        }

        uniforms.refractionRatio.value = material.refractionRatio;
        uniforms.combine.value = material.combine;
        uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;

    };

    function refreshUniformsLine ( uniforms, material ) {

        uniforms.diffuse.value = material.color;
        uniforms.opacity.value = material.opacity;

    };

    function refreshUniformsParticle ( uniforms, material ) {

        uniforms.psColor.value = material.color;
        uniforms.opacity.value = material.opacity;
        uniforms.size.value = material.size;
        uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.

        uniforms.map.value = material.map;

    };

    function refreshUniformsFog ( uniforms, fog ) {

        uniforms.fogColor.value = fog.color;

        if ( fog instanceof THREE.Fog ) {

            uniforms.fogNear.value = fog.near;
            uniforms.fogFar.value = fog.far;

        } else if ( fog instanceof THREE.FogExp2 ) {

            uniforms.fogDensity.value = fog.density;

        }

    };

    function refreshUniformsPhong ( uniforms, material ) {

        uniforms.shininess.value = material.shininess;

        if ( _this.gammaInput ) {

            uniforms.ambient.value.copyGammaToLinear( material.ambient );
            uniforms.emissive.value.copyGammaToLinear( material.emissive );
            uniforms.specular.value.copyGammaToLinear( material.specular );

        } else {

            uniforms.ambient.value = material.ambient;
            uniforms.emissive.value = material.emissive;
            uniforms.specular.value = material.specular;

        }

        if ( material.wrapAround ) {

            uniforms.wrapRGB.value.copy( material.wrapRGB );

        }

    };

    function refreshUniformsLambert ( uniforms, material ) {

        if ( _this.gammaInput ) {

            uniforms.ambient.value.copyGammaToLinear( material.ambient );
            uniforms.emissive.value.copyGammaToLinear( material.emissive );

        } else {

            uniforms.ambient.value = material.ambient;
            uniforms.emissive.value = material.emissive;

        }

        if ( material.wrapAround ) {

            uniforms.wrapRGB.value.copy( material.wrapRGB );

        }

    };

    function refreshUniformsLights ( uniforms, lights ) {

        uniforms.ambientLightColor.value = lights.ambient;

        uniforms.directionalLightColor.value = lights.directional.colors;
        uniforms.directionalLightDirection.value = lights.directional.positions;

        uniforms.pointLightColor.value = lights.point.colors;
        uniforms.pointLightPosition.value = lights.point.positions;
        uniforms.pointLightDistance.value = lights.point.distances;

        uniforms.spotLightColor.value = lights.spot.colors;
        uniforms.spotLightPosition.value = lights.spot.positions;
        uniforms.spotLightDistance.value = lights.spot.distances;
        uniforms.spotLightDirection.value = lights.spot.directions;
        uniforms.spotLightAngle.value = lights.spot.angles;
        uniforms.spotLightExponent.value = lights.spot.exponents;

        uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
        uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
        uniforms.hemisphereLightPosition.value = lights.hemi.positions;

    };

    function refreshUniformsShadow ( uniforms, lights ) {

        if ( uniforms.shadowMatrix ) {

            var j = 0;

            for ( var i = 0, il = lights.length; i < il; i ++ ) {

                var light = lights[ i ];

                if ( ! light.castShadow ) continue;

                if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {

                    uniforms.shadowMap.value[ j ] = light.shadowMap;
                    uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;

                    uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;

                    uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
                    uniforms.shadowBias.value[ j ] = light.shadowBias;

                    j ++;

                }

            }

        }

    };

    // Uniforms (load to GPU)

    function loadUniformsMatrices ( uniforms, object ) {

        _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );

        if ( uniforms.normalMatrix ) {

            _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );

        }

    };

    function getTextureUnit() {

        var textureUnit = _usedTextureUnits;

        if ( textureUnit >= _maxTextures ) {

            console.warn( "Trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures );

        }

        _usedTextureUnits += 1;

        return textureUnit;

    };

    function loadUniformsGeneric ( program, uniforms ) {

        var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset;

        for ( j = 0, jl = uniforms.length; j < jl; j ++ ) {

            location = program.uniforms[ uniforms[ j ][ 1 ] ];
            if ( !location ) continue;

            uniform = uniforms[ j ][ 0 ];

            type = uniform.type;
            value = uniform.value;

            if ( type === "i" ) { // single integer

                _gl.uniform1i( location, value );

            } else if ( type === "f" ) { // single float

                _gl.uniform1f( location, value );

            } else if ( type === "v2" ) { // single THREE.Vector2

                _gl.uniform2f( location, value.x, value.y );

            } else if ( type === "v3" ) { // single THREE.Vector3

                _gl.uniform3f( location, value.x, value.y, value.z );

            } else if ( type === "v4" ) { // single THREE.Vector4

                _gl.uniform4f( location, value.x, value.y, value.z, value.w );

            } else if ( type === "c" ) { // single THREE.Color

                _gl.uniform3f( location, value.r, value.g, value.b );

            } else if ( type === "iv1" ) { // flat array of integers (JS or typed array)

                _gl.uniform1iv( location, value );

            } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array)

                _gl.uniform3iv( location, value );

            } else if ( type === "fv1" ) { // flat array of floats (JS or typed array)

                _gl.uniform1fv( location, value );

            } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array)

                _gl.uniform3fv( location, value );

            } else if ( type === "v2v" ) { // array of THREE.Vector2

                if ( uniform._array === undefined ) {

                    uniform._array = new Float32Array( 2 * value.length );

                }

                for ( i = 0, il = value.length; i < il; i ++ ) {

                    offset = i * 2;

                    uniform._array[ offset ]      = value[ i ].x;
                    uniform._array[ offset + 1 ] = value[ i ].y;

                }

                _gl.uniform2fv( location, uniform._array );

            } else if ( type === "v3v" ) { // array of THREE.Vector3

                if ( uniform._array === undefined ) {

                    uniform._array = new Float32Array( 3 * value.length );

                }

                for ( i = 0, il = value.length; i < il; i ++ ) {

                    offset = i * 3;

                    uniform._array[ offset ]      = value[ i ].x;
                    uniform._array[ offset + 1 ] = value[ i ].y;
                    uniform._array[ offset + 2 ] = value[ i ].z;

                }

                _gl.uniform3fv( location, uniform._array );

            } else if ( type === "v4v" ) { // array of THREE.Vector4

                if ( uniform._array === undefined ) {

                    uniform._array = new Float32Array( 4 * value.length );

                }

                for ( i = 0, il = value.length; i < il; i ++ ) {

                    offset = i * 4;

                    uniform._array[ offset ]      = value[ i ].x;
                    uniform._array[ offset + 1 ] = value[ i ].y;
                    uniform._array[ offset + 2 ] = value[ i ].z;
                    uniform._array[ offset + 3 ] = value[ i ].w;

                }

                _gl.uniform4fv( location, uniform._array );

            } else if ( type === "m4") { // single THREE.Matrix4

                if ( uniform._array === undefined ) {

                    uniform._array = new Float32Array( 16 );

                }

                value.flattenToArray( uniform._array );
                _gl.uniformMatrix4fv( location, false, uniform._array );

            } else if ( type === "m4v" ) { // array of THREE.Matrix4

                if ( uniform._array === undefined ) {

                    uniform._array = new Float32Array( 16 * value.length );

                }

                for ( i = 0, il = value.length; i < il; i ++ ) {

                    value[ i ].flattenToArrayOffset( uniform._array, i * 16 );

                }

                _gl.uniformMatrix4fv( location, false, uniform._array );

            } else if ( type === "t" ) { // single THREE.Texture (2d or cube)

                texture = value;
                textureUnit = getTextureUnit();

                _gl.uniform1i( location, textureUnit );

                if ( !texture ) continue;

                if ( texture.image instanceof Array && texture.image.length === 6 ) {

                    setCubeTexture( texture, textureUnit );

                } else if ( texture instanceof THREE.WebGLRenderTargetCube ) {

                    setCubeTextureDynamic( texture, textureUnit );

                } else {

                    _this.setTexture( texture, textureUnit );

                }

            } else if ( type === "tv" ) { // array of THREE.Texture (2d)

                if ( uniform._array === undefined ) {

                    uniform._array = [];

                }

                for( i = 0, il = uniform.value.length; i < il; i ++ ) {

                    uniform._array[ i ] = getTextureUnit();

                }

                _gl.uniform1iv( location, uniform._array );

                for( i = 0, il = uniform.value.length; i < il; i ++ ) {

                    texture = uniform.value[ i ];
                    textureUnit = uniform._array[ i ];

                    if ( !texture ) continue;

                    _this.setTexture( texture, textureUnit );

                }

            }

        }

    };

    function setupMatrices ( object, camera ) {

        object._modelViewMatrix.multiply( camera.matrixWorldInverse, object.matrixWorld );

        object._normalMatrix.getInverse( object._modelViewMatrix );
        object._normalMatrix.transpose();

    };

    //

    function setColorGamma( array, offset, color, intensitySq ) {

        array[ offset ]     = color.r * color.r * intensitySq;
        array[ offset + 1 ] = color.g * color.g * intensitySq;
        array[ offset + 2 ] = color.b * color.b * intensitySq;

    };

    function setColorLinear( array, offset, color, intensity ) {

        array[ offset ]     = color.r * intensity;
        array[ offset + 1 ] = color.g * intensity;
        array[ offset + 2 ] = color.b * intensity;

    };

    function setupLights ( program, lights ) {

        var l, ll, light, n,
        r = 0, g = 0, b = 0,
        color, skyColor, groundColor,
        intensity,  intensitySq,
        position,
        distance,

        zlights = _lights,

        dirColors = zlights.directional.colors,
        dirPositions = zlights.directional.positions,

        pointColors = zlights.point.colors,
        pointPositions = zlights.point.positions,
        pointDistances = zlights.point.distances,

        spotColors = zlights.spot.colors,
        spotPositions = zlights.spot.positions,
        spotDistances = zlights.spot.distances,
        spotDirections = zlights.spot.directions,
        spotAngles = zlights.spot.angles,
        spotExponents = zlights.spot.exponents,

        hemiSkyColors = zlights.hemi.skyColors,
        hemiGroundColors = zlights.hemi.groundColors,
        hemiPositions = zlights.hemi.positions,

        dirLength = 0,
        pointLength = 0,
        spotLength = 0,
        hemiLength = 0,

        dirOffset = 0,
        pointOffset = 0,
        spotOffset = 0,
        hemiOffset = 0;

        for ( l = 0, ll = lights.length; l < ll; l ++ ) {

            light = lights[ l ];

            if ( light.onlyShadow || ! light.visible ) continue;

            color = light.color;
            intensity = light.intensity;
            distance = light.distance;

            if ( light instanceof THREE.AmbientLight ) {

                if ( _this.gammaInput ) {

                    r += color.r * color.r;
                    g += color.g * color.g;
                    b += color.b * color.b;

                } else {

                    r += color.r;
                    g += color.g;
                    b += color.b;

                }

            } else if ( light instanceof THREE.DirectionalLight ) {

                dirOffset = dirLength * 3;

                if ( _this.gammaInput ) {

                    setColorGamma( dirColors, dirOffset, color, intensity * intensity );

                } else {

                    setColorLinear( dirColors, dirOffset, color, intensity );

                }

                _direction.copy( light.matrixWorld.getPosition() );
                _direction.subSelf( light.target.matrixWorld.getPosition() );
                _direction.normalize();

                dirPositions[ dirOffset ]     = _direction.x;
                dirPositions[ dirOffset + 1 ] = _direction.y;
                dirPositions[ dirOffset + 2 ] = _direction.z;

                dirLength += 1;

            } else if( light instanceof THREE.PointLight ) {

                pointOffset = pointLength * 3;

                if ( _this.gammaInput ) {

                    setColorGamma( pointColors, pointOffset, color, intensity * intensity );

                } else {

                    setColorLinear( pointColors, pointOffset, color, intensity );

                }

                position = light.matrixWorld.getPosition();

                pointPositions[ pointOffset ]     = position.x;
                pointPositions[ pointOffset + 1 ] = position.y;
                pointPositions[ pointOffset + 2 ] = position.z;

                pointDistances[ pointLength ] = distance;

                pointLength += 1;

            } else if( light instanceof THREE.SpotLight ) {

                spotOffset = spotLength * 3;

                if ( _this.gammaInput ) {

                    setColorGamma( spotColors, spotOffset, color, intensity * intensity );

                } else {

                    setColorLinear( spotColors, spotOffset, color, intensity );

                }

                position = light.matrixWorld.getPosition();

                spotPositions[ spotOffset ]     = position.x;
                spotPositions[ spotOffset + 1 ] = position.y;
                spotPositions[ spotOffset + 2 ] = position.z;

                spotDistances[ spotLength ] = distance;

                _direction.copy( position );
                _direction.subSelf( light.target.matrixWorld.getPosition() );
                _direction.normalize();

                spotDirections[ spotOffset ]     = _direction.x;
                spotDirections[ spotOffset + 1 ] = _direction.y;
                spotDirections[ spotOffset + 2 ] = _direction.z;

                spotAngles[ spotLength ] = Math.cos( light.angle );
                spotExponents[ spotLength ] = light.exponent;

                spotLength += 1;

            } else if ( light instanceof THREE.HemisphereLight ) {

                skyColor = light.color;
                groundColor = light.groundColor;

                hemiOffset = hemiLength * 3;

                if ( _this.gammaInput ) {

                    intensitySq = intensity * intensity;

                    setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq );
                    setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq );

                } else {

                    setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
                    setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );

                }

                position = light.matrixWorld.getPosition();

                hemiPositions[ hemiOffset ]     = position.x;
                hemiPositions[ hemiOffset + 1 ] = position.y;
                hemiPositions[ hemiOffset + 2 ] = position.z;

                hemiLength += 1;

            }

        }

        // null eventual remains from removed lights
        // (this is to avoid if in shader)

        for ( l = dirLength * 3, ll = dirColors.length; l < ll; l ++ ) dirColors[ l ] = 0.0;
        for ( l = pointLength * 3, ll = pointColors.length; l < ll; l ++ ) pointColors[ l ] = 0.0;
        for ( l = spotLength * 3, ll = spotColors.length; l < ll; l ++ ) spotColors[ l ] = 0.0;
        for ( l = hemiLength * 3, ll = hemiSkyColors.length; l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
        for ( l = hemiLength * 3, ll = hemiGroundColors.length; l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;

        zlights.directional.length = dirLength;
        zlights.point.length = pointLength;
        zlights.spot.length = spotLength;
        zlights.hemi.length = hemiLength;

        zlights.ambient[ 0 ] = r;
        zlights.ambient[ 1 ] = g;
        zlights.ambient[ 2 ] = b;

    };

    // GL state setting

    this.setFaceCulling = function ( cullFace, frontFace ) {

        if ( cullFace ) {

            if ( !frontFace || frontFace === "ccw" ) {

                _gl.frontFace( _gl.CCW );

            } else {

                _gl.frontFace( _gl.CW );

            }

            if( cullFace === "back" ) {

                _gl.cullFace( _gl.BACK );

            } else if( cullFace === "front" ) {

                _gl.cullFace( _gl.FRONT );

            } else {

                _gl.cullFace( _gl.FRONT_AND_BACK );

            }

            _gl.enable( _gl.CULL_FACE );

        } else {

            _gl.disable( _gl.CULL_FACE );

        }

    };

    this.setMaterialFaces = function ( material ) {

        var doubleSided = material.side === THREE.DoubleSide;
        var flipSided = material.side === THREE.BackSide;

        if ( _oldDoubleSided !== doubleSided ) {

            if ( doubleSided ) {

                _gl.disable( _gl.CULL_FACE );

            } else {

                _gl.enable( _gl.CULL_FACE );

            }

            _oldDoubleSided = doubleSided;

        }

        if ( _oldFlipSided !== flipSided ) {

            if ( flipSided ) {

                _gl.frontFace( _gl.CW );

            } else {

                _gl.frontFace( _gl.CCW );

            }

            _oldFlipSided = flipSided;

        }

    };

    this.setDepthTest = function ( depthTest ) {

        if ( _oldDepthTest !== depthTest ) {

            if ( depthTest ) {

                _gl.enable( _gl.DEPTH_TEST );

            } else {

                _gl.disable( _gl.DEPTH_TEST );

            }

            _oldDepthTest = depthTest;

        }

    };

    this.setDepthWrite = function ( depthWrite ) {

        if ( _oldDepthWrite !== depthWrite ) {

            _gl.depthMask( depthWrite );
            _oldDepthWrite = depthWrite;

        }

    };

    function setLineWidth ( width ) {

        if ( width !== _oldLineWidth ) {

            _gl.lineWidth( width );

            _oldLineWidth = width;

        }

    };

    function setPolygonOffset ( polygonoffset, factor, units ) {

        if ( _oldPolygonOffset !== polygonoffset ) {

            if ( polygonoffset ) {

                _gl.enable( _gl.POLYGON_OFFSET_FILL );

            } else {

                _gl.disable( _gl.POLYGON_OFFSET_FILL );

            }

            _oldPolygonOffset = polygonoffset;

        }

        if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {

            _gl.polygonOffset( factor, units );

            _oldPolygonOffsetFactor = factor;
            _oldPolygonOffsetUnits = units;

        }

    };

    this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) {

        if ( blending !== _oldBlending ) {

            if ( blending === THREE.NoBlending ) {

                _gl.disable( _gl.BLEND );

            } else if ( blending === THREE.AdditiveBlending ) {

                _gl.enable( _gl.BLEND );
                _gl.blendEquation( _gl.FUNC_ADD );
                _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );

            } else if ( blending === THREE.SubtractiveBlending ) {

                // TODO: Find blendFuncSeparate() combination
                _gl.enable( _gl.BLEND );
                _gl.blendEquation( _gl.FUNC_ADD );
                _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );

            } else if ( blending === THREE.MultiplyBlending ) {

                // TODO: Find blendFuncSeparate() combination
                _gl.enable( _gl.BLEND );
                _gl.blendEquation( _gl.FUNC_ADD );
                _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );

            } else if ( blending === THREE.CustomBlending ) {

                _gl.enable( _gl.BLEND );

            } else {

                _gl.enable( _gl.BLEND );
                _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
                _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );

            }

            _oldBlending = blending;

        }

        if ( blending === THREE.CustomBlending ) {

            if ( blendEquation !== _oldBlendEquation ) {

                _gl.blendEquation( paramThreeToGL( blendEquation ) );

                _oldBlendEquation = blendEquation;

            }

            if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) {

                _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) );

                _oldBlendSrc = blendSrc;
                _oldBlendDst = blendDst;

            }

        } else {

            _oldBlendEquation = null;
            _oldBlendSrc = null;
            _oldBlendDst = null;

        }

    };

    // Shaders

    function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, parameters ) {

        var p, pl, program, code;
        var chunks = [];

        // Generate code

        if ( shaderID ) {

            chunks.push( shaderID );

        } else {

            chunks.push( fragmentShader );
            chunks.push( vertexShader );

        }

        for ( p in parameters ) {

            chunks.push( p );
            chunks.push( parameters[ p ] );

        }

        code = chunks.join();

        // Check if code has been already compiled

        for ( p = 0, pl = _programs.length; p < pl; p ++ ) {

            var programInfo = _programs[ p ];

            if ( programInfo.code === code ) {

                // console.log( "Code already compiled." /*: \n\n" + code*/ );

                programInfo.usedTimes ++;

                return programInfo.program;

            }

        }

        //console.log( "building new program " );

        //

        program = _gl.createProgram();

        var prefix_vertex = [

            "precision " + _precision + " float;",

            _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",

            _this.gammaInput ? "#define GAMMA_INPUT" : "",
            _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
            _this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",

            "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
            "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
            "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
            "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,

            "#define MAX_SHADOWS " + parameters.maxShadows,

            "#define MAX_BONES " + parameters.maxBones,

            parameters.map ? "#define USE_MAP" : "",
            parameters.envMap ? "#define USE_ENVMAP" : "",
            parameters.lightMap ? "#define USE_LIGHTMAP" : "",
            parameters.bumpMap ? "#define USE_BUMPMAP" : "",
            parameters.normalMap ? "#define USE_NORMALMAP" : "",
            parameters.specularMap ? "#define USE_SPECULARMAP" : "",
            parameters.vertexColors ? "#define USE_COLOR" : "",

            parameters.skinning ? "#define USE_SKINNING" : "",
            parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
            parameters.boneTextureWidth ? "#define N_BONE_PIXEL_X " + parameters.boneTextureWidth.toFixed( 1 ) : "",
            parameters.boneTextureHeight ? "#define N_BONE_PIXEL_Y " + parameters.boneTextureHeight.toFixed( 1 ) : "",

            parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
            parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
            parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
            parameters.wrapAround ? "#define WRAP_AROUND" : "",
            parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
            parameters.flipSided ? "#define FLIP_SIDED" : "",

            parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
            parameters.shadowMapSoft ? "#define SHADOWMAP_SOFT" : "",
            parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
            parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",

            parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",

            "uniform mat4 modelMatrix;",
            "uniform mat4 modelViewMatrix;",
            "uniform mat4 projectionMatrix;",
            "uniform mat4 viewMatrix;",
            "uniform mat3 normalMatrix;",
            "uniform vec3 cameraPosition;",

            "attribute vec3 position;",
            "attribute vec3 normal;",
            "attribute vec2 uv;",
            "attribute vec2 uv2;",

            "#ifdef USE_COLOR",

                "attribute vec3 color;",

            "#endif",

            "#ifdef USE_MORPHTARGETS",

                "attribute vec3 morphTarget0;",
                "attribute vec3 morphTarget1;",
                "attribute vec3 morphTarget2;",
                "attribute vec3 morphTarget3;",

                "#ifdef USE_MORPHNORMALS",

                    "attribute vec3 morphNormal0;",
                    "attribute vec3 morphNormal1;",
                    "attribute vec3 morphNormal2;",
                    "attribute vec3 morphNormal3;",

                "#else",

                    "attribute vec3 morphTarget4;",
                    "attribute vec3 morphTarget5;",
                    "attribute vec3 morphTarget6;",
                    "attribute vec3 morphTarget7;",

                "#endif",

            "#endif",

            "#ifdef USE_SKINNING",

                "attribute vec4 skinIndex;",
                "attribute vec4 skinWeight;",

            "#endif",

            ""

        ].join("\n");

        var prefix_fragment = [

            "precision " + _precision + " float;",

            ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",

            "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
            "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
            "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
            "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,

            "#define MAX_SHADOWS " + parameters.maxShadows,

            parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",

            _this.gammaInput ? "#define GAMMA_INPUT" : "",
            _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
            _this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",

            ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
            ( parameters.useFog && parameters.fog instanceof THREE.FogExp2 ) ? "#define FOG_EXP2" : "",

            parameters.map ? "#define USE_MAP" : "",
            parameters.envMap ? "#define USE_ENVMAP" : "",
            parameters.lightMap ? "#define USE_LIGHTMAP" : "",
            parameters.bumpMap ? "#define USE_BUMPMAP" : "",
            parameters.normalMap ? "#define USE_NORMALMAP" : "",
            parameters.specularMap ? "#define USE_SPECULARMAP" : "",
            parameters.vertexColors ? "#define USE_COLOR" : "",

            parameters.metal ? "#define METAL" : "",
            parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
            parameters.wrapAround ? "#define WRAP_AROUND" : "",
            parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
            parameters.flipSided ? "#define FLIP_SIDED" : "",

            parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
            parameters.shadowMapSoft ? "#define SHADOWMAP_SOFT" : "",
            parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
            parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",

            "uniform mat4 viewMatrix;",
            "uniform vec3 cameraPosition;",
            ""

        ].join("\n");

        var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
        var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );

        _gl.attachShader( program, glVertexShader );
        _gl.attachShader( program, glFragmentShader );

        _gl.linkProgram( program );

        if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {

            console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );

        }

        // clean up

        _gl.deleteShader( glFragmentShader );
        _gl.deleteShader( glVertexShader );

        //console.log( prefix_fragment + fragmentShader );
        //console.log( prefix_vertex + vertexShader );

        program.uniforms = {};
        program.attributes = {};

        var identifiers, u, a, i;

        // cache uniform locations

        identifiers = [

            'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
            'morphTargetInfluences'

        ];

        if ( parameters.useVertexTexture ) {

            identifiers.push( 'boneTexture' );

        } else {

            identifiers.push( 'boneGlobalMatrices' );

        }

        for ( u in uniforms ) {

            identifiers.push( u );

        }

        cacheUniformLocations( program, identifiers );

        // cache attributes locations

        identifiers = [

            "position", "normal", "uv", "uv2", "tangent", "color",
            "skinIndex", "skinWeight"

        ];

        for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {

            identifiers.push( "morphTarget" + i );

        }

        for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {

            identifiers.push( "morphNormal" + i );

        }

        for ( a in attributes ) {

            identifiers.push( a );

        }

        cacheAttributeLocations( program, identifiers );

        program.id = _programs_counter ++;

        _programs.push( { program: program, code: code, usedTimes: 1 } );

        _this.info.memory.programs = _programs.length;

        return program;

    };

    // Shader parameters cache

    function cacheUniformLocations ( program, identifiers ) {

        var i, l, id;

        for( i = 0, l = identifiers.length; i < l; i ++ ) {

            id = identifiers[ i ];
            program.uniforms[ id ] = _gl.getUniformLocation( program, id );

        }

    };

    function cacheAttributeLocations ( program, identifiers ) {

        var i, l, id;

        for( i = 0, l = identifiers.length; i < l; i ++ ) {

            id = identifiers[ i ];
            program.attributes[ id ] = _gl.getAttribLocation( program, id );

        }

    };

    function addLineNumbers ( string ) {

        var chunks = string.split( "\n" );

        for ( var i = 0, il = chunks.length; i < il; i ++ ) {

            // Chrome reports shader errors on lines
            // starting counting from 1

            chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ];

        }

        return chunks.join( "\n" );

    };

    function getShader ( type, string ) {

        var shader;

        if ( type === "fragment" ) {

            shader = _gl.createShader( _gl.FRAGMENT_SHADER );

        } else if ( type === "vertex" ) {

            shader = _gl.createShader( _gl.VERTEX_SHADER );

        }

        _gl.shaderSource( shader, string );
        _gl.compileShader( shader );

        if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {

            console.error( _gl.getShaderInfoLog( shader ) );
            console.error( addLineNumbers( string ) );
            return null;

        }

        return shader;

    };

    // Textures


    function isPowerOfTwo ( value ) {

        return ( value & ( value - 1 ) ) === 0;

    };

    function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {

        if ( isImagePowerOfTwo ) {

            _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
            _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );

            _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
            _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );

        } else {

            _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
            _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );

            _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
            _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );

        }

        if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {

            if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {

                _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
                texture.__oldAnisotropy = texture.anisotropy;

            }

        }

    };

    this.setTexture = function ( texture, slot ) {

        if ( texture.needsUpdate ) {

            if ( ! texture.__webglInit ) {

                texture.__webglInit = true;
                texture.__webglTexture = _gl.createTexture();

                _this.info.memory.textures ++;

            }

            _gl.activeTexture( _gl.TEXTURE0 + slot );
            _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );

            _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
            _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );

            var image = texture.image,
            isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
            glFormat = paramThreeToGL( texture.format ),
            glType = paramThreeToGL( texture.type );

            setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );

            if ( texture instanceof THREE.CompressedTexture ) {

                var mipmap, mipmaps = texture.mipmaps;

                for( var i = 0, il = mipmaps.length; i < il; i ++ ) {

                    mipmap = mipmaps[ i ];
                    _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                }

            } else if ( texture instanceof THREE.DataTexture ) {

                _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );

            } else {

                _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );

            }

            if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );

            texture.needsUpdate = false;

            if ( texture.onUpdate ) texture.onUpdate();

        } else {

            _gl.activeTexture( _gl.TEXTURE0 + slot );
            _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );

        }

    };

    function clampToMaxSize ( image, maxSize ) {

        if ( image.width <= maxSize && image.height <= maxSize ) {

            return image;

        }

        // Warning: Scaling through the canvas will only work with images that use
        // premultiplied alpha.

        var maxDimension = Math.max( image.width, image.height );
        var newWidth = Math.floor( image.width * maxSize / maxDimension );
        var newHeight = Math.floor( image.height * maxSize / maxDimension );

        var canvas = document.createElement( 'canvas' );
        canvas.width = newWidth;
        canvas.height = newHeight;

        var ctx = canvas.getContext( "2d" );
        ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );

        return canvas;

    }

    function setCubeTexture ( texture, slot ) {

        if ( texture.image.length === 6 ) {

            if ( texture.needsUpdate ) {

                if ( ! texture.image.__webglTextureCube ) {

                    texture.image.__webglTextureCube = _gl.createTexture();

                }

                _gl.activeTexture( _gl.TEXTURE0 + slot );
                _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );

                _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );

                var isCompressed = texture instanceof THREE.CompressedTexture;

                var cubeImage = [];

                for ( var i = 0; i < 6; i ++ ) {

                    if ( _this.autoScaleCubemaps && ! isCompressed ) {

                        cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );

                    } else {

                        cubeImage[ i ] = texture.image[ i ];

                    }

                }

                var image = cubeImage[ 0 ],
                isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
                glFormat = paramThreeToGL( texture.format ),
                glType = paramThreeToGL( texture.type );

                setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );

                for ( var i = 0; i < 6; i ++ ) {

                    if ( isCompressed ) {

                        var mipmap, mipmaps = cubeImage[ i ].mipmaps;

                        for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {

                            mipmap = mipmaps[ j ];
                            _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                        }

                    } else {

                        _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );

                    }

                }

                if ( texture.generateMipmaps && isImagePowerOfTwo ) {

                    _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );

                }

                texture.needsUpdate = false;

                if ( texture.onUpdate ) texture.onUpdate();

            } else {

                _gl.activeTexture( _gl.TEXTURE0 + slot );
                _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );

            }

        }

    };

    function setCubeTextureDynamic ( texture, slot ) {

        _gl.activeTexture( _gl.TEXTURE0 + slot );
        _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );

    };

    // Render targets

    function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {

        _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
        _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );

    };

    function setupRenderBuffer ( renderbuffer, renderTarget  ) {

        _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );

        if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {

            _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
            _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );

        /* For some reason this is not working. Defaulting to RGBA4.
        } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {

            _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
            _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
        */
        } else if( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {

            _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
            _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );

        } else {

            _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );

        }

    };

    this.setRenderTarget = function ( renderTarget ) {

        var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );

        if ( renderTarget && ! renderTarget.__webglFramebuffer ) {

            if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
            if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;

            renderTarget.__webglTexture = _gl.createTexture();

            // Setup texture, create render and frame buffers

            var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ),
                glFormat = paramThreeToGL( renderTarget.format ),
                glType = paramThreeToGL( renderTarget.type );

            if ( isCube ) {

                renderTarget.__webglFramebuffer = [];
                renderTarget.__webglRenderbuffer = [];

                _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
                setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );

                for ( var i = 0; i < 6; i ++ ) {

                    renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
                    renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();

                    _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );

                    setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
                    setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );

                }

                if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );

            } else {

                renderTarget.__webglFramebuffer = _gl.createFramebuffer();
                renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();

                _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
                setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );

                _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );

                setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
                setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );

                if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );

            }

            // Release everything

            if ( isCube ) {

                _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );

            } else {

                _gl.bindTexture( _gl.TEXTURE_2D, null );

            }

            _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
            _gl.bindFramebuffer( _gl.FRAMEBUFFER, null);

        }

        var framebuffer, width, height, vx, vy;

        if ( renderTarget ) {

            if ( isCube ) {

                framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];

            } else {

                framebuffer = renderTarget.__webglFramebuffer;

            }

            width = renderTarget.width;
            height = renderTarget.height;

            vx = 0;
            vy = 0;

        } else {

            framebuffer = null;

            width = _viewportWidth;
            height = _viewportHeight;

            vx = _viewportX;
            vy = _viewportY;

        }

        if ( framebuffer !== _currentFramebuffer ) {

            _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
            _gl.viewport( vx, vy, width, height );

            _currentFramebuffer = framebuffer;

        }

        _currentWidth = width;
        _currentHeight = height;

    };

    function updateRenderTargetMipmap ( renderTarget ) {

        if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {

            _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
            _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
            _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );

        } else {

            _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
            _gl.generateMipmap( _gl.TEXTURE_2D );
            _gl.bindTexture( _gl.TEXTURE_2D, null );

        }

    };

    // Fallback filters for non-power-of-2 textures

    function filterFallback ( f ) {

        if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {

            return _gl.NEAREST;

        }

        return _gl.LINEAR;

    };

    // Map three.js constants to WebGL constants

    function paramThreeToGL ( p ) {

        if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
        if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
        if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;

        if ( p === THREE.NearestFilter ) return _gl.NEAREST;
        if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
        if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;

        if ( p === THREE.LinearFilter ) return _gl.LINEAR;
        if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
        if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;

        if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
        if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
        if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
        if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;

        if ( p === THREE.ByteType ) return _gl.BYTE;
        if ( p === THREE.ShortType ) return _gl.SHORT;
        if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
        if ( p === THREE.IntType ) return _gl.INT;
        if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
        if ( p === THREE.FloatType ) return _gl.FLOAT;

        if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
        if ( p === THREE.RGBFormat ) return _gl.RGB;
        if ( p === THREE.RGBAFormat ) return _gl.RGBA;
        if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
        if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;

        if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
        if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
        if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;

        if ( p === THREE.ZeroFactor ) return _gl.ZERO;
        if ( p === THREE.OneFactor ) return _gl.ONE;
        if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
        if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
        if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
        if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
        if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
        if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;

        if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
        if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
        if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;

        if ( _glExtensionCompressedTextureS3TC !== undefined ) {

            if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
            if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
            if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
            if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;

        }

        return 0;

    };

    // Allocations

    function allocateBones ( object ) {

        if ( _supportsBoneTextures && object && object.useVertexTexture ) {

            return 1024;

        } else {

            // default for when object is not specified
            // ( for example when prebuilding shader
            //   to be used with multiple objects )
            //
            //     - leave some extra space for other uniforms
            //  - limit here is ANGLE's 254 max uniform vectors
            //    (up to 54 should be safe)

            var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
            var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );

            var maxBones = nVertexMatrices;

            if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {

                maxBones = Math.min( object.bones.length, maxBones );

                if ( maxBones < object.bones.length ) {

                    console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );

                }

            }

            return maxBones;

        }

    };

    function allocateLights ( lights ) {

        var l, ll, light, dirLights, pointLights, spotLights, hemiLights, maxDirLights, maxPointLights, maxSpotLights, maxHemiLights;

        dirLights = pointLights = spotLights = hemiLights = maxDirLights = maxPointLights = maxSpotLights = maxHemiLights = 0;

        for ( l = 0, ll = lights.length; l < ll; l ++ ) {

            light = lights[ l ];

            if ( light.onlyShadow ) continue;

            if ( light instanceof THREE.DirectionalLight ) dirLights ++;
            if ( light instanceof THREE.PointLight ) pointLights ++;
            if ( light instanceof THREE.SpotLight ) spotLights ++;
            if ( light instanceof THREE.HemisphereLight ) hemiLights ++;

        }

        if ( ( pointLights + spotLights + dirLights + hemiLights) <= _maxLights ) {

            maxDirLights = dirLights;
            maxPointLights = pointLights;
            maxSpotLights = spotLights;
            maxHemiLights = hemiLights;

        } else {

            maxDirLights = Math.ceil( _maxLights * dirLights / ( pointLights + dirLights ) );
            maxPointLights = _maxLights - maxDirLights;

            // these are not really correct

            maxSpotLights = maxPointLights;
            maxHemiLights = maxDirLights;

        }

        return { 'directional' : maxDirLights, 'point' : maxPointLights, 'spot': maxSpotLights, 'hemi': maxHemiLights };

    };

    function allocateShadows ( lights ) {

        var l, ll, light, maxShadows = 0;

        for ( l = 0, ll = lights.length; l < ll; l++ ) {

            light = lights[ l ];

            if ( ! light.castShadow ) continue;

            if ( light instanceof THREE.SpotLight ) maxShadows ++;
            if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;

        }

        return maxShadows;

    };

    // Initialization

    function initGL () {

        try {

            if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) {

                throw 'Error creating WebGL context.';

            }

        } catch ( error ) {

            console.error( error );

        }

        _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
        _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );

        _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) ||
                                               _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) ||
                                               _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );


        _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) ||
                                            _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) ||
                                            _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );

        if ( ! _glExtensionTextureFloat ) {

            console.log( 'THREE.WebGLRenderer: Float textures not supported.' );

        }

        if ( ! _glExtensionStandardDerivatives ) {

            console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );

        }

        if ( ! _glExtensionTextureFilterAnisotropic ) {

            console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );

        }

        if ( ! _glExtensionCompressedTextureS3TC ) {

            console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );

        }

    };

    function setDefaultGLState () {

        _gl.clearColor( 0, 0, 0, 1 );
        _gl.clearDepth( 1 );
        _gl.clearStencil( 0 );

        _gl.enable( _gl.DEPTH_TEST );
        _gl.depthFunc( _gl.LEQUAL );

        _gl.frontFace( _gl.CCW );
        _gl.cullFace( _gl.BACK );
        _gl.enable( _gl.CULL_FACE );

        _gl.enable( _gl.BLEND );
        _gl.blendEquation( _gl.FUNC_ADD );
        _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );

        _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );

    };

    // default plugins (order is important)

    this.shadowMapPlugin = new THREE.ShadowMapPlugin();
    this.addPrePlugin( this.shadowMapPlugin );

    this.addPostPlugin( new THREE.SpritePlugin() );
    this.addPostPlugin( new THREE.LensFlarePlugin() );

};
/**
 * @author szimek / https://github.com/szimek/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.WebGLRenderTarget = function ( width, height, options ) {

    this.width = width;
    this.height = height;

    options = options || {};

    this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping;
    this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping;

    this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter;
    this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter;

    this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1;

    this.offset = new THREE.Vector2( 0, 0 );
    this.repeat = new THREE.Vector2( 1, 1 );

    this.format = options.format !== undefined ? options.format : THREE.RGBAFormat;
    this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;

    this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
    this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;

    this.generateMipmaps = true;

};

THREE.WebGLRenderTarget.prototype.clone = function() {

    var tmp = new THREE.WebGLRenderTarget( this.width, this.height );

    tmp.wrapS = this.wrapS;
    tmp.wrapT = this.wrapT;

    tmp.magFilter = this.magFilter;
    tmp.anisotropy = this.anisotropy;

    tmp.minFilter = this.minFilter;

    tmp.offset.copy( this.offset );
    tmp.repeat.copy( this.repeat );

    tmp.format = this.format;
    tmp.type = this.type;

    tmp.depthBuffer = this.depthBuffer;
    tmp.stencilBuffer = this.stencilBuffer;

    tmp.generateMipmaps = this.generateMipmaps;

    return tmp;

};
/**
 * @author alteredq / http://alteredqualia.com
 */

THREE.WebGLRenderTargetCube = function ( width, height, options ) {

    THREE.WebGLRenderTarget.call( this, width, height, options );

    this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5

};

THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RenderableVertex = function () {

    this.positionWorld = new THREE.Vector3();
    this.positionScreen = new THREE.Vector4();

    this.visible = true;

};

THREE.RenderableVertex.prototype.copy = function ( vertex ) {

    this.positionWorld.copy( vertex.positionWorld );
    this.positionScreen.copy( vertex.positionScreen );

}
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RenderableFace3 = function () {

    this.v1 = new THREE.RenderableVertex();
    this.v2 = new THREE.RenderableVertex();
    this.v3 = new THREE.RenderableVertex();

    this.centroidWorld = new THREE.Vector3();
    this.centroidScreen = new THREE.Vector3();

    this.normalWorld = new THREE.Vector3();
    this.vertexNormalsWorld = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
    this.vertexNormalsLength = 0;

    this.material = null;
    this.uvs = [[]];

    this.z = null;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RenderableFace4 = function () {

    this.v1 = new THREE.RenderableVertex();
    this.v2 = new THREE.RenderableVertex();
    this.v3 = new THREE.RenderableVertex();
    this.v4 = new THREE.RenderableVertex();

    this.centroidWorld = new THREE.Vector3();
    this.centroidScreen = new THREE.Vector3();

    this.normalWorld = new THREE.Vector3();
    this.vertexNormalsWorld = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
    this.vertexNormalsLength = 0;

    this.material = null;
    this.uvs = [[]];

    this.z = null;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RenderableObject = function () {

    this.object = null;
    this.z = null;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RenderableParticle = function () {

    this.object = null;

    this.x = null;
    this.y = null;
    this.z = null;

    this.rotation = null;
    this.scale = new THREE.Vector2();

    this.material = null;

};
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.RenderableLine = function () {

    this.z = null;

    this.v1 = new THREE.RenderableVertex();
    this.v2 = new THREE.RenderableVertex();

    this.material = null;

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.ColorUtils = {

    adjustHSV : function ( color, h, s, v ) {

        var hsv = THREE.ColorUtils.__hsv;

        THREE.ColorUtils.rgbToHsv( color, hsv );

        hsv.h = THREE.Math.clamp( hsv.h + h, 0, 1 );
        hsv.s = THREE.Math.clamp( hsv.s + s, 0, 1 );
        hsv.v = THREE.Math.clamp( hsv.v + v, 0, 1 );

        color.setHSV( hsv.h, hsv.s, hsv.v );

    },

    // based on MochiKit implementation by Bob Ippolito

    rgbToHsv : function ( color, hsv ) {

        var r = color.r;
        var g = color.g;
        var b = color.b;

        var max = Math.max( Math.max( r, g ), b );
        var min = Math.min( Math.min( r, g ), b );

        var hue;
        var saturation;
        var value = max;

        if ( min === max )    {

            hue = 0;
            saturation = 0;

        } else {

            var delta = ( max - min );
            saturation = delta / max;

            if ( r === max ) {

                hue = ( g - b ) / delta;

            } else if ( g === max ) {

                hue = 2 + ( ( b - r ) / delta );

            } else    {

                hue = 4 + ( ( r - g ) / delta );
            }

            hue /= 6;

            if ( hue < 0 ) {

                hue += 1;

            }

            if ( hue > 1 ) {

                hue -= 1;

            }

        }

        if ( hsv === undefined ) {

            hsv = { h: 0, s: 0, v: 0 };

        }

        hsv.h = hue;
        hsv.s = saturation;
        hsv.v = value;

        return hsv;

    }

};

THREE.ColorUtils.__hsv = { h: 0, s: 0, v: 0 };/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.GeometryUtils = {

    // Merge two geometries or geometry and geometry from object (using object's transform)

    merge: function ( geometry1, object2 /* mesh | geometry */ ) {

        var matrix, matrixRotation,
        vertexOffset = geometry1.vertices.length,
        uvPosition = geometry1.faceVertexUvs[ 0 ].length,
        geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2,
        vertices1 = geometry1.vertices,
        vertices2 = geometry2.vertices,
        faces1 = geometry1.faces,
        faces2 = geometry2.faces,
        uvs1 = geometry1.faceVertexUvs[ 0 ],
        uvs2 = geometry2.faceVertexUvs[ 0 ];

        var geo1MaterialsMap = {};

        for ( var i = 0; i < geometry1.materials.length; i ++ ) {

            var id = geometry1.materials[ i ].id;

            geo1MaterialsMap[ id ] = i;

        }

        if ( object2 instanceof THREE.Mesh ) {

            object2.matrixAutoUpdate && object2.updateMatrix();

            matrix = object2.matrix;
            matrixRotation = new THREE.Matrix4();
            matrixRotation.extractRotation( matrix, object2.scale );

        }

        // vertices

        for ( var i = 0, il = vertices2.length; i < il; i ++ ) {

            var vertex = vertices2[ i ];

            var vertexCopy = vertex.clone();

            if ( matrix ) matrix.multiplyVector3( vertexCopy );

            vertices1.push( vertexCopy );

        }

        // faces

        for ( i = 0, il = faces2.length; i < il; i ++ ) {

            var face = faces2[ i ], faceCopy, normal, color,
            faceVertexNormals = face.vertexNormals,
            faceVertexColors = face.vertexColors;

            if ( face instanceof THREE.Face3 ) {

                faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );

            } else if ( face instanceof THREE.Face4 ) {

                faceCopy = new THREE.Face4( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset, face.d + vertexOffset );

            }

            faceCopy.normal.copy( face.normal );

            if ( matrixRotation ) matrixRotation.multiplyVector3( faceCopy.normal );

            for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {

                normal = faceVertexNormals[ j ].clone();

                if ( matrixRotation ) matrixRotation.multiplyVector3( normal );

                faceCopy.vertexNormals.push( normal );

            }

            faceCopy.color.copy( face.color );

            for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {

                color = faceVertexColors[ j ];
                faceCopy.vertexColors.push( color.clone() );

            }

            if ( face.materialIndex !== undefined ) {

                var material2 = geometry2.materials[ face.materialIndex ];
                var materialId2 = material2.id;

                var materialIndex = geo1MaterialsMap[ materialId2 ];

                if ( materialIndex === undefined ) {

                    materialIndex = geometry1.materials.length;
                    geo1MaterialsMap[ materialId2 ] = materialIndex;

                    geometry1.materials.push( material2 );

                }

                faceCopy.materialIndex = materialIndex;

            }

            faceCopy.centroid.copy( face.centroid );
            if ( matrix ) matrix.multiplyVector3( faceCopy.centroid );

            faces1.push( faceCopy );

        }

        // uvs

        for ( i = 0, il = uvs2.length; i < il; i ++ ) {

            var uv = uvs2[ i ], uvCopy = [];

            for ( var j = 0, jl = uv.length; j < jl; j ++ ) {

                uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );

            }

            uvs1.push( uvCopy );

        }

    },

    clone: function ( geometry ) {

        var cloneGeo = new THREE.Geometry();

        var i, il;

        var vertices = geometry.vertices,
            faces = geometry.faces,
            uvs = geometry.faceVertexUvs[ 0 ];

        // materials

        if ( geometry.materials ) {

            cloneGeo.materials = geometry.materials.slice();

        }

        // vertices

        for ( i = 0, il = vertices.length; i < il; i ++ ) {

            var vertex = vertices[ i ];

            cloneGeo.vertices.push( vertex.clone() );

        }

        // faces

        for ( i = 0, il = faces.length; i < il; i ++ ) {

            var face = faces[ i ];

            cloneGeo.faces.push( face.clone() );

        }

        // uvs

        for ( i = 0, il = uvs.length; i < il; i ++ ) {

            var uv = uvs[ i ], uvCopy = [];

            for ( var j = 0, jl = uv.length; j < jl; j ++ ) {

                uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );

            }

            cloneGeo.faceVertexUvs[ 0 ].push( uvCopy );

        }

        return cloneGeo;

    },

    // Get random point in triangle (via barycentric coordinates)
    //     (uniform distribution)
    //     http://www.cgafaq.info/wiki/Random_Point_In_Triangle

    randomPointInTriangle: function ( vectorA, vectorB, vectorC ) {

        var a, b, c,
            point = new THREE.Vector3(),
            tmp = THREE.GeometryUtils.__v1;

        a = THREE.GeometryUtils.random();
        b = THREE.GeometryUtils.random();

        if ( ( a + b ) > 1 ) {

            a = 1 - a;
            b = 1 - b;

        }

        c = 1 - a - b;

        point.copy( vectorA );
        point.multiplyScalar( a );

        tmp.copy( vectorB );
        tmp.multiplyScalar( b );

        point.addSelf( tmp );

        tmp.copy( vectorC );
        tmp.multiplyScalar( c );

        point.addSelf( tmp );

        return point;

    },

    // Get random point in face (triangle / quad)
    // (uniform distribution)

    randomPointInFace: function ( face, geometry, useCachedAreas ) {

        var vA, vB, vC, vD;

        if ( face instanceof THREE.Face3 ) {

            vA = geometry.vertices[ face.a ];
            vB = geometry.vertices[ face.b ];
            vC = geometry.vertices[ face.c ];

            return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );

        } else if ( face instanceof THREE.Face4 ) {

            vA = geometry.vertices[ face.a ];
            vB = geometry.vertices[ face.b ];
            vC = geometry.vertices[ face.c ];
            vD = geometry.vertices[ face.d ];

            var area1, area2;

            if ( useCachedAreas ) {

                if ( face._area1 && face._area2 ) {

                    area1 = face._area1;
                    area2 = face._area2;

                } else {

                    area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
                    area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );

                    face._area1 = area1;
                    face._area2 = area2;

                }

            } else {

                area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ),
                area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );

            }

            var r = THREE.GeometryUtils.random() * ( area1 + area2 );

            if ( r < area1 ) {

                return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vD );

            } else {

                return THREE.GeometryUtils.randomPointInTriangle( vB, vC, vD );

            }

        }

    },

    // Get uniformly distributed random points in mesh
    //     - create array with cumulative sums of face areas
    //  - pick random number from 0 to total area
    //  - find corresponding place in area array by binary search
    //    - get random point in face

    randomPointsInGeometry: function ( geometry, n ) {

        var face, i,
            faces = geometry.faces,
            vertices = geometry.vertices,
            il = faces.length,
            totalArea = 0,
            cumulativeAreas = [],
            vA, vB, vC, vD;

        // precompute face areas

        for ( i = 0; i < il; i ++ ) {

            face = faces[ i ];

            if ( face instanceof THREE.Face3 ) {

                vA = vertices[ face.a ];
                vB = vertices[ face.b ];
                vC = vertices[ face.c ];

                face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );

            } else if ( face instanceof THREE.Face4 ) {

                vA = vertices[ face.a ];
                vB = vertices[ face.b ];
                vC = vertices[ face.c ];
                vD = vertices[ face.d ];

                face._area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
                face._area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );

                face._area = face._area1 + face._area2;

            }

            totalArea += face._area;

            cumulativeAreas[ i ] = totalArea;

        }

        // binary search cumulative areas array

        function binarySearchIndices( value ) {

            function binarySearch( start, end ) {

                // return closest larger index
                // if exact number is not found

                if ( end < start )
                    return start;

                var mid = start + Math.floor( ( end - start ) / 2 );

                if ( cumulativeAreas[ mid ] > value ) {

                    return binarySearch( start, mid - 1 );

                } else if ( cumulativeAreas[ mid ] < value ) {

                    return binarySearch( mid + 1, end );

                } else {

                    return mid;

                }

            }

            var result = binarySearch( 0, cumulativeAreas.length - 1 )
            return result;

        }

        // pick random face weighted by face area

        var r, index,
            result = [];

        var stats = {};

        for ( i = 0; i < n; i ++ ) {

            r = THREE.GeometryUtils.random() * totalArea;

            index = binarySearchIndices( r );

            result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );

            if ( ! stats[ index ] ) {

                stats[ index ] = 1;

            } else {

                stats[ index ] += 1;

            }

        }

        return result;

    },

    // Get triangle area (by Heron's formula)
    //     http://en.wikipedia.org/wiki/Heron%27s_formula

    triangleArea: function ( vectorA, vectorB, vectorC ) {

        var s, a, b, c,
            tmp = THREE.GeometryUtils.__v1;

        tmp.sub( vectorA, vectorB );
        a = tmp.length();

        tmp.sub( vectorA, vectorC );
        b = tmp.length();

        tmp.sub( vectorB, vectorC );
        c = tmp.length();

        s = 0.5 * ( a + b + c );

        return Math.sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );

    },

    // Center geometry so that 0,0,0 is in center of bounding box

    center: function ( geometry ) {

        geometry.computeBoundingBox();

        var bb = geometry.boundingBox;

        var offset = new THREE.Vector3();

        offset.add( bb.min, bb.max );
        offset.multiplyScalar( -0.5 );

        geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
        geometry.computeBoundingBox();

        return offset;

    },

    // Normalize UVs to be from <0,1>
    // (for now just the first set of UVs)

    normalizeUVs: function ( geometry ) {

        var uvSet = geometry.faceVertexUvs[ 0 ];

        for ( var i = 0, il = uvSet.length; i < il; i ++ ) {

            var uvs = uvSet[ i ];

            for ( var j = 0, jl = uvs.length; j < jl; j ++ ) {

                // texture repeat

                if( uvs[ j ].u !== 1.0 ) uvs[ j ].u = uvs[ j ].u - Math.floor( uvs[ j ].u );
                if( uvs[ j ].v !== 1.0 ) uvs[ j ].v = uvs[ j ].v - Math.floor( uvs[ j ].v );

            }

        }

    },

    triangulateQuads: function ( geometry ) {

        var i, il, j, jl;

        var faces = [];
        var faceUvs = [];
        var faceVertexUvs = [];

        for ( i = 0, il = geometry.faceUvs.length; i < il; i ++ ) {

            faceUvs[ i ] = [];

        }

        for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {

            faceVertexUvs[ i ] = [];

        }

        for ( i = 0, il = geometry.faces.length; i < il; i ++ ) {

            var face = geometry.faces[ i ];

            if ( face instanceof THREE.Face4 ) {

                var a = face.a;
                var b = face.b;
                var c = face.c;
                var d = face.d;

                var triA = new THREE.Face3();
                var triB = new THREE.Face3();

                triA.color.copy( face.color );
                triB.color.copy( face.color );

                triA.materialIndex = face.materialIndex;
                triB.materialIndex = face.materialIndex;

                triA.a = a;
                triA.b = b;
                triA.c = d;

                triB.a = b;
                triB.b = c;
                triB.c = d;

                if ( face.vertexColors.length === 4 ) {

                    triA.vertexColors[ 0 ] = face.vertexColors[ 0 ].clone();
                    triA.vertexColors[ 1 ] = face.vertexColors[ 1 ].clone();
                    triA.vertexColors[ 2 ] = face.vertexColors[ 3 ].clone();

                    triB.vertexColors[ 0 ] = face.vertexColors[ 1 ].clone();
                    triB.vertexColors[ 1 ] = face.vertexColors[ 2 ].clone();
                    triB.vertexColors[ 2 ] = face.vertexColors[ 3 ].clone();

                }

                faces.push( triA, triB );

                for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {

                    if ( geometry.faceVertexUvs[ j ].length ) {

                        var uvs = geometry.faceVertexUvs[ j ][ i ];

                        var uvA = uvs[ 0 ];
                        var uvB = uvs[ 1 ];
                        var uvC = uvs[ 2 ];
                        var uvD = uvs[ 3 ];

                        var uvsTriA = [ uvA.clone(), uvB.clone(), uvD.clone() ];
                        var uvsTriB = [ uvB.clone(), uvC.clone(), uvD.clone() ];

                        faceVertexUvs[ j ].push( uvsTriA, uvsTriB );

                    }

                }

                for ( j = 0, jl = geometry.faceUvs.length; j < jl; j ++ ) {

                    if ( geometry.faceUvs[ j ].length ) {

                        var faceUv = geometry.faceUvs[ j ][ i ];

                        faceUvs[ j ].push( faceUv, faceUv );

                    }

                }

            } else {

                faces.push( face );

                for ( j = 0, jl = geometry.faceUvs.length; j < jl; j ++ ) {

                    faceUvs[ j ].push( geometry.faceUvs[ j ][ i ] );

                }

                for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {

                    faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );

                }

            }

        }

        geometry.faces = faces;
        geometry.faceUvs = faceUvs;
        geometry.faceVertexUvs = faceVertexUvs;

        geometry.computeCentroids();
        geometry.computeFaceNormals();
        geometry.computeVertexNormals();

        if ( geometry.hasTangents ) geometry.computeTangents();

    },

    // Make all faces use unique vertices
    // so that each face can be separated from others

    explode: function( geometry ) {

        var vertices = [];

        for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {

            var n = vertices.length;

            var face = geometry.faces[ i ];

            if ( face instanceof THREE.Face4 ) {

                var a = face.a;
                var b = face.b;
                var c = face.c;
                var d = face.d;

                var va = geometry.vertices[ a ];
                var vb = geometry.vertices[ b ];
                var vc = geometry.vertices[ c ];
                var vd = geometry.vertices[ d ];

                vertices.push( va.clone() );
                vertices.push( vb.clone() );
                vertices.push( vc.clone() );
                vertices.push( vd.clone() );

                face.a = n;
                face.b = n + 1;
                face.c = n + 2;
                face.d = n + 3;

            } else {

                var a = face.a;
                var b = face.b;
                var c = face.c;

                var va = geometry.vertices[ a ];
                var vb = geometry.vertices[ b ];
                var vc = geometry.vertices[ c ];

                vertices.push( va.clone() );
                vertices.push( vb.clone() );
                vertices.push( vc.clone() );

                face.a = n;
                face.b = n + 1;
                face.c = n + 2;

            }

        }

        geometry.vertices = vertices;
        delete geometry.__tmpVertices;

    },

    // Break faces with edges longer than maxEdgeLength
    // - not recursive

    tessellate: function ( geometry, maxEdgeLength ) {

        var i, il, face,
        a, b, c, d,
        va, vb, vc, vd,
        dab, dbc, dac, dcd, dad,
        m, m1, m2,
        vm, vm1, vm2,
        vnm, vnm1, vnm2,
        vcm, vcm1, vcm2,
        triA, triB,
        quadA, quadB,
        edge;

        var faces = [];
        var faceVertexUvs = [];

        for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {

            faceVertexUvs[ i ] = [];

        }

        for ( i = 0, il = geometry.faces.length; i < il; i ++ ) {

            face = geometry.faces[ i ];

            if ( face instanceof THREE.Face3 ) {

                a = face.a;
                b = face.b;
                c = face.c;

                va = geometry.vertices[ a ];
                vb = geometry.vertices[ b ];
                vc = geometry.vertices[ c ];

                dab = va.distanceTo( vb );
                dbc = vb.distanceTo( vc );
                dac = va.distanceTo( vc );

                if ( dab > maxEdgeLength || dbc > maxEdgeLength || dac > maxEdgeLength ) {

                    m = geometry.vertices.length;

                    triA = face.clone();
                    triB = face.clone();

                    if ( dab >= dbc && dab >= dac ) {

                        vm = va.clone();
                        vm.lerpSelf( vb, 0.5 );

                        triA.a = a;
                        triA.b = m;
                        triA.c = c;

                        triB.a = m;
                        triB.b = b;
                        triB.c = c;

                        if ( face.vertexNormals.length === 3 ) {

                            vnm = face.vertexNormals[ 0 ].clone();
                            vnm.lerpSelf( face.vertexNormals[ 1 ], 0.5 );

                            triA.vertexNormals[ 1 ].copy( vnm );
                            triB.vertexNormals[ 0 ].copy( vnm );

                        }

                        if ( face.vertexColors.length === 3 ) {

                            vcm = face.vertexColors[ 0 ].clone();
                            vcm.lerpSelf( face.vertexColors[ 1 ], 0.5 );

                            triA.vertexColors[ 1 ].copy( vcm );
                            triB.vertexColors[ 0 ].copy( vcm );

                        }

                        edge = 0;

                    } else if ( dbc >= dab && dbc >= dac ) {

                        vm = vb.clone();
                        vm.lerpSelf( vc, 0.5 );

                        triA.a = a;
                        triA.b = b;
                        triA.c = m;

                        triB.a = m;
                        triB.b = c;
                        triB.c = a;

                        if ( face.vertexNormals.length === 3 ) {

                            vnm = face.vertexNormals[ 1 ].clone();
                            vnm.lerpSelf( face.vertexNormals[ 2 ], 0.5 );

                            triA.vertexNormals[ 2 ].copy( vnm );

                            triB.vertexNormals[ 0 ].copy( vnm );
                            triB.vertexNormals[ 1 ].copy( face.vertexNormals[ 2 ] );
                            triB.vertexNormals[ 2 ].copy( face.vertexNormals[ 0 ] );

                        }

                        if ( face.vertexColors.length === 3 ) {

                            vcm = face.vertexColors[ 1 ].clone();
                            vcm.lerpSelf( face.vertexColors[ 2 ], 0.5 );

                            triA.vertexColors[ 2 ].copy( vcm );

                            triB.vertexColors[ 0 ].copy( vcm );
                            triB.vertexColors[ 1 ].copy( face.vertexColors[ 2 ] );
                            triB.vertexColors[ 2 ].copy( face.vertexColors[ 0 ] );

                        }

                        edge = 1;

                    } else {

                        vm = va.clone();
                        vm.lerpSelf( vc, 0.5 );

                        triA.a = a;
                        triA.b = b;
                        triA.c = m;

                        triB.a = m;
                        triB.b = b;
                        triB.c = c;

                        if ( face.vertexNormals.length === 3 ) {

                            vnm = face.vertexNormals[ 0 ].clone();
                            vnm.lerpSelf( face.vertexNormals[ 2 ], 0.5 );

                            triA.vertexNormals[ 2 ].copy( vnm );
                            triB.vertexNormals[ 0 ].copy( vnm );

                        }

                        if ( face.vertexColors.length === 3 ) {

                            vcm = face.vertexColors[ 0 ].clone();
                            vcm.lerpSelf( face.vertexColors[ 2 ], 0.5 );

                            triA.vertexColors[ 2 ].copy( vcm );
                            triB.vertexColors[ 0 ].copy( vcm );

                        }

                        edge = 2;

                    }

                    faces.push( triA, triB );
                    geometry.vertices.push( vm );

                    var j, jl, uvs, uvA, uvB, uvC, uvM, uvsTriA, uvsTriB;

                    for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {

                        if ( geometry.faceVertexUvs[ j ].length ) {

                            uvs = geometry.faceVertexUvs[ j ][ i ];

                            uvA = uvs[ 0 ];
                            uvB = uvs[ 1 ];
                            uvC = uvs[ 2 ];

                            // AB

                            if ( edge === 0 ) {

                                uvM = uvA.clone();
                                uvM.lerpSelf( uvB, 0.5 );

                                uvsTriA = [ uvA.clone(), uvM.clone(), uvC.clone() ];
                                uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];

                            // BC

                            } else if ( edge === 1 ) {

                                uvM = uvB.clone();
                                uvM.lerpSelf( uvC, 0.5 );

                                uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
                                uvsTriB = [ uvM.clone(), uvC.clone(), uvA.clone() ];

                            // AC

                            } else {

                                uvM = uvA.clone();
                                uvM.lerpSelf( uvC, 0.5 );

                                uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
                                uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];

                            }

                            faceVertexUvs[ j ].push( uvsTriA, uvsTriB );

                        }

                    }

                } else {

                    faces.push( face );

                    for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {

                        faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );

                    }

                }

            } else {

                a = face.a;
                b = face.b;
                c = face.c;
                d = face.d;

                va = geometry.vertices[ a ];
                vb = geometry.vertices[ b ];
                vc = geometry.vertices[ c ];
                vd = geometry.vertices[ d ];

                dab = va.distanceTo( vb );
                dbc = vb.distanceTo( vc );
                dcd = vc.distanceTo( vd );
                dad = va.distanceTo( vd );

                if ( dab > maxEdgeLength || dbc > maxEdgeLength || dcd > maxEdgeLength || dad > maxEdgeLength ) {

                    m1 = geometry.vertices.length;
                    m2 = geometry.vertices.length + 1;

                    quadA = face.clone();
                    quadB = face.clone();

                    if ( ( dab >= dbc && dab >= dcd && dab >= dad ) || ( dcd >= dbc && dcd >= dab && dcd >= dad ) ) {

                        vm1 = va.clone();
                        vm1.lerpSelf( vb, 0.5 );

                        vm2 = vc.clone();
                        vm2.lerpSelf( vd, 0.5 );

                        quadA.a = a;
                        quadA.b = m1;
                        quadA.c = m2;
                        quadA.d = d;

                        quadB.a = m1;
                        quadB.b = b;
                        quadB.c = c;
                        quadB.d = m2;

                        if ( face.vertexNormals.length === 4 ) {

                            vnm1 = face.vertexNormals[ 0 ].clone();
                            vnm1.lerpSelf( face.vertexNormals[ 1 ], 0.5 );

                            vnm2 = face.vertexNormals[ 2 ].clone();
                            vnm2.lerpSelf( face.vertexNormals[ 3 ], 0.5 );

                            quadA.vertexNormals[ 1 ].copy( vnm1 );
                            quadA.vertexNormals[ 2 ].copy( vnm2 );

                            quadB.vertexNormals[ 0 ].copy( vnm1 );
                            quadB.vertexNormals[ 3 ].copy( vnm2 );

                        }

                        if ( face.vertexColors.length === 4 ) {

                            vcm1 = face.vertexColors[ 0 ].clone();
                            vcm1.lerpSelf( face.vertexColors[ 1 ], 0.5 );

                            vcm2 = face.vertexColors[ 2 ].clone();
                            vcm2.lerpSelf( face.vertexColors[ 3 ], 0.5 );

                            quadA.vertexColors[ 1 ].copy( vcm1 );
                            quadA.vertexColors[ 2 ].copy( vcm2 );

                            quadB.vertexColors[ 0 ].copy( vcm1 );
                            quadB.vertexColors[ 3 ].copy( vcm2 );

                        }

                        edge = 0;

                    } else {

                        vm1 = vb.clone();
                        vm1.lerpSelf( vc, 0.5 );

                        vm2 = vd.clone();
                        vm2.lerpSelf( va, 0.5 );

                        quadA.a = a;
                        quadA.b = b;
                        quadA.c = m1;
                        quadA.d = m2;

                        quadB.a = m2;
                        quadB.b = m1;
                        quadB.c = c;
                        quadB.d = d;

                        if ( face.vertexNormals.length === 4 ) {

                            vnm1 = face.vertexNormals[ 1 ].clone();
                            vnm1.lerpSelf( face.vertexNormals[ 2 ], 0.5 );

                            vnm2 = face.vertexNormals[ 3 ].clone();
                            vnm2.lerpSelf( face.vertexNormals[ 0 ], 0.5 );

                            quadA.vertexNormals[ 2 ].copy( vnm1 );
                            quadA.vertexNormals[ 3 ].copy( vnm2 );

                            quadB.vertexNormals[ 0 ].copy( vnm2 );
                            quadB.vertexNormals[ 1 ].copy( vnm1 );

                        }

                        if ( face.vertexColors.length === 4 ) {

                            vcm1 = face.vertexColors[ 1 ].clone();
                            vcm1.lerpSelf( face.vertexColors[ 2 ], 0.5 );

                            vcm2 = face.vertexColors[ 3 ].clone();
                            vcm2.lerpSelf( face.vertexColors[ 0 ], 0.5 );

                            quadA.vertexColors[ 2 ].copy( vcm1 );
                            quadA.vertexColors[ 3 ].copy( vcm2 );

                            quadB.vertexColors[ 0 ].copy( vcm2 );
                            quadB.vertexColors[ 1 ].copy( vcm1 );

                        }

                        edge = 1;

                    }

                    faces.push( quadA, quadB );
                    geometry.vertices.push( vm1, vm2 );

                    var j, jl, uvs, uvA, uvB, uvC, uvD, uvM1, uvM2, uvsQuadA, uvsQuadB;

                    for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {

                        if ( geometry.faceVertexUvs[ j ].length ) {

                            uvs = geometry.faceVertexUvs[ j ][ i ];

                            uvA = uvs[ 0 ];
                            uvB = uvs[ 1 ];
                            uvC = uvs[ 2 ];
                            uvD = uvs[ 3 ];

                            // AB + CD

                            if ( edge === 0 ) {

                                uvM1 = uvA.clone();
                                uvM1.lerpSelf( uvB, 0.5 );

                                uvM2 = uvC.clone();
                                uvM2.lerpSelf( uvD, 0.5 );

                                uvsQuadA = [ uvA.clone(), uvM1.clone(), uvM2.clone(), uvD.clone() ];
                                uvsQuadB = [ uvM1.clone(), uvB.clone(), uvC.clone(), uvM2.clone() ];

                            // BC + AD

                            } else {

                                uvM1 = uvB.clone();
                                uvM1.lerpSelf( uvC, 0.5 );

                                uvM2 = uvD.clone();
                                uvM2.lerpSelf( uvA, 0.5 );

                                uvsQuadA = [ uvA.clone(), uvB.clone(), uvM1.clone(), uvM2.clone() ];
                                uvsQuadB = [ uvM2.clone(), uvM1.clone(), uvC.clone(), uvD.clone() ];

                            }

                            faceVertexUvs[ j ].push( uvsQuadA, uvsQuadB );

                        }

                    }

                } else {

                    faces.push( face );

                    for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {

                        faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );

                    }

                }

            }

        }

        geometry.faces = faces;
        geometry.faceVertexUvs = faceVertexUvs;

    }

};

THREE.GeometryUtils.random = THREE.Math.random16;

THREE.GeometryUtils.__v1 = new THREE.Vector3();
/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.ImageUtils = {

    crossOrigin: 'anonymous',

    loadTexture: function ( url, mapping, onLoad, onError ) {

        var image = new Image();
        var texture = new THREE.Texture( image, mapping );

        var loader = new THREE.ImageLoader();

        loader.addEventListener( 'load', function ( event ) {

            texture.image = event.content;
            texture.needsUpdate = true;

            if ( onLoad ) onLoad( texture );

        } );

        loader.addEventListener( 'error', function ( event ) {

            if ( onError ) onError( event.message );

        } );

        loader.crossOrigin = this.crossOrigin;
        loader.load( url, image );

        return texture;

    },

    loadCompressedTexture: function ( url, mapping, onLoad, onError ) {

        var texture = new THREE.CompressedTexture();
        texture.mapping = mapping;

        var request = new XMLHttpRequest();

        request.onload = function () {

            var buffer = request.response;
            var dds = THREE.ImageUtils.parseDDS( buffer, true );

            texture.format = dds.format;

            texture.mipmaps = dds.mipmaps;
            texture.image.width = dds.width;
            texture.image.height = dds.height;

            // gl.generateMipmap fails for compressed textures
            // mipmaps must be embedded in the DDS file
            // or texture filters must not use mipmapping

            texture.generateMipmaps = false;

            texture.needsUpdate = true;

            if ( onLoad ) onLoad( texture );

        }

        request.onerror = onError;

        request.open( 'GET', url, true );
        request.responseType = "arraybuffer";
        request.send( null );

        return texture;

    },

    loadTextureCube: function ( array, mapping, onLoad, onError ) {

        var images = [];
        images.loadCount = 0;

        var texture = new THREE.Texture();
        texture.image = images;
        if ( mapping !== undefined ) texture.mapping = mapping;

        // no flipping needed for cube textures

        texture.flipY = false;

        for ( var i = 0, il = array.length; i < il; ++ i ) {

            var cubeImage = new Image();
            images[ i ] = cubeImage;

            cubeImage.onload = function () {

                images.loadCount += 1;

                if ( images.loadCount === 6 ) {

                    texture.needsUpdate = true;
                    if ( onLoad ) onLoad();

                }

            };

            cubeImage.onerror = onError;

            cubeImage.crossOrigin = this.crossOrigin;
            cubeImage.src = array[ i ];

        }

        return texture;

    },

    loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) {

        var images = [];
        images.loadCount = 0;

        var texture = new THREE.CompressedTexture();
        texture.image = images;
        if ( mapping !== undefined ) texture.mapping = mapping;

        // no flipping for cube textures
        // (also flipping doesn't work for compressed textures )

        texture.flipY = false;

        // can't generate mipmaps for compressed textures
        // mips must be embedded in DDS files

        texture.generateMipmaps = false;

        var generateCubeFaceCallback = function ( rq, img ) {

            return function () {

                var buffer = rq.response;
                var dds = THREE.ImageUtils.parseDDS( buffer, true );

                img.format = dds.format;

                img.mipmaps = dds.mipmaps;
                img.width = dds.width;
                img.height = dds.height;

                images.loadCount += 1;

                if ( images.loadCount === 6 ) {

                    texture.format = dds.format;
                    texture.needsUpdate = true;
                    if ( onLoad ) onLoad();

                }

            }

        }

        for ( var i = 0, il = array.length; i < il; ++ i ) {

            var cubeImage = {};
            images[ i ] = cubeImage;

            var request = new XMLHttpRequest();

            request.onload = generateCubeFaceCallback( request, cubeImage );
            request.onerror = onError;

            var url = array[ i ];

            request.open( 'GET', url, true );
            request.responseType = "arraybuffer";
            request.send( null );

        }

        return texture;

    },

    parseDDS: function ( buffer, loadMipmaps ) {

        var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 };

        // Adapted from @toji's DDS utils
        //    https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js

        // All values and structures referenced from:
        // http://msdn.microsoft.com/en-us/library/bb943991.aspx/

        var DDS_MAGIC = 0x20534444;

        var DDSD_CAPS = 0x1,
            DDSD_HEIGHT = 0x2,
            DDSD_WIDTH = 0x4,
            DDSD_PITCH = 0x8,
            DDSD_PIXELFORMAT = 0x1000,
            DDSD_MIPMAPCOUNT = 0x20000,
            DDSD_LINEARSIZE = 0x80000,
            DDSD_DEPTH = 0x800000;

        var DDSCAPS_COMPLEX = 0x8,
            DDSCAPS_MIPMAP = 0x400000,
            DDSCAPS_TEXTURE = 0x1000;

        var DDSCAPS2_CUBEMAP = 0x200,
            DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
            DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
            DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
            DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
            DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
            DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
            DDSCAPS2_VOLUME = 0x200000;

        var DDPF_ALPHAPIXELS = 0x1,
            DDPF_ALPHA = 0x2,
            DDPF_FOURCC = 0x4,
            DDPF_RGB = 0x40,
            DDPF_YUV = 0x200,
            DDPF_LUMINANCE = 0x20000;

        function fourCCToInt32( value ) {

            return value.charCodeAt(0) +
                (value.charCodeAt(1) << 8) +
                (value.charCodeAt(2) << 16) +
                (value.charCodeAt(3) << 24);

        }

        function int32ToFourCC( value ) {

            return String.fromCharCode(
                value & 0xff,
                (value >> 8) & 0xff,
                (value >> 16) & 0xff,
                (value >> 24) & 0xff
            );
        }

        var FOURCC_DXT1 = fourCCToInt32("DXT1");
        var FOURCC_DXT3 = fourCCToInt32("DXT3");
        var FOURCC_DXT5 = fourCCToInt32("DXT5");

        var headerLengthInt = 31; // The header length in 32 bit ints

        // Offsets into the header array

        var off_magic = 0;

        var off_size = 1;
        var off_flags = 2;
        var off_height = 3;
        var off_width = 4;

        var off_mipmapCount = 7;

        var off_pfFlags = 20;
        var off_pfFourCC = 21;

        // Parse header

        var header = new Int32Array( buffer, 0, headerLengthInt );

        if ( header[ off_magic ] !== DDS_MAGIC ) {

            console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" );
            return dds;

        }

        if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {

            console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" );
            return dds;

        }

        var blockBytes;

        var fourCC = header[ off_pfFourCC ];

        switch ( fourCC ) {

            case FOURCC_DXT1:

                blockBytes = 8;
                dds.format = THREE.RGB_S3TC_DXT1_Format;
                break;

            case FOURCC_DXT3:

                blockBytes = 16;
                dds.format = THREE.RGBA_S3TC_DXT3_Format;
                break;

            case FOURCC_DXT5:

                blockBytes = 16;
                dds.format = THREE.RGBA_S3TC_DXT5_Format;
                break;

            default:

                console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) );
                return dds;

        }

        dds.mipmapCount = 1;

        if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {

            dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );

        }

        dds.width = header[ off_width ];
        dds.height = header[ off_height ];

        var dataOffset = header[ off_size ] + 4;

        // Extract mipmaps buffers

        var width = dds.width;
        var height = dds.height;

        for ( var i = 0; i < dds.mipmapCount; i ++ ) {

            var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
            var byteArray = new Uint8Array( buffer, dataOffset, dataLength );

            var mipmap = { "data": byteArray, "width": width, "height": height };
            dds.mipmaps.push( mipmap );

            dataOffset += dataLength;

            width = Math.max( width * 0.5, 1 );
            height = Math.max( height * 0.5, 1 );

        }

        return dds;

    },

    getNormalMap: function ( image, depth ) {

        // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/

        var cross = function ( a, b ) {

            return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];

        }

        var subtract = function ( a, b ) {

            return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];

        }

        var normalize = function ( a ) {

            var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
            return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];

        }

        depth = depth | 1;

        var width = image.width;
        var height = image.height;

        var canvas = document.createElement( 'canvas' );
        canvas.width = width;
        canvas.height = height;

        var context = canvas.getContext( '2d' );
        context.drawImage( image, 0, 0 );

        var data = context.getImageData( 0, 0, width, height ).data;
        var imageData = context.createImageData( width, height );
        var output = imageData.data;

        for ( var x = 0; x < width; x ++ ) {

            for ( var y = 0; y < height; y ++ ) {

                var ly = y - 1 < 0 ? 0 : y - 1;
                var uy = y + 1 > height - 1 ? height - 1 : y + 1;
                var lx = x - 1 < 0 ? 0 : x - 1;
                var ux = x + 1 > width - 1 ? width - 1 : x + 1;

                var points = [];
                var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
                points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
                points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
                points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
                points.push( [  1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
                points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
                points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
                points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
                points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );

                var normals = [];
                var num_points = points.length;

                for ( var i = 0; i < num_points; i ++ ) {

                    var v1 = points[ i ];
                    var v2 = points[ ( i + 1 ) % num_points ];
                    v1 = subtract( v1, origin );
                    v2 = subtract( v2, origin );
                    normals.push( normalize( cross( v1, v2 ) ) );

                }

                var normal = [ 0, 0, 0 ];

                for ( var i = 0; i < normals.length; i ++ ) {

                    normal[ 0 ] += normals[ i ][ 0 ];
                    normal[ 1 ] += normals[ i ][ 1 ];
                    normal[ 2 ] += normals[ i ][ 2 ];

                }

                normal[ 0 ] /= normals.length;
                normal[ 1 ] /= normals.length;
                normal[ 2 ] /= normals.length;

                var idx = ( y * width + x ) * 4;

                output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
                output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
                output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
                output[ idx + 3 ] = 255;

            }

        }

        context.putImageData( imageData, 0, 0 );

        return canvas;

    },

    generateDataTexture: function ( width, height, color ) {

        var size = width * height;
        var data = new Uint8Array( 3 * size );

        var r = Math.floor( color.r * 255 );
        var g = Math.floor( color.g * 255 );
        var b = Math.floor( color.b * 255 );

        for ( var i = 0; i < size; i ++ ) {

            data[ i * 3 ]       = r;
            data[ i * 3 + 1 ] = g;
            data[ i * 3 + 2 ] = b;

        }

        var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
        texture.needsUpdate = true;

        return texture;

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SceneUtils = {

    showHierarchy : function ( root, visible ) {

        THREE.SceneUtils.traverseHierarchy( root, function( node ) { node.visible = visible; } );

    },

    traverseHierarchy : function ( root, callback ) {

        var n, i, l = root.children.length;

        for ( i = 0; i < l; i ++ ) {

            n = root.children[ i ];

            callback( n );

            THREE.SceneUtils.traverseHierarchy( n, callback );

        }

    },

    createMultiMaterialObject : function ( geometry, materials ) {

        var i, il = materials.length,
            group = new THREE.Object3D();

        for ( i = 0; i < il; i ++ ) {

            var object = new THREE.Mesh( geometry, materials[ i ] );
            group.add( object );

        }

        return group;

    },

    cloneObject: function ( source ) {

        var object;

        // subclass specific properties
        // (must process in order from more specific subclasses to more abstract classes)

        if ( source instanceof THREE.MorphAnimMesh ) {

            object = new THREE.MorphAnimMesh( source.geometry, source.material );

            object.duration = source.duration;
            object.mirroredLoop = source.mirroredLoop;
            object.time = source.time;

            object.lastKeyframe = source.lastKeyframe;
            object.currentKeyframe = source.currentKeyframe;

            object.direction = source.direction;
            object.directionBackwards = source.directionBackwards;

        } else if ( source instanceof THREE.SkinnedMesh ) {

            object = new THREE.SkinnedMesh( source.geometry, source.material, source.useVertexTexture );

        } else if ( source instanceof THREE.Mesh ) {

            object = new THREE.Mesh( source.geometry, source.material );

        } else if ( source instanceof THREE.Line ) {

            object = new THREE.Line( source.geometry, source.material, source.type );

        } else if ( source instanceof THREE.Ribbon ) {

            object = new THREE.Ribbon( source.geometry, source.material );

        } else if ( source instanceof THREE.ParticleSystem ) {

            object = new THREE.ParticleSystem( source.geometry, source.material );
            object.sortParticles = source.sortParticles;

        } else if ( source instanceof THREE.Particle ) {

            object = new THREE.Particle( source.material );

        } else if ( source instanceof THREE.Sprite ) {

            object = new THREE.Sprite( {} );

            object.color.copy( source.color );
            object.map = source.map;
            object.blending = source.blending;

            object.useScreenCoordinates = source.useScreenCoordinates;
            object.mergeWith3D = source.mergeWith3D;
            object.affectedByDistance = source.affectedByDistance;
            object.scaleByViewport = source.scaleByViewport;
            object.alignment = source.alignment;

            object.rotation3d.copy( source.rotation3d );
            object.rotation = source.rotation;
            object.opacity = source.opacity;

            object.uvOffset.copy( source.uvOffset );
            object.uvScale.copy( source.uvScale);

        } else if ( source instanceof THREE.LOD ) {

            object = new THREE.LOD();

        /*
        } else if ( source instanceof THREE.MarchingCubes ) {

            object = new THREE.MarchingCubes( source.resolution, source.material );
            object.field.set( source.field );
            object.isolation = source.isolation;
        */

        } else if ( source instanceof THREE.Object3D ) {

            object = new THREE.Object3D();

        }

        // base class properties

        object.name = source.name;

        object.parent = source.parent;

        object.up.copy( source.up );

        object.position.copy( source.position );

        // because of Sprite madness

        if ( object.rotation instanceof THREE.Vector3 )
            object.rotation.copy( source.rotation );

        object.eulerOrder = source.eulerOrder;

        object.scale.copy( source.scale );

        object.dynamic = source.dynamic;

        object.renderDepth = source.renderDepth;

        object.rotationAutoUpdate = source.rotationAutoUpdate;

        object.matrix.copy( source.matrix );
        object.matrixWorld.copy( source.matrixWorld );
        object.matrixRotationWorld.copy( source.matrixRotationWorld );

        object.matrixAutoUpdate = source.matrixAutoUpdate;
        object.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;

        object.quaternion.copy( source.quaternion );
        object.useQuaternion = source.useQuaternion;

        object.boundRadius = source.boundRadius;
        object.boundRadiusScale = source.boundRadiusScale;

        object.visible = source.visible;

        object.castShadow = source.castShadow;
        object.receiveShadow = source.receiveShadow;

        object.frustumCulled = source.frustumCulled;

        // children

        for ( var i = 0; i < source.children.length; i ++ ) {

            var child = THREE.SceneUtils.cloneObject( source.children[ i ] );
            object.children[ i ] = child;

            child.parent = object;

        }

        // LODs need to be patched separately to use cloned children

        if ( source instanceof THREE.LOD ) {

            for ( var i = 0; i < source.LODs.length; i ++ ) {

                var lod = source.LODs[ i ];
                object.LODs[ i ] = { visibleAtDistance: lod.visibleAtDistance, object3D: object.children[ i ] };

            }

        }

        return object;

    },

    detach : function ( child, parent, scene ) {

        child.applyMatrix( parent.matrixWorld );
        parent.remove( child );
        scene.add( child );

    },

    attach: function ( child, scene, parent ) {

        var matrixWorldInverse = new THREE.Matrix4();
        matrixWorldInverse.getInverse( parent.matrixWorld );
        child.applyMatrix( matrixWorldInverse );

        scene.remove( child );
        parent.add( child );

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 *
 * ShaderUtils currently contains:
 *
 *    fresnel
 *    normal
 *     cube
 *
 */

if ( THREE.WebGLRenderer ) {

THREE.ShaderUtils = {

    lib: {

        /* -------------------------------------------------------------------------
        //    Fresnel shader
        //    - based on Nvidia Cg tutorial
         ------------------------------------------------------------------------- */

        'fresnel': {

            uniforms: {

                "mRefractionRatio": { type: "f", value: 1.02 },
                "mFresnelBias": { type: "f", value: 0.1 },
                "mFresnelPower": { type: "f", value: 2.0 },
                "mFresnelScale": { type: "f", value: 1.0 },
                "tCube": { type: "t", value: null }

            },

            fragmentShader: [

                "uniform samplerCube tCube;",

                "varying vec3 vReflect;",
                "varying vec3 vRefract[3];",
                "varying float vReflectionFactor;",

                "void main() {",

                    "vec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",
                    "vec4 refractedColor = vec4( 1.0, 1.0, 1.0, 1.0 );",

                    "refractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;",
                    "refractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;",
                    "refractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;",
                    "refractedColor.a = 1.0;",

                    "gl_FragColor = mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );",

                "}"

            ].join("\n"),

            vertexShader: [

                "uniform float mRefractionRatio;",
                "uniform float mFresnelBias;",
                "uniform float mFresnelScale;",
                "uniform float mFresnelPower;",

                "varying vec3 vReflect;",
                "varying vec3 vRefract[3];",
                "varying float vReflectionFactor;",

                "void main() {",

                    "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
                    "vec4 mPosition = modelMatrix * vec4( position, 1.0 );",

                    "vec3 nWorld = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );",

                    "vec3 I = mPosition.xyz - cameraPosition;",

                    "vReflect = reflect( I, nWorld );",
                    "vRefract[0] = refract( normalize( I ), nWorld, mRefractionRatio );",
                    "vRefract[1] = refract( normalize( I ), nWorld, mRefractionRatio * 0.99 );",
                    "vRefract[2] = refract( normalize( I ), nWorld, mRefractionRatio * 0.98 );",
                    "vReflectionFactor = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( I ), nWorld ), mFresnelPower );",

                    "gl_Position = projectionMatrix * mvPosition;",

                "}"

            ].join("\n")

        },

        /* -------------------------------------------------------------------------
        //    Normal map shader
        //        - Blinn-Phong
        //        - normal + diffuse + specular + AO + displacement + reflection + shadow maps
        //        - point and directional lights (use with "lights: true" material option)
         ------------------------------------------------------------------------- */

        'normal' : {

            uniforms: THREE.UniformsUtils.merge( [

                THREE.UniformsLib[ "fog" ],
                THREE.UniformsLib[ "lights" ],
                THREE.UniformsLib[ "shadowmap" ],

                {

                "enableAO"          : { type: "i", value: 0 },
                "enableDiffuse"      : { type: "i", value: 0 },
                "enableSpecular"  : { type: "i", value: 0 },
                "enableReflection": { type: "i", value: 0 },
                "enableDisplacement": { type: "i", value: 0 },

                "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture
                "tDiffuse"       : { type: "t", value: null },
                "tCube"           : { type: "t", value: null },
                "tNormal"       : { type: "t", value: null },
                "tSpecular"       : { type: "t", value: null },
                "tAO"           : { type: "t", value: null },

                "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) },

                "uDisplacementBias": { type: "f", value: 0.0 },
                "uDisplacementScale": { type: "f", value: 1.0 },

                "uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) },
                "uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
                "uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) },
                "uShininess": { type: "f", value: 30 },
                "uOpacity": { type: "f", value: 1 },

                "useRefract": { type: "i", value: 0 },
                "uRefractionRatio": { type: "f", value: 0.98 },
                "uReflectivity": { type: "f", value: 0.5 },

                "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) },
                "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },

                "wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }

                }

            ] ),

            fragmentShader: [

                "uniform vec3 uAmbientColor;",
                "uniform vec3 uDiffuseColor;",
                "uniform vec3 uSpecularColor;",
                "uniform float uShininess;",
                "uniform float uOpacity;",

                "uniform bool enableDiffuse;",
                "uniform bool enableSpecular;",
                "uniform bool enableAO;",
                "uniform bool enableReflection;",

                "uniform sampler2D tDiffuse;",
                "uniform sampler2D tNormal;",
                "uniform sampler2D tSpecular;",
                "uniform sampler2D tAO;",

                "uniform samplerCube tCube;",

                "uniform vec2 uNormalScale;",

                "uniform bool useRefract;",
                "uniform float uRefractionRatio;",
                "uniform float uReflectivity;",

                "varying vec3 vTangent;",
                "varying vec3 vBinormal;",
                "varying vec3 vNormal;",
                "varying vec2 vUv;",

                "uniform vec3 ambientLightColor;",

                "#if MAX_DIR_LIGHTS > 0",

                    "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
                    "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",

                "#endif",

                "#if MAX_HEMI_LIGHTS > 0",

                    "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
                    "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
                    "uniform vec3 hemisphereLightPosition[ MAX_HEMI_LIGHTS ];",

                "#endif",

                "#if MAX_POINT_LIGHTS > 0",

                    "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
                    "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
                    "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

                "#endif",

                "#if MAX_SPOT_LIGHTS > 0",

                    "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
                    "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
                    "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
                    "uniform float spotLightAngle[ MAX_SPOT_LIGHTS ];",
                    "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
                    "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",

                "#endif",

                "#ifdef WRAP_AROUND",

                    "uniform vec3 wrapRGB;",

                "#endif",

                "varying vec3 vWorldPosition;",
                "varying vec3 vViewPosition;",

                THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
                THREE.ShaderChunk[ "fog_pars_fragment" ],

                "void main() {",

                    "gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",

                    "vec3 specularTex = vec3( 1.0 );",

                    "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
                    "normalTex.xy *= uNormalScale;",
                    "normalTex = normalize( normalTex );",

                    "if( enableDiffuse ) {",

                        "#ifdef GAMMA_INPUT",

                            "vec4 texelColor = texture2D( tDiffuse, vUv );",
                            "texelColor.xyz *= texelColor.xyz;",

                            "gl_FragColor = gl_FragColor * texelColor;",

                        "#else",

                            "gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",

                        "#endif",

                    "}",

                    "if( enableAO ) {",

                        "#ifdef GAMMA_INPUT",

                            "vec4 aoColor = texture2D( tAO, vUv );",
                            "aoColor.xyz *= aoColor.xyz;",

                            "gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",

                        "#else",

                            "gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",

                        "#endif",

                    "}",

                    "if( enableSpecular )",
                        "specularTex = texture2D( tSpecular, vUv ).xyz;",

                    "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );",
                    "vec3 finalNormal = tsb * normalTex;",

                    "#ifdef FLIP_SIDED",

                        "finalNormal = -finalNormal;",

                    "#endif",

                    "vec3 normal = normalize( finalNormal );",
                    "vec3 viewPosition = normalize( vViewPosition );",

                    // point lights

                    "#if MAX_POINT_LIGHTS > 0",

                        "vec3 pointDiffuse = vec3( 0.0 );",
                        "vec3 pointSpecular = vec3( 0.0 );",

                        "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",

                            "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
                            "vec3 pointVector = lPosition.xyz + vViewPosition.xyz;",

                            "float pointDistance = 1.0;",
                            "if ( pointLightDistance[ i ] > 0.0 )",
                                "pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );",

                            "pointVector = normalize( pointVector );",

                            // diffuse

                            "#ifdef WRAP_AROUND",

                                "float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );",
                                "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );",

                                "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",

                            "#else",

                                "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",

                            "#endif",

                            "pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;",

                            // specular

                            "vec3 pointHalfVector = normalize( pointVector + viewPosition );",
                            "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
                            "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );",

                            "#ifdef PHYSICALLY_BASED_SHADING",

                                // 2.0 => 2.0001 is hack to work around ANGLE bug

                                "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",

                                "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );",
                                "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",

                            "#else",

                                "pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;",

                            "#endif",

                        "}",

                    "#endif",

                    // spot lights

                    "#if MAX_SPOT_LIGHTS > 0",

                        "vec3 spotDiffuse = vec3( 0.0 );",
                        "vec3 spotSpecular = vec3( 0.0 );",

                        "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",

                            "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
                            "vec3 spotVector = lPosition.xyz + vViewPosition.xyz;",

                            "float spotDistance = 1.0;",
                            "if ( spotLightDistance[ i ] > 0.0 )",
                                "spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );",

                            "spotVector = normalize( spotVector );",

                            "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",

                            "if ( spotEffect > spotLightAngle[ i ] ) {",

                                "spotEffect = pow( spotEffect, spotLightExponent[ i ] );",

                                // diffuse

                                "#ifdef WRAP_AROUND",

                                    "float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );",
                                    "float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );",

                                    "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",

                                "#else",

                                    "float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );",

                                "#endif",

                                "spotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;",

                                // specular

                                "vec3 spotHalfVector = normalize( spotVector + viewPosition );",
                                "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
                                "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );",

                                "#ifdef PHYSICALLY_BASED_SHADING",

                                    // 2.0 => 2.0001 is hack to work around ANGLE bug

                                    "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",

                                    "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );",
                                    "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;",

                                "#else",

                                    "spotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;",

                                "#endif",

                            "}",

                        "}",

                    "#endif",

                    // directional lights

                    "#if MAX_DIR_LIGHTS > 0",

                        "vec3 dirDiffuse = vec3( 0.0 );",
                        "vec3 dirSpecular = vec3( 0.0 );",

                        "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",

                            "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
                            "vec3 dirVector = normalize( lDirection.xyz );",

                            // diffuse

                            "#ifdef WRAP_AROUND",

                                "float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );",
                                "float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",

                                "vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );",

                            "#else",

                                "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",

                            "#endif",

                            "dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;",

                            // specular

                            "vec3 dirHalfVector = normalize( dirVector + viewPosition );",
                            "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
                            "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );",

                            "#ifdef PHYSICALLY_BASED_SHADING",

                                // 2.0 => 2.0001 is hack to work around ANGLE bug

                                "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",

                                "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
                                "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",

                            "#else",

                                "dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;",

                            "#endif",

                        "}",

                    "#endif",

                    // hemisphere lights

                    "#if MAX_HEMI_LIGHTS > 0",

                        "vec3 hemiDiffuse  = vec3( 0.0 );",
                        "vec3 hemiSpecular = vec3( 0.0 );" ,

                        "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",

                            "vec4 lPosition = viewMatrix * vec4( hemisphereLightPosition[ i ], 1.0 );",
                            "vec3 lVector = normalize( lPosition.xyz + vViewPosition.xyz );",

                            // diffuse

                            "float dotProduct = dot( normal, lVector );",
                            "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",

                            "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",

                            "hemiDiffuse += uDiffuseColor * hemiColor;",

                            // specular (sky light)


                            "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
                            "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
                            "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );",

                            // specular (ground light)

                            "vec3 lVectorGround = normalize( -lPosition.xyz + vViewPosition.xyz );",

                            "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
                            "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
                            "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );",

                            "#ifdef PHYSICALLY_BASED_SHADING",

                                "float dotProductGround = dot( normal, lVectorGround );",

                                // 2.0 => 2.0001 is hack to work around ANGLE bug

                                "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",

                                "vec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );",
                                "vec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );",
                                "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",

                            "#else",

                                "hemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;",

                            "#endif",

                        "}",

                    "#endif",

                    // all lights contribution summation

                    "vec3 totalDiffuse = vec3( 0.0 );",
                    "vec3 totalSpecular = vec3( 0.0 );",

                    "#if MAX_DIR_LIGHTS > 0",

                        "totalDiffuse += dirDiffuse;",
                        "totalSpecular += dirSpecular;",

                    "#endif",

                    "#if MAX_HEMI_LIGHTS > 0",

                        "totalDiffuse += hemiDiffuse;",
                        "totalSpecular += hemiSpecular;",

                    "#endif",

                    "#if MAX_POINT_LIGHTS > 0",

                        "totalDiffuse += pointDiffuse;",
                        "totalSpecular += pointSpecular;",

                    "#endif",

                    "#if MAX_SPOT_LIGHTS > 0",

                        "totalDiffuse += spotDiffuse;",
                        "totalSpecular += spotSpecular;",

                    "#endif",

                    "#ifdef METAL",

                        "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );",

                    "#else",

                        "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;",

                    "#endif",

                    "if ( enableReflection ) {",

                        "vec3 vReflect;",
                        "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",

                        "if ( useRefract ) {",

                            "vReflect = refract( cameraToVertex, normal, uRefractionRatio );",

                        "} else {",

                            "vReflect = reflect( cameraToVertex, normal );",

                        "}",

                        "vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",

                        "#ifdef GAMMA_INPUT",

                            "cubeColor.xyz *= cubeColor.xyz;",

                        "#endif",

                        "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );",

                    "}",

                    THREE.ShaderChunk[ "shadowmap_fragment" ],
                    THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
                    THREE.ShaderChunk[ "fog_fragment" ],

                "}"

            ].join("\n"),

            vertexShader: [

                "attribute vec4 tangent;",

                "uniform vec2 uOffset;",
                "uniform vec2 uRepeat;",

                "uniform bool enableDisplacement;",

                "#ifdef VERTEX_TEXTURES",

                    "uniform sampler2D tDisplacement;",
                    "uniform float uDisplacementScale;",
                    "uniform float uDisplacementBias;",

                "#endif",

                "varying vec3 vTangent;",
                "varying vec3 vBinormal;",
                "varying vec3 vNormal;",
                "varying vec2 vUv;",

                "varying vec3 vWorldPosition;",
                "varying vec3 vViewPosition;",

                THREE.ShaderChunk[ "skinning_pars_vertex" ],
                THREE.ShaderChunk[ "shadowmap_pars_vertex" ],

                "void main() {",

                    THREE.ShaderChunk[ "skinbase_vertex" ],
                    THREE.ShaderChunk[ "skinnormal_vertex" ],

                    // normal, tangent and binormal vectors

                    "#ifdef USE_SKINNING",

                        "vNormal = normalMatrix * skinnedNormal.xyz;",

                        "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );",
                        "vTangent = normalMatrix * skinnedTangent.xyz;",

                    "#else",

                        "vNormal = normalMatrix * normal;",
                        "vTangent = normalMatrix * tangent.xyz;",

                    "#endif",

                    "vBinormal = cross( vNormal, vTangent ) * tangent.w;",

                    "vUv = uv * uRepeat + uOffset;",

                    // displacement mapping

                    "vec3 displacedPosition;",

                    "#ifdef VERTEX_TEXTURES",

                        "if ( enableDisplacement ) {",

                            "vec3 dv = texture2D( tDisplacement, uv ).xyz;",
                            "float df = uDisplacementScale * dv.x + uDisplacementBias;",
                            "displacedPosition = position + normalize( normal ) * df;",

                        "} else {",

                            "#ifdef USE_SKINNING",

                                "vec4 skinVertex = vec4( position, 1.0 );",

                                "vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
                                "skinned       += boneMatY * skinVertex * skinWeight.y;",

                                "displacedPosition  = skinned.xyz;",

                            "#else",

                                "displacedPosition = position;",

                            "#endif",

                        "}",

                    "#else",

                        "#ifdef USE_SKINNING",

                            "vec4 skinVertex = vec4( position, 1.0 );",

                            "vec4 skinned  = boneMatX * skinVertex * skinWeight.x;",
                            "skinned       += boneMatY * skinVertex * skinWeight.y;",

                            "displacedPosition  = skinned.xyz;",

                        "#else",

                            "displacedPosition = position;",

                        "#endif",

                    "#endif",

                    //

                    "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );",
                    "vec4 mPosition = modelMatrix * vec4( displacedPosition, 1.0 );",

                    "gl_Position = projectionMatrix * mvPosition;",

                    //

                    "vWorldPosition = mPosition.xyz;",
                    "vViewPosition = -mvPosition.xyz;",

                    // shadows

                    "#ifdef USE_SHADOWMAP",

                        "for( int i = 0; i < MAX_SHADOWS; i ++ ) {",

                            "vShadowCoord[ i ] = shadowMatrix[ i ] * mPosition;",

                        "}",

                    "#endif",

                "}"

            ].join("\n")

        },

        /* -------------------------------------------------------------------------
        //    Cube map shader
         ------------------------------------------------------------------------- */

        'cube': {

            uniforms: { "tCube": { type: "t", value: null },
                        "tFlip": { type: "f", value: -1 } },

            vertexShader: [

                "varying vec3 vViewPosition;",

                "void main() {",

                    "vec4 mPosition = modelMatrix * vec4( position, 1.0 );",
                    "vViewPosition = cameraPosition - mPosition.xyz;",

                    "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

                "}"

            ].join("\n"),

            fragmentShader: [

                "uniform samplerCube tCube;",
                "uniform float tFlip;",

                "varying vec3 vViewPosition;",

                "void main() {",

                    "vec3 wPos = cameraPosition - vViewPosition;",
                    "gl_FragColor = textureCube( tCube, vec3( tFlip * wPos.x, wPos.yz ) );",

                "}"

            ].join("\n")

        }

    }

};

};
/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * @author alteredq / http://alteredqualia.com/
 *
 * For Text operations in three.js (See TextGeometry)
 *
 * It uses techniques used in:
 *
 *     typeface.js and canvastext
 *         For converting fonts and rendering with javascript
 *        http://typeface.neocracy.org
 *
 *    Triangulation ported from AS3
 *        Simple Polygon Triangulation
 *        http://actionsnippet.com/?p=1462
 *
 *     A Method to triangulate shapes with holes
 *        http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
 *
 */

THREE.FontUtils = {

    faces : {},

    // Just for now. face[weight][style]

    face : "helvetiker",
    weight: "normal",
    style : "normal",
    size : 150,
    divisions : 10,

    getFace : function() {

        return this.faces[ this.face ][ this.weight ][ this.style ];

    },

    loadFace : function( data ) {

        var family = data.familyName.toLowerCase();

        var ThreeFont = this;

        ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};

        ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
        ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;

        var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;

        return data;

    },

    drawText : function( text ) {

        var characterPts = [], allPts = [];

        // RenderText

        var i, p,
            face = this.getFace(),
            scale = this.size / face.resolution,
            offset = 0,
            chars = String( text ).split( '' ),
            length = chars.length;

        var fontPaths = [];

        for ( i = 0; i < length; i ++ ) {

            var path = new THREE.Path();

            var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
            offset += ret.offset;

            fontPaths.push( ret.path );

        }

        // get the width

        var width = offset / 2;
        //
        // for ( p = 0; p < allPts.length; p++ ) {
        //
        //     allPts[ p ].x -= width;
        //
        // }

        //var extract = this.extractPoints( allPts, characterPts );
        //extract.contour = allPts;

        //extract.paths = fontPaths;
        //extract.offset = width;

        return { paths : fontPaths, offset : width };

    },




    extractGlyphPoints : function( c, face, scale, offset, path ) {

        var pts = [];

        var i, i2, divisions,
            outline, action, length,
            scaleX, scaleY,
            x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
            laste,
            glyph = face.glyphs[ c ] || face.glyphs[ '?' ];

        if ( !glyph ) return;

        if ( glyph.o ) {

            outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
            length = outline.length;

            scaleX = scale;
            scaleY = scale;

            for ( i = 0; i < length; ) {

                action = outline[ i ++ ];

                //console.log( action );

                switch( action ) {

                case 'm':

                    // Move To

                    x = outline[ i++ ] * scaleX + offset;
                    y = outline[ i++ ] * scaleY;

                    path.moveTo( x, y );
                    break;

                case 'l':

                    // Line To

                    x = outline[ i++ ] * scaleX + offset;
                    y = outline[ i++ ] * scaleY;
                    path.lineTo(x,y);
                    break;

                case 'q':

                    // QuadraticCurveTo

                    cpx  = outline[ i++ ] * scaleX + offset;
                    cpy  = outline[ i++ ] * scaleY;
                    cpx1 = outline[ i++ ] * scaleX + offset;
                    cpy1 = outline[ i++ ] * scaleY;

                    path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);

                    laste = pts[ pts.length - 1 ];

                    if ( laste ) {

                        cpx0 = laste.x;
                        cpy0 = laste.y;

                        for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {

                            var t = i2 / divisions;
                            var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
                            var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
                      }

                  }

                  break;

                case 'b':

                    // Cubic Bezier Curve

                    cpx  = outline[ i++ ] *  scaleX + offset;
                    cpy  = outline[ i++ ] *  scaleY;
                    cpx1 = outline[ i++ ] *  scaleX + offset;
                    cpy1 = outline[ i++ ] * -scaleY;
                    cpx2 = outline[ i++ ] *  scaleX + offset;
                    cpy2 = outline[ i++ ] * -scaleY;

                    path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 );

                    laste = pts[ pts.length - 1 ];

                    if ( laste ) {

                        cpx0 = laste.x;
                        cpy0 = laste.y;

                        for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {

                            var t = i2 / divisions;
                            var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
                            var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );

                        }

                    }

                    break;

                }

            }
        }



        return { offset: glyph.ha*scale, path:path};
    }

};


THREE.FontUtils.generateShapes = function( text, parameters ) {

    // Parameters

    parameters = parameters || {};

    var size = parameters.size !== undefined ? parameters.size : 100;
    var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;

    var font = parameters.font !== undefined ? parameters.font : "helvetiker";
    var weight = parameters.weight !== undefined ? parameters.weight : "normal";
    var style = parameters.style !== undefined ? parameters.style : "normal";

    THREE.FontUtils.size = size;
    THREE.FontUtils.divisions = curveSegments;

    THREE.FontUtils.face = font;
    THREE.FontUtils.weight = weight;
    THREE.FontUtils.style = style;

    // Get a Font data json object

    var data = THREE.FontUtils.drawText( text );

    var paths = data.paths;
    var shapes = [];

    for ( var p = 0, pl = paths.length; p < pl; p ++ ) {

        Array.prototype.push.apply( shapes, paths[ p ].toShapes() );

    }

    return shapes;

};


/**
 * This code is a quick port of code written in C++ which was submitted to
 * flipcode.com by John W. Ratcliff  // July 22, 2000
 * See original code and more information here:
 * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
 *
 * ported to actionscript by Zevan Rosser
 * www.actionsnippet.com
 *
 * ported to javascript by Joshua Koo
 * http://www.lab4games.net/zz85/blog
 *
 */


( function( namespace ) {

    var EPSILON = 0.0000000001;

    // takes in an contour array and returns

    var process = function( contour, indices ) {

        var n = contour.length;

        if ( n < 3 ) return null;

        var result = [],
            verts = [],
            vertIndices = [];

        /* we want a counter-clockwise polygon in verts */

        var u, v, w;

        if ( area( contour ) > 0.0 ) {

            for ( v = 0; v < n; v++ ) verts[ v ] = v;

        } else {

            for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;

        }

        var nv = n;

        /*  remove nv - 2 vertices, creating 1 triangle every time */

        var count = 2 * nv;   /* error detection */

        for( v = nv - 1; nv > 2; ) {

            /* if we loop, it is probably a non-simple polygon */

            if ( ( count-- ) <= 0 ) {

                //** Triangulate: ERROR - probable bad polygon!

                //throw ( "Warning, unable to triangulate polygon!" );
                //return null;
                // Sometimes warning is fine, especially polygons are triangulated in reverse.
                console.log( "Warning, unable to triangulate polygon!" );

                if ( indices ) return vertIndices;
                return result;

            }

            /* three consecutive vertices in current polygon, <u,v,w> */

            u = v;          if ( nv <= u ) u = 0;     /* previous */
            v = u + 1;  if ( nv <= v ) v = 0;     /* new v    */
            w = v + 1;  if ( nv <= w ) w = 0;     /* next     */

            if ( snip( contour, u, v, w, nv, verts ) ) {

                var a, b, c, s, t;

                /* true names of the vertices */

                a = verts[ u ];
                b = verts[ v ];
                c = verts[ w ];

                /* output Triangle */

                /*
                result.push( contour[ a ] );
                result.push( contour[ b ] );
                result.push( contour[ c ] );
                */
                result.push( [ contour[ a ],
                    contour[ b ],
                    contour[ c ] ] );


                vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );

                /* remove v from the remaining polygon */

                for( s = v, t = v + 1; t < nv; s++, t++ ) {

                    verts[ s ] = verts[ t ];

                }

                nv--;

                /* reset error detection counter */

                count = 2 * nv;

            }

        }

        if ( indices ) return vertIndices;
        return result;

    };

    // calculate area of the contour polygon

    var area = function ( contour ) {

        var n = contour.length;
        var a = 0.0;

        for( var p = n - 1, q = 0; q < n; p = q++ ) {

            a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;

        }

        return a * 0.5;

    };

    // see if p is inside triangle abc

    var insideTriangle = function( ax, ay,
                                   bx, by,
                                   cx, cy,
                                   px, py ) {

          var aX, aY, bX, bY;
          var cX, cY, apx, apy;
          var bpx, bpy, cpx, cpy;
          var cCROSSap, bCROSScp, aCROSSbp;

          aX = cx - bx;  aY = cy - by;
          bX = ax - cx;  bY = ay - cy;
          cX = bx - ax;  cY = by - ay;
          apx= px  -ax;  apy= py - ay;
          bpx= px - bx;  bpy= py - by;
          cpx= px - cx;  cpy= py - cy;

          aCROSSbp = aX*bpy - aY*bpx;
          cCROSSap = cX*apy - cY*apx;
          bCROSScp = bX*cpy - bY*cpx;

          return ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) );

    };


    var snip = function ( contour, u, v, w, n, verts ) {

        var p;
        var ax, ay, bx, by;
        var cx, cy, px, py;

        ax = contour[ verts[ u ] ].x;
        ay = contour[ verts[ u ] ].y;

        bx = contour[ verts[ v ] ].x;
        by = contour[ verts[ v ] ].y;

        cx = contour[ verts[ w ] ].x;
        cy = contour[ verts[ w ] ].y;

        if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;

            for ( p = 0; p < n; p++ ) {

                if( (p == u) || (p == v) || (p == w) ) continue;

                px = contour[ verts[ p ] ].x
                py = contour[ verts[ p ] ].y

                if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) return false;

          }

          return true;

    };


    namespace.Triangulate = process;
    namespace.Triangulate.area = area;

    return namespace;

})(THREE.FontUtils);

// To use the typeface.js face files, hook up the API
self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * Extensible curve object
 *
 * Some common of Curve methods
 * .getPoint(t), getTangent(t)
 * .getPointAt(u), getTagentAt(u)
 * .getPoints(), .getSpacedPoints()
 * .getLength()
 * .updateArcLengths()
 *
 * This file contains following classes:
 *
 * -- 2d classes --
 * THREE.Curve
 * THREE.LineCurve
 * THREE.QuadraticBezierCurve
 * THREE.CubicBezierCurve
 * THREE.SplineCurve
 * THREE.ArcCurve
 * THREE.EllipseCurve
 *
 * -- 3d classes --
 * THREE.LineCurve3
 * THREE.QuadraticBezierCurve3
 * THREE.CubicBezierCurve3
 * THREE.SplineCurve3
 * THREE.ClosedSplineCurve3
 *
 * A series of curves can be represented as a THREE.CurvePath
 *
 **/

/**************************************************************
 *    Abstract Curve base class
 **************************************************************/

THREE.Curve = function () {

};

// Virtual base class method to overwrite and implement in subclasses
//    - t [0 .. 1]

THREE.Curve.prototype.getPoint = function ( t ) {

    console.log( "Warning, getPoint() not implemented!" );
    return null;

};

// Get point at relative position in curve according to arc length
// - u [0 .. 1]

THREE.Curve.prototype.getPointAt = function ( u ) {

    var t = this.getUtoTmapping( u );
    return this.getPoint( t );

};

// Get sequence of points using getPoint( t )

THREE.Curve.prototype.getPoints = function ( divisions ) {

    if ( !divisions ) divisions = 5;

    var d, pts = [];

    for ( d = 0; d <= divisions; d ++ ) {

        pts.push( this.getPoint( d / divisions ) );

    }

    return pts;

};

// Get sequence of points using getPointAt( u )

THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {

    if ( !divisions ) divisions = 5;

    var d, pts = [];

    for ( d = 0; d <= divisions; d ++ ) {

        pts.push( this.getPointAt( d / divisions ) );

    }

    return pts;

};

// Get total curve arc length

THREE.Curve.prototype.getLength = function () {

    var lengths = this.getLengths();
    return lengths[ lengths.length - 1 ];

};

// Get list of cumulative segment lengths

THREE.Curve.prototype.getLengths = function ( divisions ) {

    if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200;

    if ( this.cacheArcLengths
        && ( this.cacheArcLengths.length == divisions + 1 )
        && !this.needsUpdate) {

        //console.log( "cached", this.cacheArcLengths );
        return this.cacheArcLengths;

    }

    this.needsUpdate = false;

    var cache = [];
    var current, last = this.getPoint( 0 );
    var p, sum = 0;

    cache.push( 0 );

    for ( p = 1; p <= divisions; p ++ ) {

        current = this.getPoint ( p / divisions );
        sum += current.distanceTo( last );
        cache.push( sum );
        last = current;

    }

    this.cacheArcLengths = cache;

    return cache; // { sums: cache, sum:sum }; Sum is in the last element.

};


THREE.Curve.prototype.updateArcLengths = function() {
    this.needsUpdate = true;
    this.getLengths();
};

// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance

THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {

    var arcLengths = this.getLengths();

    var i = 0, il = arcLengths.length;

    var targetArcLength; // The targeted u distance value to get

    if ( distance ) {

        targetArcLength = distance;

    } else {

        targetArcLength = u * arcLengths[ il - 1 ];

    }

    //var time = Date.now();

    // binary search for the index with largest value smaller than target u distance

    var low = 0, high = il - 1, comparison;

    while ( low <= high ) {

        i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats

        comparison = arcLengths[ i ] - targetArcLength;

        if ( comparison < 0 ) {

            low = i + 1;
            continue;

        } else if ( comparison > 0 ) {

            high = i - 1;
            continue;

        } else {

            high = i;
            break;

            // DONE

        }

    }

    i = high;

    //console.log('b' , i, low, high, Date.now()- time);

    if ( arcLengths[ i ] == targetArcLength ) {

        var t = i / ( il - 1 );
        return t;

    }

    // we could get finer grain at lengths, or use simple interpolatation between two points

    var lengthBefore = arcLengths[ i ];
    var lengthAfter = arcLengths[ i + 1 ];

    var segmentLength = lengthAfter - lengthBefore;

    // determine where we are between the 'before' and 'after' points

    var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;

    // add that fractional amount to t

    var t = ( i + segmentFraction ) / ( il -1 );

    return t;

};


// In 2D space, there are actually 2 normal vectors,
// and in 3D space, infinte
// TODO this should be depreciated.
THREE.Curve.prototype.getNormalVector = function( t ) {

    var vec = this.getTangent( t );

    return new THREE.Vector2( -vec.y , vec.x );

};

// Returns a unit vector tangent at t
// In case any sub curve does not implement its tangent / normal finding,
// we get 2 points with a small delta and find a gradient of the 2 points
// which seems to make a reasonable approximation

THREE.Curve.prototype.getTangent = function( t ) {

    var delta = 0.0001;
    var t1 = t - delta;
    var t2 = t + delta;

    // Capping in case of danger

    if ( t1 < 0 ) t1 = 0;
    if ( t2 > 1 ) t2 = 1;

    var pt1 = this.getPoint( t1 );
    var pt2 = this.getPoint( t2 );

    var vec = pt2.clone().subSelf(pt1);
    return vec.normalize();

};


THREE.Curve.prototype.getTangentAt = function ( u ) {

    var t = this.getUtoTmapping( u );
    return this.getTangent( t );

};

/**************************************************************
 *    Line
 **************************************************************/

THREE.LineCurve = function ( v1, v2 ) {

    this.v1 = v1;
    this.v2 = v2;

};

THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype );

THREE.LineCurve.prototype.getPoint = function ( t ) {

    var point = this.v2.clone().subSelf(this.v1);
    point.multiplyScalar( t ).addSelf( this.v1 );

    return point;

};

// Line curve is linear, so we can overwrite default getPointAt

THREE.LineCurve.prototype.getPointAt = function ( u ) {

    return this.getPoint( u );

};

THREE.LineCurve.prototype.getTangent = function( t ) {

    var tangent = this.v2.clone().subSelf(this.v1);

    return tangent.normalize();

};

/**************************************************************
 *    Quadratic Bezier curve
 **************************************************************/


THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) {

    this.v0 = v0;
    this.v1 = v1;
    this.v2 = v2;

};

THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype );


THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {

    var tx, ty;

    tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
    ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );

    return new THREE.Vector2( tx, ty );

};


THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {

    var tx, ty;

    tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );
    ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y );

    // returns unit vector

    var tangent = new THREE.Vector2( tx, ty );
    tangent.normalize();

    return tangent;

};


/**************************************************************
 *    Cubic Bezier curve
 **************************************************************/

THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) {

    this.v0 = v0;
    this.v1 = v1;
    this.v2 = v2;
    this.v3 = v3;

};

THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype );

THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {

    var tx, ty;

    tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
    ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );

    return new THREE.Vector2( tx, ty );

};

THREE.CubicBezierCurve.prototype.getTangent = function( t ) {

    var tx, ty;

    tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
    ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );

    var tangent = new THREE.Vector2( tx, ty );
    tangent.normalize();

    return tangent;

};


/**************************************************************
 *    Spline curve
 **************************************************************/

THREE.SplineCurve = function ( points /* array of Vector2 */ ) {

    this.points = (points == undefined) ? [] : points;

};

THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype );

THREE.SplineCurve.prototype.getPoint = function ( t ) {

    var v = new THREE.Vector2();
    var c = [];
    var points = this.points, point, intPoint, weight;
    point = ( points.length - 1 ) * t;

    intPoint = Math.floor( point );
    weight = point - intPoint;

    c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
    c[ 1 ] = intPoint;
    c[ 2 ] = intPoint  > points.length - 2 ? points.length -1 : intPoint + 1;
    c[ 3 ] = intPoint  > points.length - 3 ? points.length -1 : intPoint + 2;

    v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight );
    v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight );

    return v;

};

/**************************************************************
 *    Ellipse curve
 **************************************************************/

THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius,
                            aStartAngle, aEndAngle,
                            aClockwise ) {

    this.aX = aX;
    this.aY = aY;

    this.xRadius = xRadius;
    this.yRadius = yRadius;

    this.aStartAngle = aStartAngle;
    this.aEndAngle = aEndAngle;

    this.aClockwise = aClockwise;

};

THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype );

THREE.EllipseCurve.prototype.getPoint = function ( t ) {

    var deltaAngle = this.aEndAngle - this.aStartAngle;

    if ( !this.aClockwise ) {

        t = 1 - t;

    }

    var angle = this.aStartAngle + t * deltaAngle;

    var tx = this.aX + this.xRadius * Math.cos( angle );
    var ty = this.aY + this.yRadius * Math.sin( angle );

    return new THREE.Vector2( tx, ty );

};

/**************************************************************
 *    Arc curve
 **************************************************************/

THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {

    THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
};

THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );


/**************************************************************
 *    Utils
 **************************************************************/

THREE.Curve.Utils = {

    tangentQuadraticBezier: function ( t, p0, p1, p2 ) {

        return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );

    },

    // Puay Bing, thanks for helping with this derivative!

    tangentCubicBezier: function (t, p0, p1, p2, p3 ) {

        return -3 * p0 * (1 - t) * (1 - t)  +
            3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) +
            6 * t *  p2 * (1-t) - 3 * t * t * p2 +
            3 * t * t * p3;
    },


    tangentSpline: function ( t, p0, p1, p2, p3 ) {

        // To check if my formulas are correct

        var h00 = 6 * t * t - 6 * t;     // derived from 2t^3 − 3t^2 + 1
        var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t
        var h01 = -6 * t * t + 6 * t;     // − 2t3 + 3t2
        var h11 = 3 * t * t - 2 * t;    // t3 − t2

        return h00 + h10 + h01 + h11;

    },

    // Catmull-Rom

    interpolate: function( p0, p1, p2, p3, t ) {

        var v0 = ( p2 - p0 ) * 0.5;
        var v1 = ( p3 - p1 ) * 0.5;
        var t2 = t * t;
        var t3 = t * t2;
        return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;

    }

};


// TODO: Transformation for Curves?

/**************************************************************
 *    3D Curves
 **************************************************************/

// A Factory method for creating new curve subclasses

THREE.Curve.create = function ( constructor, getPointFunc ) {

    constructor.prototype = Object.create( THREE.Curve.prototype );
    constructor.prototype.getPoint = getPointFunc;

    return constructor;

};


/**************************************************************
 *    Line3D
 **************************************************************/

THREE.LineCurve3 = THREE.Curve.create(

    function ( v1, v2 ) {

        this.v1 = v1;
        this.v2 = v2;

    },

    function ( t ) {

        var r = new THREE.Vector3();


        r.sub( this.v2, this.v1 ); // diff
        r.multiplyScalar( t );
        r.addSelf( this.v1 );

        return r;

    }

);


/**************************************************************
 *    Quadratic Bezier 3D curve
 **************************************************************/

THREE.QuadraticBezierCurve3 = THREE.Curve.create(

    function ( v0, v1, v2 ) {

        this.v0 = v0;
        this.v1 = v1;
        this.v2 = v2;

    },

    function ( t ) {

        var tx, ty, tz;

        tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
        ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
        tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );

        return new THREE.Vector3( tx, ty, tz );

    }

);



/**************************************************************
 *    Cubic Bezier 3D curve
 **************************************************************/

THREE.CubicBezierCurve3 = THREE.Curve.create(

    function ( v0, v1, v2, v3 ) {

        this.v0 = v0;
        this.v1 = v1;
        this.v2 = v2;
        this.v3 = v3;

    },

    function ( t ) {

        var tx, ty, tz;

        tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
        ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
        tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z );

        return new THREE.Vector3( tx, ty, tz );

    }

);



/**************************************************************
 *    Spline 3D curve
 **************************************************************/


THREE.SplineCurve3 = THREE.Curve.create(

    function ( points /* array of Vector3 */) {

        this.points = (points == undefined) ? [] : points;

    },

    function ( t ) {

        var v = new THREE.Vector3();
        var c = [];
        var points = this.points, point, intPoint, weight;
        point = ( points.length - 1 ) * t;

        intPoint = Math.floor( point );
        weight = point - intPoint;

        c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
        c[ 1 ] = intPoint;
        c[ 2 ] = intPoint  > points.length - 2 ? points.length - 1 : intPoint + 1;
        c[ 3 ] = intPoint  > points.length - 3 ? points.length - 1 : intPoint + 2;

        var pt0 = points[ c[0] ],
            pt1 = points[ c[1] ],
            pt2 = points[ c[2] ],
            pt3 = points[ c[3] ];

        v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight);
        v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight);
        v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight);

        return v;

    }

);


// THREE.SplineCurve3.prototype.getTangent = function(t) {
//         var v = new THREE.Vector3();
//         var c = [];
//         var points = this.points, point, intPoint, weight;
//         point = ( points.length - 1 ) * t;

//         intPoint = Math.floor( point );
//         weight = point - intPoint;

//         c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
//         c[ 1 ] = intPoint;
//         c[ 2 ] = intPoint  > points.length - 2 ? points.length - 1 : intPoint + 1;
//         c[ 3 ] = intPoint  > points.length - 3 ? points.length - 1 : intPoint + 2;

//         var pt0 = points[ c[0] ],
//             pt1 = points[ c[1] ],
//             pt2 = points[ c[2] ],
//             pt3 = points[ c[3] ];

//     // t = weight;
//     v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x );
//     v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y );
//     v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z );

//     return v;

// }

/**************************************************************
 *    Closed Spline 3D curve
 **************************************************************/


THREE.ClosedSplineCurve3 = THREE.Curve.create(

    function ( points /* array of Vector3 */) {

        this.points = (points == undefined) ? [] : points;

    },

    function ( t ) {

        var v = new THREE.Vector3();
        var c = [];
        var points = this.points, point, intPoint, weight;
        point = ( points.length - 0 ) * t;
            // This needs to be from 0-length +1

        intPoint = Math.floor( point );
        weight = point - intPoint;

        intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;
        c[ 0 ] = ( intPoint - 1 ) % points.length;
        c[ 1 ] = ( intPoint ) % points.length;
        c[ 2 ] = ( intPoint + 1 ) % points.length;
        c[ 3 ] = ( intPoint + 2 ) % points.length;

        v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight );
        v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight );
        v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight );

        return v;

    }

);
/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 **/

/**************************************************************
 *    Curved Path - a curve path is simply a array of connected
 *  curves, but retains the api of a curve
 **************************************************************/

THREE.CurvePath = function () {

    this.curves = [];
    this.bends = [];

    this.autoClose = false; // Automatically closes the path
};

THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype );

THREE.CurvePath.prototype.add = function ( curve ) {

    this.curves.push( curve );

};

THREE.CurvePath.prototype.checkConnection = function() {
    // TODO
    // If the ending of curve is not connected to the starting
    // or the next curve, then, this is not a real path
};

THREE.CurvePath.prototype.closePath = function() {
    // TODO Test
    // and verify for vector3 (needs to implement equals)
    // Add a line curve if start and end of lines are not connected
    var startPoint = this.curves[0].getPoint(0);
    var endPoint = this.curves[this.curves.length-1].getPoint(1);

    if (!startPoint.equals(endPoint)) {
        this.curves.push( new THREE.LineCurve(endPoint, startPoint) );
    }

};

// To get accurate point with reference to
// entire path distance at time t,
// following has to be done:

// 1. Length of each sub path have to be known
// 2. Locate and identify type of curve
// 3. Get t for the curve
// 4. Return curve.getPointAt(t')

THREE.CurvePath.prototype.getPoint = function( t ) {

    var d = t * this.getLength();
    var curveLengths = this.getCurveLengths();
    var i = 0, diff, curve;

    // To think about boundaries points.

    while ( i < curveLengths.length ) {

        if ( curveLengths[ i ] >= d ) {

            diff = curveLengths[ i ] - d;
            curve = this.curves[ i ];

            var u = 1 - diff / curve.getLength();

            return curve.getPointAt( u );

            break;
        }

        i ++;

    }

    return null;

    // loop where sum != 0, sum > d , sum+1 <d

};

/*
THREE.CurvePath.prototype.getTangent = function( t ) {
};*/


// We cannot use the default THREE.Curve getPoint() with getLength() because in
// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
// getPoint() depends on getLength

THREE.CurvePath.prototype.getLength = function() {

    var lens = this.getCurveLengths();
    return lens[ lens.length - 1 ];

};

// Compute lengths and cache them
// We cannot overwrite getLengths() because UtoT mapping uses it.

THREE.CurvePath.prototype.getCurveLengths = function() {

    // We use cache values if curves and cache array are same length

    if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) {

        return this.cacheLengths;

    };

    // Get length of subsurve
    // Push sums into cached array

    var lengths = [], sums = 0;
    var i, il = this.curves.length;

    for ( i = 0; i < il; i ++ ) {

        sums += this.curves[ i ].getLength();
        lengths.push( sums );

    }

    this.cacheLengths = lengths;

    return lengths;

};



// Returns min and max coordinates, as well as centroid

THREE.CurvePath.prototype.getBoundingBox = function () {

    var points = this.getPoints();

    var maxX, maxY, maxZ;
    var minX, minY, minZ;

    maxX = maxY = Number.NEGATIVE_INFINITY;
    minX = minY = Number.POSITIVE_INFINITY;

    var p, i, il, sum;

    var v3 = points[0] instanceof THREE.Vector3;

    sum = v3 ? new THREE.Vector3() : new THREE.Vector2();

    for ( i = 0, il = points.length; i < il; i ++ ) {

        p = points[ i ];

        if ( p.x > maxX ) maxX = p.x;
        else if ( p.x < minX ) minX = p.x;

        if ( p.y > maxY ) maxY = p.y;
        else if ( p.y < minY ) minY = p.y;

        if (v3) {

            if ( p.z > maxZ ) maxZ = p.z;
            else if ( p.z < minZ ) minZ = p.z;

        }

        sum.addSelf( p );

    }

    var ret = {

        minX: minX,
        minY: minY,
        maxX: maxX,
        maxY: maxY,
        centroid: sum.divideScalar( il )

    };

    if (v3) {

        ret.maxZ = maxZ;
        ret.minZ = minZ;

    }

    return ret;

};

/**************************************************************
 *    Create Geometries Helpers
 **************************************************************/

/// Generate geometry from path points (for Line or ParticleSystem objects)

THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) {

    var pts = this.getPoints( divisions, true );
    return this.createGeometry( pts );

};

// Generate geometry from equidistance sampling along the path

THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) {

    var pts = this.getSpacedPoints( divisions, true );
    return this.createGeometry( pts );

};

THREE.CurvePath.prototype.createGeometry = function( points ) {

    var geometry = new THREE.Geometry();

    for ( var i = 0; i < points.length; i ++ ) {

        geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) );

    }

    return geometry;

};


/**************************************************************
 *    Bend / Wrap Helper Methods
 **************************************************************/

// Wrap path / Bend modifiers?

THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) {

    this.bends.push( bendpath );

};

THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) {

    var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
    var i, il;

    if ( !bends ) {

        bends = this.bends;

    }

    for ( i = 0, il = bends.length; i < il; i ++ ) {

        oldPts = this.getWrapPoints( oldPts, bends[ i ] );

    }

    return oldPts;

};

THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) {

    var oldPts = this.getSpacedPoints( segments );

    var i, il;

    if ( !bends ) {

        bends = this.bends;

    }

    for ( i = 0, il = bends.length; i < il; i ++ ) {

        oldPts = this.getWrapPoints( oldPts, bends[ i ] );

    }

    return oldPts;

};

// This returns getPoints() bend/wrapped around the contour of a path.
// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html

THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) {

    var bounds = this.getBoundingBox();

    var i, il, p, oldX, oldY, xNorm;

    for ( i = 0, il = oldPts.length; i < il; i ++ ) {

        p = oldPts[ i ];

        oldX = p.x;
        oldY = p.y;

        xNorm = oldX / bounds.maxX;

        // If using actual distance, for length > path, requires line extrusions
        //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance

        xNorm = path.getUtoTmapping( xNorm, oldX );

        // check for out of bounds?

        var pathPt = path.getPoint( xNorm );
        var normal = path.getNormalVector( xNorm ).multiplyScalar( oldY );

        p.x = pathPt.x + normal.x;
        p.y = pathPt.y + normal.y;

    }

    return oldPts;

};

/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Gyroscope = function () {

    THREE.Object3D.call( this );

};

THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype );

THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) {

    this.matrixAutoUpdate && this.updateMatrix();

    // update matrixWorld

    if ( this.matrixWorldNeedsUpdate || force ) {

        if ( this.parent ) {

            this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix );

            this.matrixWorld.decompose( this.translationWorld, this.rotationWorld, this.scaleWorld );
            this.matrix.decompose( this.translationObject, this.rotationObject, this.scaleObject );

            this.matrixWorld.compose( this.translationWorld, this.rotationObject, this.scaleWorld );


        } else {

            this.matrixWorld.copy( this.matrix );

        }


        this.matrixWorldNeedsUpdate = false;

        force = true;

    }

    // update children

    for ( var i = 0, l = this.children.length; i < l; i ++ ) {

        this.children[ i ].updateMatrixWorld( force );

    }

};

THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3();
THREE.Gyroscope.prototype.translationObject = new THREE.Vector3();
THREE.Gyroscope.prototype.rotationWorld = new THREE.Quaternion();
THREE.Gyroscope.prototype.rotationObject = new THREE.Quaternion();
THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3();
THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3();

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * Creates free form 2d path using series of points, lines or curves.
 *
 **/

THREE.Path = function ( points ) {

    THREE.CurvePath.call(this);

    this.actions = [];

    if ( points ) {

        this.fromPoints( points );

    }

};

THREE.Path.prototype = Object.create( THREE.CurvePath.prototype );

THREE.PathActions = {

    MOVE_TO: 'moveTo',
    LINE_TO: 'lineTo',
    QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
    BEZIER_CURVE_TO: 'bezierCurveTo',         // Bezier cubic curve
    CSPLINE_THRU: 'splineThru',                // Catmull-rom spline
    ARC: 'arc',                                // Circle
    ELLIPSE: 'ellipse'
};

// TODO Clean up PATH API

// Create path using straight lines to connect all points
// - vectors: array of Vector2

THREE.Path.prototype.fromPoints = function ( vectors ) {

    this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );

    for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) {

        this.lineTo( vectors[ v ].x, vectors[ v ].y );

    };

};

// startPath() endPath()?

THREE.Path.prototype.moveTo = function ( x, y ) {

    var args = Array.prototype.slice.call( arguments );
    this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } );

};

THREE.Path.prototype.lineTo = function ( x, y ) {

    var args = Array.prototype.slice.call( arguments );

    var lastargs = this.actions[ this.actions.length - 1 ].args;

    var x0 = lastargs[ lastargs.length - 2 ];
    var y0 = lastargs[ lastargs.length - 1 ];

    var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );
    this.curves.push( curve );

    this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } );

};

THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {

    var args = Array.prototype.slice.call( arguments );

    var lastargs = this.actions[ this.actions.length - 1 ].args;

    var x0 = lastargs[ lastargs.length - 2 ];
    var y0 = lastargs[ lastargs.length - 1 ];

    var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),
                                                new THREE.Vector2( aCPx, aCPy ),
                                                new THREE.Vector2( aX, aY ) );
    this.curves.push( curve );

    this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );

};

THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y,
                                               aCP2x, aCP2y,
                                               aX, aY ) {

    var args = Array.prototype.slice.call( arguments );

    var lastargs = this.actions[ this.actions.length - 1 ].args;

    var x0 = lastargs[ lastargs.length - 2 ];
    var y0 = lastargs[ lastargs.length - 1 ];

    var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ),
                                            new THREE.Vector2( aCP1x, aCP1y ),
                                            new THREE.Vector2( aCP2x, aCP2y ),
                                            new THREE.Vector2( aX, aY ) );
    this.curves.push( curve );

    this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } );

};

THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {

    var args = Array.prototype.slice.call( arguments );
    var lastargs = this.actions[ this.actions.length - 1 ].args;

    var x0 = lastargs[ lastargs.length - 2 ];
    var y0 = lastargs[ lastargs.length - 1 ];
//---
    var npts = [ new THREE.Vector2( x0, y0 ) ];
    Array.prototype.push.apply( npts, pts );

    var curve = new THREE.SplineCurve( npts );
    this.curves.push( curve );

    this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } );

};

// FUTURE: Change the API or follow canvas API?

THREE.Path.prototype.arc = function ( aX, aY, aRadius,
                                      aStartAngle, aEndAngle, aClockwise ) {

    var lastargs = this.actions[ this.actions.length - 1].args;
    var x0 = lastargs[ lastargs.length - 2 ];
    var y0 = lastargs[ lastargs.length - 1 ];

    this.absarc(aX + x0, aY + y0, aRadius,
        aStartAngle, aEndAngle, aClockwise );

 };

 THREE.Path.prototype.absarc = function ( aX, aY, aRadius,
                                      aStartAngle, aEndAngle, aClockwise ) {
    this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
 };

THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
                                      aStartAngle, aEndAngle, aClockwise ) {

    var lastargs = this.actions[ this.actions.length - 1].args;
    var x0 = lastargs[ lastargs.length - 2 ];
    var y0 = lastargs[ lastargs.length - 1 ];

    this.absellipse(aX + x0, aY + y0, xRadius, yRadius,
        aStartAngle, aEndAngle, aClockwise );

 };


THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius,
                                      aStartAngle, aEndAngle, aClockwise ) {

    var args = Array.prototype.slice.call( arguments );
    var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
                                    aStartAngle, aEndAngle, aClockwise );
    this.curves.push( curve );

    var lastPoint = curve.getPoint(aClockwise ? 1 : 0);
    args.push(lastPoint.x);
    args.push(lastPoint.y);

    this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );

 };

THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {

    if ( ! divisions ) divisions = 40;

    var points = [];

    for ( var i = 0; i < divisions; i ++ ) {

        points.push( this.getPoint( i / divisions ) );

        //if( !this.getPoint( i / divisions ) ) throw "DIE";

    }

    // if ( closedPath ) {
    //
    //     points.push( points[ 0 ] );
    //
    // }

    return points;

};

/* Return an array of vectors based on contour of the path */

THREE.Path.prototype.getPoints = function( divisions, closedPath ) {

    if (this.useSpacedPoints) {
        console.log('tata');
        return this.getSpacedPoints( divisions, closedPath );
    }

    divisions = divisions || 12;

    var points = [];

    var i, il, item, action, args;
    var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
        laste, j,
        t, tx, ty;

    for ( i = 0, il = this.actions.length; i < il; i ++ ) {

        item = this.actions[ i ];

        action = item.action;
        args = item.args;

        switch( action ) {

        case THREE.PathActions.MOVE_TO:

            points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );

            break;

        case THREE.PathActions.LINE_TO:

            points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );

            break;

        case THREE.PathActions.QUADRATIC_CURVE_TO:

            cpx  = args[ 2 ];
            cpy  = args[ 3 ];

            cpx1 = args[ 0 ];
            cpy1 = args[ 1 ];

            if ( points.length > 0 ) {

                laste = points[ points.length - 1 ];

                cpx0 = laste.x;
                cpy0 = laste.y;

            } else {

                laste = this.actions[ i - 1 ].args;

                cpx0 = laste[ laste.length - 2 ];
                cpy0 = laste[ laste.length - 1 ];

            }

            for ( j = 1; j <= divisions; j ++ ) {

                t = j / divisions;

                tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
                ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );

                points.push( new THREE.Vector2( tx, ty ) );

              }

            break;

        case THREE.PathActions.BEZIER_CURVE_TO:

            cpx  = args[ 4 ];
            cpy  = args[ 5 ];

            cpx1 = args[ 0 ];
            cpy1 = args[ 1 ];

            cpx2 = args[ 2 ];
            cpy2 = args[ 3 ];

            if ( points.length > 0 ) {

                laste = points[ points.length - 1 ];

                cpx0 = laste.x;
                cpy0 = laste.y;

            } else {

                laste = this.actions[ i - 1 ].args;

                cpx0 = laste[ laste.length - 2 ];
                cpy0 = laste[ laste.length - 1 ];

            }


            for ( j = 1; j <= divisions; j ++ ) {

                t = j / divisions;

                tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
                ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );

                points.push( new THREE.Vector2( tx, ty ) );

            }

            break;

        case THREE.PathActions.CSPLINE_THRU:

            laste = this.actions[ i - 1 ].args;

            var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
            var spts = [ last ];

            var n = divisions * args[ 0 ].length;

            spts = spts.concat( args[ 0 ] );

            var spline = new THREE.SplineCurve( spts );

            for ( j = 1; j <= n; j ++ ) {

                points.push( spline.getPointAt( j / n ) ) ;

            }

            break;

        case THREE.PathActions.ARC:

            var aX = args[ 0 ], aY = args[ 1 ],
                aRadius = args[ 2 ],
                aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
                aClockwise = !!args[ 5 ];

            var deltaAngle = aEndAngle - aStartAngle;
            var angle;
            var tdivisions = divisions * 2;

            for ( j = 1; j <= tdivisions; j ++ ) {

                t = j / tdivisions;

                if ( ! aClockwise ) {

                    t = 1 - t;

                }

                angle = aStartAngle + t * deltaAngle;

                tx = aX + aRadius * Math.cos( angle );
                ty = aY + aRadius * Math.sin( angle );

                //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);

                points.push( new THREE.Vector2( tx, ty ) );

            }

            //console.log(points);

          break;

        case THREE.PathActions.ELLIPSE:

            var aX = args[ 0 ], aY = args[ 1 ],
                xRadius = args[ 2 ],
                yRadius = args[ 3 ],
                aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
                aClockwise = !!args[ 6 ];


            var deltaAngle = aEndAngle - aStartAngle;
            var angle;
            var tdivisions = divisions * 2;

            for ( j = 1; j <= tdivisions; j ++ ) {

                t = j / tdivisions;

                if ( ! aClockwise ) {

                    t = 1 - t;

                }

                angle = aStartAngle + t * deltaAngle;

                tx = aX + xRadius * Math.cos( angle );
                ty = aY + yRadius * Math.sin( angle );

                //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);

                points.push( new THREE.Vector2( tx, ty ) );

            }

            //console.log(points);

          break;

        } // end switch

    }



    // Normalize to remove the closing point by default.
    var lastPoint = points[ points.length - 1];
    var EPSILON = 0.0000000001;
    if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON &&
             Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)
        points.splice( points.length - 1, 1);
    if ( closedPath ) {

        points.push( points[ 0 ] );

    }

    return points;

};

// Breaks path into shapes

THREE.Path.prototype.toShapes = function() {

    var i, il, item, action, args;

    var subPaths = [], lastPath = new THREE.Path();

    for ( i = 0, il = this.actions.length; i < il; i ++ ) {

        item = this.actions[ i ];

        args = item.args;
        action = item.action;

        if ( action == THREE.PathActions.MOVE_TO ) {

            if ( lastPath.actions.length != 0 ) {

                subPaths.push( lastPath );
                lastPath = new THREE.Path();

            }

        }

        lastPath[ action ].apply( lastPath, args );

    }

    if ( lastPath.actions.length != 0 ) {

        subPaths.push( lastPath );

    }

    // console.log(subPaths);

    if ( subPaths.length == 0 ) return [];

    var tmpPath, tmpShape, shapes = [];

    var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
    // console.log("Holes first", holesFirst);

    if ( subPaths.length == 1) {
        tmpPath = subPaths[0];
        tmpShape = new THREE.Shape();
        tmpShape.actions = tmpPath.actions;
        tmpShape.curves = tmpPath.curves;
        shapes.push( tmpShape );
        return shapes;
    };

    if ( holesFirst ) {

        tmpShape = new THREE.Shape();

        for ( i = 0, il = subPaths.length; i < il; i ++ ) {

            tmpPath = subPaths[ i ];

            if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) {

                tmpShape.actions = tmpPath.actions;
                tmpShape.curves = tmpPath.curves;

                shapes.push( tmpShape );
                tmpShape = new THREE.Shape();

                //console.log('cw', i);

            } else {

                tmpShape.holes.push( tmpPath );

                //console.log('ccw', i);

            }

        }

    } else {

        // Shapes first

        for ( i = 0, il = subPaths.length; i < il; i ++ ) {

            tmpPath = subPaths[ i ];

            if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) {


                if ( tmpShape ) shapes.push( tmpShape );

                tmpShape = new THREE.Shape();
                tmpShape.actions = tmpPath.actions;
                tmpShape.curves = tmpPath.curves;

            } else {

                tmpShape.holes.push( tmpPath );

            }

        }

        shapes.push( tmpShape );

    }

    //console.log("shape", shapes);

    return shapes;

};
/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * Defines a 2d shape plane using paths.
 **/

// STEP 1 Create a path.
// STEP 2 Turn path into shape.
// STEP 3 ExtrudeGeometry takes in Shape/Shapes
// STEP 3a - Extract points from each shape, turn to vertices
// STEP 3b - Triangulate each shape, add faces.

THREE.Shape = function ( ) {

    THREE.Path.apply( this, arguments );
    this.holes = [];

};

THREE.Shape.prototype = Object.create( THREE.Path.prototype );

// Convenience method to return ExtrudeGeometry

THREE.Shape.prototype.extrude = function ( options ) {

    var extruded = new THREE.ExtrudeGeometry( this, options );
    return extruded;

};

// Convenience method to return ShapeGeometry

THREE.Shape.prototype.makeGeometry = function ( options ) {

    var geometry = new THREE.ShapeGeometry( this, options );
    return geometry;

};

// Get points of holes

THREE.Shape.prototype.getPointsHoles = function ( divisions ) {

    var i, il = this.holes.length, holesPts = [];

    for ( i = 0; i < il; i ++ ) {

        holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );

    }

    return holesPts;

};

// Get points of holes (spaced by regular distance)

THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {

    var i, il = this.holes.length, holesPts = [];

    for ( i = 0; i < il; i ++ ) {

        holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );

    }

    return holesPts;

};


// Get points of shape and holes (keypoints based on segments parameter)

THREE.Shape.prototype.extractAllPoints = function ( divisions ) {

    return {

        shape: this.getTransformedPoints( divisions ),
        holes: this.getPointsHoles( divisions )

    };

};

THREE.Shape.prototype.extractPoints = function ( divisions ) {

    if (this.useSpacedPoints) {
        return this.extractAllSpacedPoints(divisions);
    }

    return this.extractAllPoints(divisions);

};

//
// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
//
//     return {
//
//         shape: this.transform( bend, divisions ),
//         holes: this.getPointsHoles( divisions, bend )
//
//     };
//
// };

// Get points of shape and holes (spaced by regular distance)

THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {

    return {

        shape: this.getTransformedSpacedPoints( divisions ),
        holes: this.getSpacedPointsHoles( divisions )

    };

};

/**************************************************************
 *    Utils
 **************************************************************/

THREE.Shape.Utils = {

    /*
        contour - array of vector2 for contour
        holes   - array of array of vector2
    */

    removeHoles: function ( contour, holes ) {

        var shape = contour.concat(); // work on this shape
        var allpoints = shape.concat();

        /* For each isolated shape, find the closest points and break to the hole to allow triangulation */


        var prevShapeVert, nextShapeVert,
            prevHoleVert, nextHoleVert,
            holeIndex, shapeIndex,
            shapeId, shapeGroup,
            h, h2,
            hole, shortest, d,
            p, pts1, pts2,
            tmpShape1, tmpShape2,
            tmpHole1, tmpHole2,
            verts = [];

        for ( h = 0; h < holes.length; h ++ ) {

            hole = holes[ h ];

            /*
            shapeholes[ h ].concat(); // preserves original
            holes.push( hole );
            */

            Array.prototype.push.apply( allpoints, hole );

            shortest = Number.POSITIVE_INFINITY;


            // Find the shortest pair of pts between shape and hole

            // Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n)
            // Using distanceToSquared() intead of distanceTo() should speed a little
            // since running square roots operations are reduced.

            for ( h2 = 0; h2 < hole.length; h2 ++ ) {

                pts1 = hole[ h2 ];
                var dist = [];

                for ( p = 0; p < shape.length; p++ ) {

                    pts2 = shape[ p ];
                    d = pts1.distanceToSquared( pts2 );
                    dist.push( d );

                    if ( d < shortest ) {

                        shortest = d;
                        holeIndex = h2;
                        shapeIndex = p;

                    }

                }

            }

            //console.log("shortest", shortest, dist);

            prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
            prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;

            var areaapts = [

                hole[ holeIndex ],
                shape[ shapeIndex ],
                shape[ prevShapeVert ]

            ];

            var areaa = THREE.FontUtils.Triangulate.area( areaapts );

            var areabpts = [

                hole[ holeIndex ],
                hole[ prevHoleVert ],
                shape[ shapeIndex ]

            ];

            var areab = THREE.FontUtils.Triangulate.area( areabpts );

            var shapeOffset = 1;
            var holeOffset = -1;

            var oldShapeIndex = shapeIndex, oldHoleIndex = holeIndex;
            shapeIndex += shapeOffset;
            holeIndex += holeOffset;

            if ( shapeIndex < 0 ) { shapeIndex += shape.length;  }
            shapeIndex %= shape.length;

            if ( holeIndex < 0 ) { holeIndex += hole.length;  }
            holeIndex %= hole.length;

            prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
            prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;

            areaapts = [

                hole[ holeIndex ],
                shape[ shapeIndex ],
                shape[ prevShapeVert ]

            ];

            var areaa2 = THREE.FontUtils.Triangulate.area( areaapts );

            areabpts = [

                hole[ holeIndex ],
                hole[ prevHoleVert ],
                shape[ shapeIndex ]

            ];

            var areab2 = THREE.FontUtils.Triangulate.area( areabpts );
            //console.log(areaa,areab ,areaa2,areab2, ( areaa + areab ),  ( areaa2 + areab2 ));

            if ( ( areaa + areab ) > ( areaa2 + areab2 ) ) {

                // In case areas are not correct.
                //console.log("USE THIS");

                shapeIndex = oldShapeIndex;
                holeIndex = oldHoleIndex ;

                if ( shapeIndex < 0 ) { shapeIndex += shape.length;  }
                shapeIndex %= shape.length;

                if ( holeIndex < 0 ) { holeIndex += hole.length;  }
                holeIndex %= hole.length;

                prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
                prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;

            } else {

                //console.log("USE THAT ")

            }

            tmpShape1 = shape.slice( 0, shapeIndex );
            tmpShape2 = shape.slice( shapeIndex );
            tmpHole1 = hole.slice( holeIndex );
            tmpHole2 = hole.slice( 0, holeIndex );

            // Should check orders here again?

            var trianglea = [

                hole[ holeIndex ],
                shape[ shapeIndex ],
                shape[ prevShapeVert ]

            ];

            var triangleb = [

                hole[ holeIndex ] ,
                hole[ prevHoleVert ],
                shape[ shapeIndex ]

            ];

            verts.push( trianglea );
            verts.push( triangleb );

            shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );

        }

        return {

            shape:shape,         /* shape with no holes */
            isolatedPts: verts, /* isolated faces */
            allpoints: allpoints

        }


    },

    triangulateShape: function ( contour, holes ) {

        var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes );

        var shape = shapeWithoutHoles.shape,
            allpoints = shapeWithoutHoles.allpoints,
            isolatedPts = shapeWithoutHoles.isolatedPts;

        var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape

        // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.

        //console.log( "triangles",triangles, triangles.length );
        //console.log( "allpoints",allpoints, allpoints.length );

        var i, il, f, face,
            key, index,
            allPointsMap = {},
            isolatedPointsMap = {};

        // prepare all points map

        for ( i = 0, il = allpoints.length; i < il; i ++ ) {

            key = allpoints[ i ].x + ":" + allpoints[ i ].y;

            if ( allPointsMap[ key ] !== undefined ) {

                console.log( "Duplicate point", key );

            }

            allPointsMap[ key ] = i;

        }

        // check all face vertices against all points map

        for ( i = 0, il = triangles.length; i < il; i ++ ) {

            face = triangles[ i ];

            for ( f = 0; f < 3; f ++ ) {

                key = face[ f ].x + ":" + face[ f ].y;

                index = allPointsMap[ key ];

                if ( index !== undefined ) {

                    face[ f ] = index;

                }

            }

        }

        // check isolated points vertices against all points map

        for ( i = 0, il = isolatedPts.length; i < il; i ++ ) {

            face = isolatedPts[ i ];

            for ( f = 0; f < 3; f ++ ) {

                key = face[ f ].x + ":" + face[ f ].y;

                index = allPointsMap[ key ];

                if ( index !== undefined ) {

                    face[ f ] = index;

                }

            }

        }

        return triangles.concat( isolatedPts );

    }, // end triangulate shapes

    /*
    triangulate2 : function( pts, holes ) {

        // For use with Poly2Tri.js

        var allpts = pts.concat();
        var shape = [];
        for (var p in pts) {
            shape.push(new js.poly2tri.Point(pts[p].x, pts[p].y));
        }

        var swctx = new js.poly2tri.SweepContext(shape);

        for (var h in holes) {
            var aHole = holes[h];
            var newHole = []
            for (i in aHole) {
                newHole.push(new js.poly2tri.Point(aHole[i].x, aHole[i].y));
                allpts.push(aHole[i]);
            }
            swctx.AddHole(newHole);
        }

        var find;
        var findIndexForPt = function (pt) {
            find = new THREE.Vector2(pt.x, pt.y);
            var p;
            for (p=0, pl = allpts.length; p<pl; p++) {
                if (allpts[p].equals(find)) return p;
            }
            return -1;
        };

        // triangulate
        js.poly2tri.sweep.Triangulate(swctx);

        var triangles =  swctx.GetTriangles();
        var tr ;
        var facesPts = [];
        for (var t in triangles) {
            tr =  triangles[t];
            facesPts.push([
                findIndexForPt(tr.GetPoint(0)),
                findIndexForPt(tr.GetPoint(1)),
                findIndexForPt(tr.GetPoint(2))
                    ]);
        }


    //    console.log(facesPts);
    //    console.log("triangles", triangles.length, triangles);

        // Returns array of faces with 3 element each
    return facesPts;
    },
*/

    isClockWise: function ( pts ) {

        return THREE.FontUtils.Triangulate.area( pts ) < 0;

    },

    // Bezier Curves formulas obtained from
    // http://en.wikipedia.org/wiki/B%C3%A9zier_curve

    // Quad Bezier Functions

    b2p0: function ( t, p ) {

        var k = 1 - t;
        return k * k * p;

    },

    b2p1: function ( t, p ) {

        return 2 * ( 1 - t ) * t * p;

    },

    b2p2: function ( t, p ) {

        return t * t * p;

    },

    b2: function ( t, p0, p1, p2 ) {

        return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );

    },

    // Cubic Bezier Functions

    b3p0: function ( t, p ) {

        var k = 1 - t;
        return k * k * k * p;

    },

    b3p1: function ( t, p ) {

        var k = 1 - t;
        return 3 * k * k * t * p;

    },

    b3p2: function ( t, p ) {

        var k = 1 - t;
        return 3 * k * t * t * p;

    },

    b3p3: function ( t, p ) {

        return t * t * t * p;

    },

    b3: function ( t, p0, p1, p2, p3 ) {

        return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) +  this.b3p3( t, p3 );

    }

};

/**
 * @author mikael emtinger / http://gomo.se/
 */

THREE.AnimationHandler = (function() {

    var playing = [];
    var library = {};
    var that    = {};


    //--- update ---

    that.update = function( deltaTimeMS ) {

        for( var i = 0; i < playing.length; i ++ )
            playing[ i ].update( deltaTimeMS );

    };


    //--- add ---

    that.addToUpdate = function( animation ) {

        if ( playing.indexOf( animation ) === -1 )
            playing.push( animation );

    };


    //--- remove ---

    that.removeFromUpdate = function( animation ) {

        var index = playing.indexOf( animation );

        if( index !== -1 )
            playing.splice( index, 1 );

    };


    //--- add ---

    that.add = function( data ) {

        if ( library[ data.name ] !== undefined )
            console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." );

        library[ data.name ] = data;
        initData( data );

    };


    //--- get ---

    that.get = function( name ) {

        if ( typeof name === "string" ) {

            if ( library[ name ] ) {

                return library[ name ];

            } else {

                console.log( "THREE.AnimationHandler.get: Couldn't find animation " + name );
                return null;

            }

        } else {

            // todo: add simple tween library

        }

    };

    //--- parse ---

    that.parse = function( root ) {

        // setup hierarchy

        var hierarchy = [];

        if ( root instanceof THREE.SkinnedMesh ) {

            for( var b = 0; b < root.bones.length; b++ ) {

                hierarchy.push( root.bones[ b ] );

            }

        } else {

            parseRecurseHierarchy( root, hierarchy );

        }

        return hierarchy;

    };

    var parseRecurseHierarchy = function( root, hierarchy ) {

        hierarchy.push( root );

        for( var c = 0; c < root.children.length; c++ )
            parseRecurseHierarchy( root.children[ c ], hierarchy );

    }


    //--- init data ---

    var initData = function( data ) {

        if( data.initialized === true )
            return;


        // loop through all keys

        for( var h = 0; h < data.hierarchy.length; h ++ ) {

            for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {

                // remove minus times

                if( data.hierarchy[ h ].keys[ k ].time < 0 )
                    data.hierarchy[ h ].keys[ k ].time = 0;


                // create quaternions

                if( data.hierarchy[ h ].keys[ k ].rot !== undefined &&
                 !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) {

                    var quat = data.hierarchy[ h ].keys[ k ].rot;
                    data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] );

                }

            }


            // prepare morph target keys

            if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) {

                // get all used

                var usedMorphTargets = {};

                for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {

                    for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {

                        var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ];
                        usedMorphTargets[ morphTargetName ] = -1;

                    }

                }

                data.hierarchy[ h ].usedMorphTargets = usedMorphTargets;


                // set all used on all frames

                for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {

                    var influences = {};

                    for ( var morphTargetName in usedMorphTargets ) {

                        for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {

                            if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) {

                                influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ];
                                break;

                            }

                        }

                        if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) {

                            influences[ morphTargetName ] = 0;

                        }

                    }

                    data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences;

                }

            }


            // remove all keys that are on the same time

            for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) {

                if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) {

                    data.hierarchy[ h ].keys.splice( k, 1 );
                    k --;

                }

            }


            // set index

            for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {

                data.hierarchy[ h ].keys[ k ].index = k;

            }

        }


        // JIT

        var lengthInFrames = parseInt( data.length * data.fps, 10 );

        data.JIT = {};
        data.JIT.hierarchy = [];

        for( var h = 0; h < data.hierarchy.length; h ++ )
            data.JIT.hierarchy.push( new Array( lengthInFrames ) );


        // done

        data.initialized = true;

    };


    // interpolation types

    that.LINEAR = 0;
    that.CATMULLROM = 1;
    that.CATMULLROM_FORWARD = 2;

    return that;

}());
/**
 * @author mikael emtinger / http://gomo.se/
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Animation = function ( root, name, interpolationType ) {

    this.root = root;
    this.data = THREE.AnimationHandler.get( name );
    this.hierarchy = THREE.AnimationHandler.parse( root );

    this.currentTime = 0;
    this.timeScale = 1;

    this.isPlaying = false;
    this.isPaused = true;
    this.loop = true;

    this.interpolationType = interpolationType !== undefined ? interpolationType : THREE.AnimationHandler.LINEAR;

    this.points = [];
    this.target = new THREE.Vector3();

};

THREE.Animation.prototype.play = function ( loop, startTimeMS ) {

    if ( this.isPlaying === false ) {

        this.isPlaying = true;
        this.loop = loop !== undefined ? loop : true;
        this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;

        // reset key cache

        var h, hl = this.hierarchy.length,
            object;

        for ( h = 0; h < hl; h ++ ) {

            object = this.hierarchy[ h ];

            if ( this.interpolationType !== THREE.AnimationHandler.CATMULLROM_FORWARD ) {

                object.useQuaternion = true;

            }

            object.matrixAutoUpdate = true;

            if ( object.animationCache === undefined ) {

                object.animationCache = {};
                object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 };
                object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 };
                object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;

            }

            var prevKey = object.animationCache.prevKey;
            var nextKey = object.animationCache.nextKey;

            prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
            prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
            prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];

            nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
            nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
            nextKey.scl = this.getNextKeyWith( "scl", h, 1 );

        }

        this.update( 0 );

    }

    this.isPaused = false;

    THREE.AnimationHandler.addToUpdate( this );

};


THREE.Animation.prototype.pause = function() {

    if ( this.isPaused === true ) {

        THREE.AnimationHandler.addToUpdate( this );

    } else {

        THREE.AnimationHandler.removeFromUpdate( this );

    }

    this.isPaused = !this.isPaused;

};


THREE.Animation.prototype.stop = function() {

    this.isPlaying = false;
    this.isPaused  = false;
    THREE.AnimationHandler.removeFromUpdate( this );

};


THREE.Animation.prototype.update = function ( deltaTimeMS ) {

    // early out

    if ( this.isPlaying === false ) return;


    // vars

    var types = [ "pos", "rot", "scl" ];
    var type;
    var scale;
    var vector;
    var prevXYZ, nextXYZ;
    var prevKey, nextKey;
    var object;
    var animationCache;
    var frame;
    var JIThierarchy = this.data.JIT.hierarchy;
    var currentTime, unloopedCurrentTime;
    var currentPoint, forwardPoint, angle;


    this.currentTime += deltaTimeMS * this.timeScale;

    unloopedCurrentTime = this.currentTime;
    currentTime = this.currentTime = this.currentTime % this.data.length;
    frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );


    for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {

        object = this.hierarchy[ h ];
        animationCache = object.animationCache;

        // loop through pos/rot/scl

        for ( var t = 0; t < 3; t ++ ) {

            // get keys

            type    = types[ t ];
            prevKey = animationCache.prevKey[ type ];
            nextKey = animationCache.nextKey[ type ];

            // switch keys?

            if ( nextKey.time <= unloopedCurrentTime ) {

                // did we loop?

                if ( currentTime < unloopedCurrentTime ) {

                    if ( this.loop ) {

                        prevKey = this.data.hierarchy[ h ].keys[ 0 ];
                        nextKey = this.getNextKeyWith( type, h, 1 );

                        while( nextKey.time < currentTime ) {

                            prevKey = nextKey;
                            nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );

                        }

                    } else {

                        this.stop();
                        return;

                    }

                } else {

                    do {

                        prevKey = nextKey;
                        nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );

                    } while( nextKey.time < currentTime )

                }

                animationCache.prevKey[ type ] = prevKey;
                animationCache.nextKey[ type ] = nextKey;

            }


            object.matrixAutoUpdate = true;
            object.matrixWorldNeedsUpdate = true;

            scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
            prevXYZ = prevKey[ type ];
            nextXYZ = nextKey[ type ];


            // check scale error

            if ( scale < 0 || scale > 1 ) {

                console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h );
                scale = scale < 0 ? 0 : 1;

            }

            // interpolate

            if ( type === "pos" ) {

                vector = object.position;

                if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {

                    vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
                    vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
                    vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;

                } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
                            this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {

                    this.points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
                    this.points[ 1 ] = prevXYZ;
                    this.points[ 2 ] = nextXYZ;
                    this.points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ];

                    scale = scale * 0.33 + 0.33;

                    currentPoint = this.interpolateCatmullRom( this.points, scale );

                    vector.x = currentPoint[ 0 ];
                    vector.y = currentPoint[ 1 ];
                    vector.z = currentPoint[ 2 ];

                    if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {

                        forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 );

                        this.target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
                        this.target.subSelf( vector );
                        this.target.y = 0;
                        this.target.normalize();

                        angle = Math.atan2( this.target.x, this.target.z );
                        object.rotation.set( 0, angle, 0 );

                    }

                }

            } else if ( type === "rot" ) {

                THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale );

            } else if ( type === "scl" ) {

                vector = object.scale;

                vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
                vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
                vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;

            }

        }

    }

};

// Catmull-Rom spline

THREE.Animation.prototype.interpolateCatmullRom = function ( points, scale ) {

    var c = [], v3 = [],
    point, intPoint, weight, w2, w3,
    pa, pb, pc, pd;

    point = ( points.length - 1 ) * scale;
    intPoint = Math.floor( point );
    weight = point - intPoint;

    c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
    c[ 1 ] = intPoint;
    c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;
    c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;

    pa = points[ c[ 0 ] ];
    pb = points[ c[ 1 ] ];
    pc = points[ c[ 2 ] ];
    pd = points[ c[ 3 ] ];

    w2 = weight * weight;
    w3 = weight * w2;

    v3[ 0 ] = this.interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
    v3[ 1 ] = this.interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
    v3[ 2 ] = this.interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );

    return v3;

};

THREE.Animation.prototype.interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {

    var v0 = ( p2 - p0 ) * 0.5,
        v1 = ( p3 - p1 ) * 0.5;

    return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;

};



// Get next key with

THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) {

    var keys = this.data.hierarchy[ h ].keys;

    if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
         this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {

        key = key < keys.length - 1 ? key : keys.length - 1;

    } else {

        key = key % keys.length;

    }

    for ( ; key < keys.length; key++ ) {

        if ( keys[ key ][ type ] !== undefined ) {

            return keys[ key ];

        }

    }

    return this.data.hierarchy[ h ].keys[ 0 ];

};

// Get previous key with

THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) {

    var keys = this.data.hierarchy[ h ].keys;

    if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
         this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {

        key = key > 0 ? key : 0;

    } else {

        key = key >= 0 ? key : key + keys.length;

    }


    for ( ; key >= 0; key -- ) {

        if ( keys[ key ][ type ] !== undefined ) {

            return keys[ key ];

        }

    }

    return this.data.hierarchy[ h ].keys[ keys.length - 1 ];

};
/**
 * @author mikael emtinger / http://gomo.se/
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author khang duong
 * @author erik kitson
 */

THREE.KeyFrameAnimation = function( root, data, JITCompile ) {

    this.root = root;
    this.data = THREE.AnimationHandler.get( data );
    this.hierarchy = THREE.AnimationHandler.parse( root );
    this.currentTime = 0;
    this.timeScale = 0.001;
    this.isPlaying = false;
    this.isPaused = true;
    this.loop = true;
    this.JITCompile = JITCompile !== undefined ? JITCompile : true;

    // initialize to first keyframes

    for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {

        var keys = this.data.hierarchy[h].keys,
            sids = this.data.hierarchy[h].sids,
            obj = this.hierarchy[h];

        if ( keys.length && sids ) {

            for ( var s = 0; s < sids.length; s++ ) {

                var sid = sids[ s ],
                    next = this.getNextKeyWith( sid, h, 0 );

                if ( next ) {

                    next.apply( sid );

                }

            }

            obj.matrixAutoUpdate = false;
            this.data.hierarchy[h].node.updateMatrix();
            obj.matrixWorldNeedsUpdate = true;

        }

    }

};

// Play

THREE.KeyFrameAnimation.prototype.play = function( loop, startTimeMS ) {

    if( !this.isPlaying ) {

        this.isPlaying = true;
        this.loop = loop !== undefined ? loop : true;
        this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
        this.startTimeMs = startTimeMS;
        this.startTime = 10000000;
        this.endTime = -this.startTime;


        // reset key cache

        var h, hl = this.hierarchy.length,
            object,
            node;

        for ( h = 0; h < hl; h++ ) {

            object = this.hierarchy[ h ];
            node = this.data.hierarchy[ h ];
            object.useQuaternion = true;

            if ( node.animationCache === undefined ) {

                node.animationCache = {};
                node.animationCache.prevKey = null;
                node.animationCache.nextKey = null;
                node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;

            }

            var keys = this.data.hierarchy[h].keys;

            if (keys.length) {

                node.animationCache.prevKey = keys[ 0 ];
                node.animationCache.nextKey = keys[ 1 ];

                this.startTime = Math.min( keys[0].time, this.startTime );
                this.endTime = Math.max( keys[keys.length - 1].time, this.endTime );

            }

        }

        this.update( 0 );

    }

    this.isPaused = false;

    THREE.AnimationHandler.addToUpdate( this );

};



// Pause

THREE.KeyFrameAnimation.prototype.pause = function() {

    if( this.isPaused ) {

        THREE.AnimationHandler.addToUpdate( this );

    } else {

        THREE.AnimationHandler.removeFromUpdate( this );

    }

    this.isPaused = !this.isPaused;

};


// Stop

THREE.KeyFrameAnimation.prototype.stop = function() {

    this.isPlaying = false;
    this.isPaused  = false;
    THREE.AnimationHandler.removeFromUpdate( this );


    // reset JIT matrix and remove cache

    for ( var h = 0; h < this.data.hierarchy.length; h++ ) {

        var obj = this.hierarchy[ h ];
        var node = this.data.hierarchy[ h ];

        if ( node.animationCache !== undefined ) {

            var original = node.animationCache.originalMatrix;

            if( obj instanceof THREE.Bone ) {

                original.copy( obj.skinMatrix );
                obj.skinMatrix = original;

            } else {

                original.copy( obj.matrix );
                obj.matrix = original;

            }

            delete node.animationCache;

        }

    }

};


// Update

THREE.KeyFrameAnimation.prototype.update = function( deltaTimeMS ) {

    // early out

    if( !this.isPlaying ) return;


    // vars

    var prevKey, nextKey;
    var object;
    var node;
    var frame;
    var JIThierarchy = this.data.JIT.hierarchy;
    var currentTime, unloopedCurrentTime;
    var looped;


    // update

    this.currentTime += deltaTimeMS * this.timeScale;

    unloopedCurrentTime = this.currentTime;
    currentTime         = this.currentTime = this.currentTime % this.data.length;

    // if looped around, the current time should be based on the startTime
    if ( currentTime < this.startTimeMs ) {

        currentTime = this.currentTime = this.startTimeMs + currentTime;

    }

    frame               = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
    looped                 = currentTime < unloopedCurrentTime;

    if ( looped && !this.loop ) {

        // Set the animation to the last keyframes and stop
        for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {

            var keys = this.data.hierarchy[h].keys,
                sids = this.data.hierarchy[h].sids,
                end = keys.length-1,
                obj = this.hierarchy[h];

            if ( keys.length ) {

                for ( var s = 0; s < sids.length; s++ ) {

                    var sid = sids[ s ],
                        prev = this.getPrevKeyWith( sid, h, end );

                    if ( prev ) {
                        prev.apply( sid );

                    }

                }

                this.data.hierarchy[h].node.updateMatrix();
                obj.matrixWorldNeedsUpdate = true;

            }

        }

        this.stop();
        return;

    }

    // check pre-infinity
    if ( currentTime < this.startTime ) {

        return;

    }

    // update

    for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {

        object = this.hierarchy[ h ];
        node = this.data.hierarchy[ h ];

        var keys = node.keys,
            animationCache = node.animationCache;

        // use JIT?

        if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) {

            if( object instanceof THREE.Bone ) {

                object.skinMatrix = JIThierarchy[ h ][ frame ];
                object.matrixWorldNeedsUpdate = false;

            } else {

                object.matrix = JIThierarchy[ h ][ frame ];
                object.matrixWorldNeedsUpdate = true;

            }

        // use interpolation

        } else if ( keys.length ) {

            // make sure so original matrix and not JIT matrix is set

            if ( this.JITCompile && animationCache ) {

                if( object instanceof THREE.Bone ) {

                    object.skinMatrix = animationCache.originalMatrix;

                } else {

                    object.matrix = animationCache.originalMatrix;

                }

            }

            prevKey = animationCache.prevKey;
            nextKey = animationCache.nextKey;

            if ( prevKey && nextKey ) {

                // switch keys?

                if ( nextKey.time <= unloopedCurrentTime ) {

                    // did we loop?

                    if ( looped && this.loop ) {

                        prevKey = keys[ 0 ];
                        nextKey = keys[ 1 ];

                        while ( nextKey.time < currentTime ) {

                            prevKey = nextKey;
                            nextKey = keys[ prevKey.index + 1 ];

                        }

                    } else if ( !looped ) {

                        var lastIndex = keys.length - 1;

                        while ( nextKey.time < currentTime && nextKey.index !== lastIndex ) {

                            prevKey = nextKey;
                            nextKey = keys[ prevKey.index + 1 ];

                        }

                    }

                    animationCache.prevKey = prevKey;
                    animationCache.nextKey = nextKey;

                }
                if(nextKey.time >= currentTime)
                    prevKey.interpolate( nextKey, currentTime );
                else
                    prevKey.interpolate( nextKey, nextKey.time);

            }

            this.data.hierarchy[h].node.updateMatrix();
            object.matrixWorldNeedsUpdate = true;

        }

    }

    // update JIT?

    if ( this.JITCompile ) {

        if ( JIThierarchy[ 0 ][ frame ] === undefined ) {

            this.hierarchy[ 0 ].updateMatrixWorld( true );

            for ( var h = 0; h < this.hierarchy.length; h++ ) {

                if( this.hierarchy[ h ] instanceof THREE.Bone ) {

                    JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone();

                } else {

                    JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone();

                }

            }

        }

    }

};

// Get next key with

THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) {

    var keys = this.data.hierarchy[ h ].keys;
    key = key % keys.length;

    for ( ; key < keys.length; key++ ) {

        if ( keys[ key ].hasTarget( sid ) ) {

            return keys[ key ];

        }

    }

    return keys[ 0 ];

};

// Get previous key with

THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) {

    var keys = this.data.hierarchy[ h ].keys;
    key = key >= 0 ? key : key + keys.length;

    for ( ; key >= 0; key-- ) {

        if ( keys[ key ].hasTarget( sid ) ) {

            return keys[ key ];

        }

    }

    return keys[ keys.length - 1 ];

};
/**
 * Camera for rendering cube maps
 *    - renders scene into axis-aligned cube
 *
 * @author alteredq / http://alteredqualia.com/
 */

THREE.CubeCamera = function ( near, far, cubeResolution ) {

    THREE.Object3D.call( this );

    var fov = 90, aspect = 1;

    var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far );
    cameraPX.up.set( 0, -1, 0 );
    cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) );
    this.add( cameraPX );

    var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far );
    cameraNX.up.set( 0, -1, 0 );
    cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) );
    this.add( cameraNX );

    var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far );
    cameraPY.up.set( 0, 0, 1 );
    cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) );
    this.add( cameraPY );

    var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far );
    cameraNY.up.set( 0, 0, -1 );
    cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) );
    this.add( cameraNY );

    var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
    cameraPZ.up.set( 0, -1, 0 );
    cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) );
    this.add( cameraPZ );

    var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
    cameraNZ.up.set( 0, -1, 0 );
    cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) );
    this.add( cameraNZ );

    this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );

    this.updateCubeMap = function ( renderer, scene ) {

        var renderTarget = this.renderTarget;
        var generateMipmaps = renderTarget.generateMipmaps;

        renderTarget.generateMipmaps = false;

        renderTarget.activeCubeFace = 0;
        renderer.render( scene, cameraPX, renderTarget );

        renderTarget.activeCubeFace = 1;
        renderer.render( scene, cameraNX, renderTarget );

        renderTarget.activeCubeFace = 2;
        renderer.render( scene, cameraPY, renderTarget );

        renderTarget.activeCubeFace = 3;
        renderer.render( scene, cameraNY, renderTarget );

        renderTarget.activeCubeFace = 4;
        renderer.render( scene, cameraPZ, renderTarget );

        renderTarget.generateMipmaps = generateMipmaps;

        renderTarget.activeCubeFace = 5;
        renderer.render( scene, cameraNZ, renderTarget );

    };

};

THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype );
/*
 *    @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
 *
 *    A general perpose camera, for setting FOV, Lens Focal Length,
 *        and switching between perspective and orthographic views easily.
 *        Use this only if you do not wish to manage
 *        both a Orthographic and Perspective Camera
 *
 */


THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) {

    THREE.Camera.call( this );

    this.fov = fov;

    this.left = -width / 2;
    this.right = width / 2
    this.top = height / 2;
    this.bottom = -height / 2;

    // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects

    this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2,     orthoNear, orthoFar );
    this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far );

    this.zoom = 1;

    this.toPerspective();

    var aspect = width/height;

};

THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype );

THREE.CombinedCamera.prototype.toPerspective = function () {

    // Switches to the Perspective Camera

    this.near = this.cameraP.near;
    this.far = this.cameraP.far;

    this.cameraP.fov =  this.fov / this.zoom ;

    this.cameraP.updateProjectionMatrix();

    this.projectionMatrix = this.cameraP.projectionMatrix;

    this.inPerspectiveMode = true;
    this.inOrthographicMode = false;

};

THREE.CombinedCamera.prototype.toOrthographic = function () {

    // Switches to the Orthographic camera estimating viewport from Perspective

    var fov = this.fov;
    var aspect = this.cameraP.aspect;
    var near = this.cameraP.near;
    var far = this.cameraP.far;

    // The size that we set is the mid plane of the viewing frustum

    var hyperfocus = ( near + far ) / 2;

    var halfHeight = Math.tan( fov / 2 ) * hyperfocus;
    var planeHeight = 2 * halfHeight;
    var planeWidth = planeHeight * aspect;
    var halfWidth = planeWidth / 2;

    halfHeight /= this.zoom;
    halfWidth /= this.zoom;

    this.cameraO.left = -halfWidth;
    this.cameraO.right = halfWidth;
    this.cameraO.top = halfHeight;
    this.cameraO.bottom = -halfHeight;

    // this.cameraO.left = -farHalfWidth;
    // this.cameraO.right = farHalfWidth;
    // this.cameraO.top = farHalfHeight;
    // this.cameraO.bottom = -farHalfHeight;

    // this.cameraO.left = this.left / this.zoom;
    // this.cameraO.right = this.right / this.zoom;
    // this.cameraO.top = this.top / this.zoom;
    // this.cameraO.bottom = this.bottom / this.zoom;

    this.cameraO.updateProjectionMatrix();

    this.near = this.cameraO.near;
    this.far = this.cameraO.far;
    this.projectionMatrix = this.cameraO.projectionMatrix;

    this.inPerspectiveMode = false;
    this.inOrthographicMode = true;

};


THREE.CombinedCamera.prototype.setSize = function( width, height ) {

    this.cameraP.aspect = width / height;
    this.left = -width / 2;
    this.right = width / 2
    this.top = height / 2;
    this.bottom = -height / 2;

};


THREE.CombinedCamera.prototype.setFov = function( fov ) {

    this.fov = fov;

    if ( this.inPerspectiveMode ) {

        this.toPerspective();

    } else {

        this.toOrthographic();

    }

};

// For mantaining similar API with PerspectiveCamera

THREE.CombinedCamera.prototype.updateProjectionMatrix = function() {

    if ( this.inPerspectiveMode ) {

        this.toPerspective();

    } else {

        this.toPerspective();
        this.toOrthographic();

    }

};

/*
* Uses Focal Length (in mm) to estimate and set FOV
* 35mm (fullframe) camera is used if frame size is not specified;
* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
*/
THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) {

    if ( frameHeight === undefined ) frameHeight = 24;

    var fov = 2 * Math.atan( frameHeight / ( focalLength * 2 ) ) * ( 180 / Math.PI );

    this.setFov( fov );

    return fov;
};


THREE.CombinedCamera.prototype.setZoom = function( zoom ) {

    this.zoom = zoom;

    if ( this.inPerspectiveMode ) {

        this.toPerspective();

    } else {

        this.toOrthographic();

    }

};

THREE.CombinedCamera.prototype.toFrontView = function() {

    this.rotation.x = 0;
    this.rotation.y = 0;
    this.rotation.z = 0;

    // should we be modifing the matrix instead?

    this.rotationAutoUpdate = false;

};

THREE.CombinedCamera.prototype.toBackView = function() {

    this.rotation.x = 0;
    this.rotation.y = Math.PI;
    this.rotation.z = 0;
    this.rotationAutoUpdate = false;

};

THREE.CombinedCamera.prototype.toLeftView = function() {

    this.rotation.x = 0;
    this.rotation.y = - Math.PI / 2;
    this.rotation.z = 0;
    this.rotationAutoUpdate = false;

};

THREE.CombinedCamera.prototype.toRightView = function() {

    this.rotation.x = 0;
    this.rotation.y = Math.PI / 2;
    this.rotation.z = 0;
    this.rotationAutoUpdate = false;

};

THREE.CombinedCamera.prototype.toTopView = function() {

    this.rotation.x = - Math.PI / 2;
    this.rotation.y = 0;
    this.rotation.z = 0;
    this.rotationAutoUpdate = false;

};

THREE.CombinedCamera.prototype.toBottomView = function() {

    this.rotation.x = Math.PI / 2;
    this.rotation.y = 0;
    this.rotation.z = 0;
    this.rotationAutoUpdate = false;

};

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author paulirish / http://paulirish.com/
 */

THREE.FirstPersonControls = function ( object, domElement ) {

    this.object = object;
    this.target = new THREE.Vector3( 0, 0, 0 );

    this.domElement = ( domElement !== undefined ) ? domElement : document;

    this.movementSpeed = 1.0;
    this.lookSpeed = 0.005;

    this.lookVertical = true;
    this.autoForward = false;
    // this.invertVertical = false;

    this.activeLook = true;

    this.heightSpeed = false;
    this.heightCoef = 1.0;
    this.heightMin = 0.0;
    this.heightMax = 1.0;

    this.constrainVertical = false;
    this.verticalMin = 0;
    this.verticalMax = Math.PI;

    this.autoSpeedFactor = 0.0;

    this.mouseX = 0;
    this.mouseY = 0;

    this.lat = 0;
    this.lon = 0;
    this.phi = 0;
    this.theta = 0;

    this.moveForward = false;
    this.moveBackward = false;
    this.moveLeft = false;
    this.moveRight = false;
    this.freeze = false;

    this.mouseDragOn = false;

    this.viewHalfX = 0;
    this.viewHalfY = 0;

    if ( this.domElement !== document ) {

        this.domElement.setAttribute( 'tabindex', -1 );

    }

    //

    this.handleResize = function () {

        if ( this.domElement === document ) {

            this.viewHalfX = window.innerWidth / 2;
            this.viewHalfY = window.innerHeight / 2;

        } else {

            this.viewHalfX = this.domElement.offsetWidth / 2;
            this.viewHalfY = this.domElement.offsetHeight / 2;

        }

    };

    this.onMouseDown = function ( event ) {

        if ( this.domElement !== document ) {

            this.domElement.focus();

        }

        event.preventDefault();
        event.stopPropagation();

        if ( this.activeLook ) {

            switch ( event.button ) {

                case 0: this.moveForward = true; break;
                case 2: this.moveBackward = true; break;

            }

        }

        this.mouseDragOn = true;

    };

    this.onMouseUp = function ( event ) {

        event.preventDefault();
        event.stopPropagation();

        if ( this.activeLook ) {

            switch ( event.button ) {

                case 0: this.moveForward = false; break;
                case 2: this.moveBackward = false; break;

            }

        }

        this.mouseDragOn = false;

    };

    this.onMouseMove = function ( event ) {

        if ( this.domElement === document ) {

            this.mouseX = event.pageX - this.viewHalfX;
            this.mouseY = event.pageY - this.viewHalfY;

        } else {

            this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
            this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;

        }

    };

    this.onKeyDown = function ( event ) {

        //event.preventDefault();

        switch ( event.keyCode ) {

            case 38: /*up*/
            case 87: /*W*/ this.moveForward = true; break;

            case 37: /*left*/
            case 65: /*A*/ this.moveLeft = true; break;

            case 40: /*down*/
            case 83: /*S*/ this.moveBackward = true; break;

            case 39: /*right*/
            case 68: /*D*/ this.moveRight = true; break;

            case 82: /*R*/ this.moveUp = true; break;
            case 70: /*F*/ this.moveDown = true; break;

            case 81: /*Q*/ this.freeze = !this.freeze; break;

        }

    };

    this.onKeyUp = function ( event ) {

        switch( event.keyCode ) {

            case 38: /*up*/
            case 87: /*W*/ this.moveForward = false; break;

            case 37: /*left*/
            case 65: /*A*/ this.moveLeft = false; break;

            case 40: /*down*/
            case 83: /*S*/ this.moveBackward = false; break;

            case 39: /*right*/
            case 68: /*D*/ this.moveRight = false; break;

            case 82: /*R*/ this.moveUp = false; break;
            case 70: /*F*/ this.moveDown = false; break;

        }

    };

    this.update = function( delta ) {
        var actualMoveSpeed = 0;

        if ( this.freeze ) {

            return;

        } else {

            if ( this.heightSpeed ) {

                var y = THREE.Math.clamp( this.object.position.y, this.heightMin, this.heightMax );
                var heightDelta = y - this.heightMin;

                this.autoSpeedFactor = delta * ( heightDelta * this.heightCoef );

            } else {

                this.autoSpeedFactor = 0.0;

            }

            actualMoveSpeed = delta * this.movementSpeed;

            if ( this.moveForward || ( this.autoForward && !this.moveBackward ) ) this.object.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
            if ( this.moveBackward ) this.object.translateZ( actualMoveSpeed );

            if ( this.moveLeft ) this.object.translateX( - actualMoveSpeed );
            if ( this.moveRight ) this.object.translateX( actualMoveSpeed );

            if ( this.moveUp ) this.object.translateY( actualMoveSpeed );
            if ( this.moveDown ) this.object.translateY( - actualMoveSpeed );

            var actualLookSpeed = delta * this.lookSpeed;

            if ( !this.activeLook ) {

                actualLookSpeed = 0;

            }

            this.lon += this.mouseX * actualLookSpeed;
            if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed; // * this.invertVertical?-1:1;

            this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
            this.phi = ( 90 - this.lat ) * Math.PI / 180;
            this.theta = this.lon * Math.PI / 180;

            var targetPosition = this.target,
                position = this.object.position;

            targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
            targetPosition.y = position.y + 100 * Math.cos( this.phi );
            targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

        }

        var verticalLookRatio = 1;

        if ( this.constrainVertical ) {

            verticalLookRatio = Math.PI / ( this.verticalMax - this.verticalMin );

        }

        this.lon += this.mouseX * actualLookSpeed;
        if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;

        this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
        this.phi = ( 90 - this.lat ) * Math.PI / 180;

        this.theta = this.lon * Math.PI / 180;

        if ( this.constrainVertical ) {

            this.phi = THREE.Math.mapLinear( this.phi, 0, Math.PI, this.verticalMin, this.verticalMax );

        }

        var targetPosition = this.target,
            position = this.object.position;

        targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
        targetPosition.y = position.y + 100 * Math.cos( this.phi );
        targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

        this.object.lookAt( targetPosition );

    };


    this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

    this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false );
    this.domElement.addEventListener( 'mousedown', bind( this, this.onMouseDown ), false );
    this.domElement.addEventListener( 'mouseup', bind( this, this.onMouseUp ), false );
    this.domElement.addEventListener( 'keydown', bind( this, this.onKeyDown ), false );
    this.domElement.addEventListener( 'keyup', bind( this, this.onKeyUp ), false );

    function bind( scope, fn ) {

        return function () {

            fn.apply( scope, arguments );

        };

    };

    this.handleResize();

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.PathControls = function ( object, domElement ) {

    this.object = object;
    this.domElement = ( domElement !== undefined ) ? domElement : document;

    this.id = "PathControls" + THREE.PathControlsIdCounter ++;

    // API

    this.duration = 10 * 1000; // milliseconds
    this.waypoints = [];

    this.useConstantSpeed = true;
    this.resamplingCoef = 50;

    this.debugPath = new THREE.Object3D();
    this.debugDummy = new THREE.Object3D();

    this.animationParent = new THREE.Object3D();

    this.lookSpeed = 0.005;
    this.lookVertical = true;
    this.lookHorizontal = true;
    this.verticalAngleMap   = { srcRange: [ 0, 2 * Math.PI ], dstRange: [ 0, 2 * Math.PI ] };
    this.horizontalAngleMap = { srcRange: [ 0, 2 * Math.PI ], dstRange: [ 0, 2 * Math.PI ] };

    // internals

    this.target = new THREE.Object3D();

    this.mouseX = 0;
    this.mouseY = 0;

    this.lat = 0;
    this.lon = 0;

    this.phi = 0;
    this.theta = 0;

    var PI2 = Math.PI * 2,
        PI180 = Math.PI / 180;

    this.viewHalfX = 0;
    this.viewHalfY = 0;

    if ( this.domElement !== document ) {

        this.domElement.setAttribute( 'tabindex', -1 );

    }

    // methods

    this.handleResize = function () {

        if ( this.domElement === document ) {

            this.viewHalfX = window.innerWidth / 2;
            this.viewHalfY = window.innerHeight / 2;

        } else {

            this.viewHalfX = this.domElement.offsetWidth / 2;
            this.viewHalfY = this.domElement.offsetHeight / 2;

        }

    };

    this.update = function ( delta ) {

        var srcRange, dstRange;

        if( this.lookHorizontal ) this.lon += this.mouseX * this.lookSpeed * delta;
        if( this.lookVertical )   this.lat -= this.mouseY * this.lookSpeed * delta;

        this.lon = Math.max( 0, Math.min( 360, this.lon ) );
        this.lat = Math.max( - 85, Math.min( 85, this.lat ) );

        this.phi = ( 90 - this.lat ) * PI180;
        this.theta = this.lon * PI180;

        this.phi = normalize_angle_rad( this.phi );

        // constrain vertical look angle

        srcRange = this.verticalAngleMap.srcRange;
        dstRange = this.verticalAngleMap.dstRange;

        var tmpPhi = THREE.Math.mapLinear( this.phi, srcRange[ 0 ], srcRange[ 1 ], dstRange[ 0 ], dstRange[ 1 ] );
        var tmpPhiFullRange = dstRange[ 1 ] - dstRange[ 0 ];
        var tmpPhiNormalized = ( tmpPhi - dstRange[ 0 ] ) / tmpPhiFullRange;

        this.phi = QuadraticEaseInOut( tmpPhiNormalized ) * tmpPhiFullRange + dstRange[ 0 ];

        // constrain horizontal look angle

        srcRange = this.horizontalAngleMap.srcRange;
        dstRange = this.horizontalAngleMap.dstRange;

        var tmpTheta = THREE.Math.mapLinear( this.theta, srcRange[ 0 ], srcRange[ 1 ], dstRange[ 0 ], dstRange[ 1 ] );
        var tmpThetaFullRange = dstRange[ 1 ] - dstRange[ 0 ];
        var tmpThetaNormalized = ( tmpTheta - dstRange[ 0 ] ) / tmpThetaFullRange;

        this.theta = QuadraticEaseInOut( tmpThetaNormalized ) * tmpThetaFullRange + dstRange[ 0 ];

        var targetPosition = this.target.position,
            position = this.object.position;

        targetPosition.x = 100 * Math.sin( this.phi ) * Math.cos( this.theta );
        targetPosition.y = 100 * Math.cos( this.phi );
        targetPosition.z = 100 * Math.sin( this.phi ) * Math.sin( this.theta );

        this.object.lookAt( this.target.position );

    };

    this.onMouseMove = function ( event ) {

        if ( this.domElement === document ) {

            this.mouseX = event.pageX - this.viewHalfX;
            this.mouseY = event.pageY - this.viewHalfY;

        } else {

            this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
            this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;

        }

    };

    // utils

    function normalize_angle_rad( a ) {

        var b = a % PI2;
        return b >= 0 ? b : b + PI2;

    };

    function distance( a, b ) {

        var dx = a[ 0 ] - b[ 0 ],
            dy = a[ 1 ] - b[ 1 ],
            dz = a[ 2 ] - b[ 2 ];

        return Math.sqrt( dx * dx + dy * dy + dz * dz );

    };

    function QuadraticEaseInOut ( k ) {

        if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
        return - 0.5 * ( --k * ( k - 2 ) - 1 );

    };

    function bind( scope, fn ) {

        return function () {

            fn.apply( scope, arguments );

        };

    };

    function initAnimationPath( parent, spline, name, duration ) {

        var animationData = {

           name: name,
           fps: 0.6,
           length: duration,

           hierarchy: []

        };

        var i,
            parentAnimation, childAnimation,
            path = spline.getControlPointsArray(),
            sl = spline.getLength(),
            pl = path.length,
            t = 0,
            first = 0,
            last  = pl - 1;

        parentAnimation = { parent: -1, keys: [] };
        parentAnimation.keys[ first ] = { time: 0,        pos: path[ first ], rot: [ 0, 0, 0, 1 ], scl: [ 1, 1, 1 ] };
        parentAnimation.keys[ last  ] = { time: duration, pos: path[ last ],  rot: [ 0, 0, 0, 1 ], scl: [ 1, 1, 1 ] };

        for ( i = 1; i < pl - 1; i++ ) {

            // real distance (approximation via linear segments)

            t = duration * sl.chunks[ i ] / sl.total;

            // equal distance

            //t = duration * ( i / pl );

            // linear distance

            //t += duration * distance( path[ i ], path[ i - 1 ] ) / sl.total;

            parentAnimation.keys[ i ] = { time: t, pos: path[ i ] };

        }

        animationData.hierarchy[ 0 ] = parentAnimation;

        THREE.AnimationHandler.add( animationData );

        return new THREE.Animation( parent, name, THREE.AnimationHandler.CATMULLROM_FORWARD, false );

    };


    function createSplineGeometry( spline, n_sub ) {

        var i, index, position,
            geometry = new THREE.Geometry();

        for ( i = 0; i < spline.points.length * n_sub; i ++ ) {

            index = i / ( spline.points.length * n_sub );
            position = spline.getPoint( index );

            geometry.vertices[ i ] = new THREE.Vector3( position.x, position.y, position.z );

        }

        return geometry;

    };

    function createPath( parent, spline ) {

        var lineGeo = createSplineGeometry( spline, 10 ),
            particleGeo = createSplineGeometry( spline, 10 ),
            lineMat = new THREE.LineBasicMaterial( { color: 0xff0000, linewidth: 3 } ),
            lineObj = new THREE.Line( lineGeo, lineMat ),
            particleObj = new THREE.ParticleSystem( particleGeo, new THREE.ParticleBasicMaterial( { color: 0xffaa00, size: 3 } ) );

        lineObj.scale.set( 1, 1, 1 );
        parent.add( lineObj );

        particleObj.scale.set( 1, 1, 1 );
        parent.add( particleObj );

        var waypoint,
            geo = new THREE.SphereGeometry( 1, 16, 8 ),
            mat = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );

        for ( var i = 0; i < spline.points.length; i ++ ) {

            waypoint = new THREE.Mesh( geo, mat );
            waypoint.position.copy( spline.points[ i ] );
            parent.add( waypoint );

        }

    };

    this.init = function ( ) {

        // constructor

        this.spline = new THREE.Spline();
        this.spline.initFromArray( this.waypoints );

        if ( this.useConstantSpeed ) {

            this.spline.reparametrizeByArcLength( this.resamplingCoef );

        }

        if ( this.createDebugDummy ) {

            var dummyParentMaterial = new THREE.MeshLambertMaterial( { color: 0x0077ff } ),
            dummyChildMaterial  = new THREE.MeshLambertMaterial( { color: 0x00ff00 } ),
            dummyParentGeo = new THREE.CubeGeometry( 10, 10, 20 ),
            dummyChildGeo  = new THREE.CubeGeometry( 2, 2, 10 );

            this.animationParent = new THREE.Mesh( dummyParentGeo, dummyParentMaterial );

            var dummyChild = new THREE.Mesh( dummyChildGeo, dummyChildMaterial );
            dummyChild.position.set( 0, 10, 0 );

            this.animation = initAnimationPath( this.animationParent, this.spline, this.id, this.duration );

            this.animationParent.add( this.object );
            this.animationParent.add( this.target );
            this.animationParent.add( dummyChild );

        } else {

            this.animation = initAnimationPath( this.animationParent, this.spline, this.id, this.duration );
            this.animationParent.add( this.target );
            this.animationParent.add( this.object );

        }

        if ( this.createDebugPath ) {

            createPath( this.debugPath, this.spline );

        }

        this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false );

    };

    this.handleResize();

};

THREE.PathControlsIdCounter = 0;
/**
 * @author James Baicoianu / http://www.baicoianu.com/
 */

THREE.FlyControls = function ( object, domElement ) {

    this.object = object;

    this.domElement = ( domElement !== undefined ) ? domElement : document;
    if ( domElement ) this.domElement.setAttribute( 'tabindex', -1 );

    // API

    this.movementSpeed = 1.0;
    this.rollSpeed = 0.005;

    this.dragToLook = false;
    this.autoForward = false;

    // disable default target object behavior

    this.object.useQuaternion = true;

    // internals

    this.tmpQuaternion = new THREE.Quaternion();

    this.mouseStatus = 0;

    this.moveState = { up: 0, down: 0, left: 0, right: 0, forward: 0, back: 0, pitchUp: 0, pitchDown: 0, yawLeft: 0, yawRight: 0, rollLeft: 0, rollRight: 0 };
    this.moveVector = new THREE.Vector3( 0, 0, 0 );
    this.rotationVector = new THREE.Vector3( 0, 0, 0 );

    this.handleEvent = function ( event ) {

        if ( typeof this[ event.type ] == 'function' ) {

            this[ event.type ]( event );

        }

    };

    this.keydown = function( event ) {

        if ( event.altKey ) {

            return;

        }

        //event.preventDefault();

        switch ( event.keyCode ) {

            case 16: /* shift */ this.movementSpeedMultiplier = .1; break;

            case 87: /*W*/ this.moveState.forward = 1; break;
            case 83: /*S*/ this.moveState.back = 1; break;

            case 65: /*A*/ this.moveState.left = 1; break;
            case 68: /*D*/ this.moveState.right = 1; break;

            case 82: /*R*/ this.moveState.up = 1; break;
            case 70: /*F*/ this.moveState.down = 1; break;

            case 38: /*up*/ this.moveState.pitchUp = 1; break;
            case 40: /*down*/ this.moveState.pitchDown = 1; break;

            case 37: /*left*/ this.moveState.yawLeft = 1; break;
            case 39: /*right*/ this.moveState.yawRight = 1; break;

            case 81: /*Q*/ this.moveState.rollLeft = 1; break;
            case 69: /*E*/ this.moveState.rollRight = 1; break;

        }

        this.updateMovementVector();
        this.updateRotationVector();

    };

    this.keyup = function( event ) {

        switch( event.keyCode ) {

            case 16: /* shift */ this.movementSpeedMultiplier = 1; break;

            case 87: /*W*/ this.moveState.forward = 0; break;
            case 83: /*S*/ this.moveState.back = 0; break;

            case 65: /*A*/ this.moveState.left = 0; break;
            case 68: /*D*/ this.moveState.right = 0; break;

            case 82: /*R*/ this.moveState.up = 0; break;
            case 70: /*F*/ this.moveState.down = 0; break;

            case 38: /*up*/ this.moveState.pitchUp = 0; break;
            case 40: /*down*/ this.moveState.pitchDown = 0; break;

            case 37: /*left*/ this.moveState.yawLeft = 0; break;
            case 39: /*right*/ this.moveState.yawRight = 0; break;

            case 81: /*Q*/ this.moveState.rollLeft = 0; break;
            case 69: /*E*/ this.moveState.rollRight = 0; break;

        }

        this.updateMovementVector();
        this.updateRotationVector();

    };

    this.mousedown = function( event ) {

        if ( this.domElement !== document ) {

            this.domElement.focus();

        }

        event.preventDefault();
        event.stopPropagation();

        if ( this.dragToLook ) {

            this.mouseStatus ++;

        } else {

            switch ( event.button ) {

                case 0: this.object.moveForward = true; break;
                case 2: this.object.moveBackward = true; break;

            }

        }

    };

    this.mousemove = function( event ) {

        if ( !this.dragToLook || this.mouseStatus > 0 ) {

            var container = this.getContainerDimensions();
            var halfWidth  = container.size[ 0 ] / 2;
            var halfHeight = container.size[ 1 ] / 2;

            this.moveState.yawLeft   = - ( ( event.pageX - container.offset[ 0 ] ) - halfWidth  ) / halfWidth;
            this.moveState.pitchDown =   ( ( event.pageY - container.offset[ 1 ] ) - halfHeight ) / halfHeight;

            this.updateRotationVector();

        }

    };

    this.mouseup = function( event ) {

        event.preventDefault();
        event.stopPropagation();

        if ( this.dragToLook ) {

            this.mouseStatus --;

            this.moveState.yawLeft = this.moveState.pitchDown = 0;

        } else {

            switch ( event.button ) {

                case 0: this.moveForward = false; break;
                case 2: this.moveBackward = false; break;

            }

        }

        this.updateRotationVector();

    };

    this.update = function( delta ) {

        var moveMult = delta * this.movementSpeed;
        var rotMult = delta * this.rollSpeed;

        this.object.translateX( this.moveVector.x * moveMult );
        this.object.translateY( this.moveVector.y * moveMult );
        this.object.translateZ( this.moveVector.z * moveMult );

        this.tmpQuaternion.set( this.rotationVector.x * rotMult, this.rotationVector.y * rotMult, this.rotationVector.z * rotMult, 1 ).normalize();
        this.object.quaternion.multiplySelf( this.tmpQuaternion );

        this.object.matrix.setPosition( this.object.position );
        this.object.matrix.setRotationFromQuaternion( this.object.quaternion );
        this.object.matrixWorldNeedsUpdate = true;


    };

    this.updateMovementVector = function() {

        var forward = ( this.moveState.forward || ( this.autoForward && !this.moveState.back ) ) ? 1 : 0;

        this.moveVector.x = ( -this.moveState.left    + this.moveState.right );
        this.moveVector.y = ( -this.moveState.down    + this.moveState.up );
        this.moveVector.z = ( -forward + this.moveState.back );

        //console.log( 'move:', [ this.moveVector.x, this.moveVector.y, this.moveVector.z ] );

    };

    this.updateRotationVector = function() {

        this.rotationVector.x = ( -this.moveState.pitchDown + this.moveState.pitchUp );
        this.rotationVector.y = ( -this.moveState.yawRight  + this.moveState.yawLeft );
        this.rotationVector.z = ( -this.moveState.rollRight + this.moveState.rollLeft );

        //console.log( 'rotate:', [ this.rotationVector.x, this.rotationVector.y, this.rotationVector.z ] );

    };

    this.getContainerDimensions = function() {

        if ( this.domElement != document ) {

            return {
                size    : [ this.domElement.offsetWidth, this.domElement.offsetHeight ],
                offset    : [ this.domElement.offsetLeft,  this.domElement.offsetTop ]
            };

        } else {

            return {
                size    : [ window.innerWidth, window.innerHeight ],
                offset    : [ 0, 0 ]
            };

        }

    };

    function bind( scope, fn ) {

        return function () {

            fn.apply( scope, arguments );

        };

    };

    this.domElement.addEventListener( 'mousemove', bind( this, this.mousemove ), false );
    this.domElement.addEventListener( 'mousedown', bind( this, this.mousedown ), false );
    this.domElement.addEventListener( 'mouseup',   bind( this, this.mouseup ), false );

    this.domElement.addEventListener( 'keydown', bind( this, this.keydown ), false );
    this.domElement.addEventListener( 'keyup',   bind( this, this.keyup ), false );

    this.updateMovementVector();
    this.updateRotationVector();

};
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.RollControls = function ( object, domElement ) {

    this.object = object;
    this.domElement = ( domElement !== undefined ) ? domElement : document;

    // API

    this.mouseLook = true;
    this.autoForward = false;

    this.lookSpeed = 1;
    this.movementSpeed = 1;
    this.rollSpeed = 1;

    this.constrainVertical = [ -0.9, 0.9 ];

    // disable default target object behavior

    this.object.matrixAutoUpdate = false;

    // internals

    this.forward = new THREE.Vector3( 0, 0, 1 );
    this.roll = 0;

    var xTemp = new THREE.Vector3();
    var yTemp = new THREE.Vector3();
    var zTemp = new THREE.Vector3();
    var rollMatrix = new THREE.Matrix4();

    var doRoll = false, rollDirection = 1, forwardSpeed = 0, sideSpeed = 0, upSpeed = 0;

    var mouseX = 0, mouseY = 0;

    var windowHalfX = 0;
    var windowHalfY = 0;

    //

    this.handleResize = function () {

        windowHalfX = window.innerWidth / 2;
        windowHalfY = window.innerHeight / 2;

    };

    // custom update

    this.update = function ( delta ) {

        if ( this.mouseLook ) {

            var actualLookSpeed = delta * this.lookSpeed;

            this.rotateHorizontally( actualLookSpeed * mouseX );
            this.rotateVertically( actualLookSpeed * mouseY );

        }

        var actualSpeed = delta * this.movementSpeed;
        var forwardOrAuto = ( forwardSpeed > 0 || ( this.autoForward && ! ( forwardSpeed < 0 ) ) ) ? 1 : forwardSpeed;

        this.object.translateZ( -actualSpeed * forwardOrAuto );
        this.object.translateX( actualSpeed * sideSpeed );
        this.object.translateY( actualSpeed * upSpeed );

        if( doRoll ) {

            this.roll += this.rollSpeed * delta * rollDirection;

        }

        // cap forward up / down

        if( this.forward.y > this.constrainVertical[ 1 ] ) {

            this.forward.y = this.constrainVertical[ 1 ];
            this.forward.normalize();

        } else if( this.forward.y < this.constrainVertical[ 0 ] ) {

            this.forward.y = this.constrainVertical[ 0 ];
            this.forward.normalize();

        }


        // construct unrolled camera matrix

        zTemp.copy( this.forward );
        yTemp.set( 0, 1, 0 );

        xTemp.cross( yTemp, zTemp ).normalize();
        yTemp.cross( zTemp, xTemp ).normalize();

        this.object.matrix.elements[0] = xTemp.x; this.object.matrix.elements[4] = yTemp.x; this.object.matrix.elements[8] = zTemp.x;
        this.object.matrix.elements[1] = xTemp.y; this.object.matrix.elements[5] = yTemp.y; this.object.matrix.elements[9] = zTemp.y;
        this.object.matrix.elements[2] = xTemp.z; this.object.matrix.elements[6] = yTemp.z; this.object.matrix.elements[10] = zTemp.z;

        // calculate roll matrix

        rollMatrix.identity();
        rollMatrix.elements[0] = Math.cos( this.roll ); rollMatrix.elements[4] = -Math.sin( this.roll );
        rollMatrix.elements[1] = Math.sin( this.roll ); rollMatrix.elements[5] =  Math.cos( this.roll );

        // multiply camera with roll

        this.object.matrix.multiplySelf( rollMatrix );
        this.object.matrixWorldNeedsUpdate = true;

        // set position

        this.object.matrix.elements[12] = this.object.position.x;
        this.object.matrix.elements[13] = this.object.position.y;
        this.object.matrix.elements[14] = this.object.position.z;


    };

    this.translateX = function ( distance ) {

        this.object.position.x += this.object.matrix.elements[0] * distance;
        this.object.position.y += this.object.matrix.elements[1] * distance;
        this.object.position.z += this.object.matrix.elements[2] * distance;

    };

    this.translateY = function ( distance ) {

        this.object.position.x += this.object.matrix.elements[4] * distance;
        this.object.position.y += this.object.matrix.elements[5] * distance;
        this.object.position.z += this.object.matrix.elements[6] * distance;

    };

    this.translateZ = function ( distance ) {

        this.object.position.x -= this.object.matrix.elements[8] * distance;
        this.object.position.y -= this.object.matrix.elements[9] * distance;
        this.object.position.z -= this.object.matrix.elements[10] * distance;

    };


    this.rotateHorizontally = function ( amount ) {

        // please note that the amount is NOT degrees, but a scale value

        xTemp.set( this.object.matrix.elements[0], this.object.matrix.elements[1], this.object.matrix.elements[2] );
        xTemp.multiplyScalar( amount );

        this.forward.subSelf( xTemp );
        this.forward.normalize();

    };

    this.rotateVertically = function ( amount ) {

        // please note that the amount is NOT degrees, but a scale value

        yTemp.set( this.object.matrix.elements[4], this.object.matrix.elements[5], this.object.matrix.elements[6] );
        yTemp.multiplyScalar( amount );

        this.forward.addSelf( yTemp );
        this.forward.normalize();

    };

    function onKeyDown( event ) {

        //event.preventDefault();

        switch ( event.keyCode ) {

            case 38: /*up*/
            case 87: /*W*/ forwardSpeed = 1; break;

            case 37: /*left*/
            case 65: /*A*/ sideSpeed = -1; break;

            case 40: /*down*/
            case 83: /*S*/ forwardSpeed = -1; break;

            case 39: /*right*/
            case 68: /*D*/ sideSpeed = 1; break;

            case 81: /*Q*/ doRoll = true; rollDirection = 1; break;
            case 69: /*E*/ doRoll = true; rollDirection = -1; break;

            case 82: /*R*/ upSpeed = 1; break;
            case 70: /*F*/ upSpeed = -1; break;

        }

    };

    function onKeyUp( event ) {

        switch( event.keyCode ) {

            case 38: /*up*/
            case 87: /*W*/ forwardSpeed = 0; break;

            case 37: /*left*/
            case 65: /*A*/ sideSpeed = 0; break;

            case 40: /*down*/
            case 83: /*S*/ forwardSpeed = 0; break;

            case 39: /*right*/
            case 68: /*D*/ sideSpeed = 0; break;

            case 81: /*Q*/ doRoll = false; break;
            case 69: /*E*/ doRoll = false; break;

            case 82: /*R*/ upSpeed = 0; break;
            case 70: /*F*/ upSpeed = 0; break;

        }

    };

    function onMouseMove( event ) {

        mouseX = ( event.clientX - windowHalfX ) / window.innerWidth;
        mouseY = ( event.clientY - windowHalfY ) / window.innerHeight;

    };

    function onMouseDown ( event ) {

        event.preventDefault();
        event.stopPropagation();

        switch ( event.button ) {

            case 0: forwardSpeed = 1; break;
            case 2: forwardSpeed = -1; break;

        }

    };

    function onMouseUp ( event ) {

        event.preventDefault();
        event.stopPropagation();

        switch ( event.button ) {

            case 0: forwardSpeed = 0; break;
            case 2: forwardSpeed = 0; break;

        }

    };

    this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

    this.domElement.addEventListener( 'mousemove', onMouseMove, false );
    this.domElement.addEventListener( 'mousedown', onMouseDown, false );
    this.domElement.addEventListener( 'mouseup', onMouseUp, false );
    this.domElement.addEventListener( 'keydown', onKeyDown, false );
    this.domElement.addEventListener( 'keyup', onKeyUp, false );

    this.handleResize();

};
/**
 * @author Eberhard Graether / http://egraether.com/
 */

THREE.TrackballControls = function ( object, domElement ) {

    THREE.EventTarget.call( this );

    var _this = this,
    STATE = { NONE : -1, ROTATE : 0, ZOOM : 1, PAN : 2 };

    this.object = object;
    this.domElement = ( domElement !== undefined ) ? domElement : document;

    // API

    this.enabled = true;

    this.screen = { width: 0, height: 0, offsetLeft: 0, offsetTop: 0 };
    this.radius = ( this.screen.width + this.screen.height ) / 4;

    this.rotateSpeed = 1.0;
    this.zoomSpeed = 1.2;
    this.panSpeed = 0.3;

    this.noRotate = false;
    this.noZoom = false;
    this.noPan = false;

    this.staticMoving = false;
    this.dynamicDampingFactor = 0.2;

    this.minDistance = 0;
    this.maxDistance = Infinity;

    this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];

    // internals

    this.target = new THREE.Vector3();

    var lastPosition = new THREE.Vector3();

    var _keyPressed = false,
    _state = STATE.NONE,

    _eye = new THREE.Vector3(),

    _rotateStart = new THREE.Vector3(),
    _rotateEnd = new THREE.Vector3(),

    _zoomStart = new THREE.Vector2(),
    _zoomEnd = new THREE.Vector2(),

    _panStart = new THREE.Vector2(),
    _panEnd = new THREE.Vector2();

    // events

    var changeEvent = { type: 'change' };


    // methods

    this.handleResize = function () {

        this.screen.width = window.innerWidth;
        this.screen.height = window.innerHeight;

        this.screen.offsetLeft = 0;
        this.screen.offsetTop = 0;

        this.radius = ( this.screen.width + this.screen.height ) / 4;
    };

    this.handleEvent = function ( event ) {

        if ( typeof this[ event.type ] == 'function' ) {

            this[ event.type ]( event );

        }

    };

    this.getMouseOnScreen = function ( clientX, clientY ) {

        return new THREE.Vector2(
            ( clientX - _this.screen.offsetLeft ) / _this.radius * 0.5,
            ( clientY - _this.screen.offsetTop ) / _this.radius * 0.5
        );

    };

    this.getMouseProjectionOnBall = function ( clientX, clientY ) {

        var mouseOnBall = new THREE.Vector3(
            ( clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft ) / _this.radius,
            ( _this.screen.height * 0.5 + _this.screen.offsetTop - clientY ) / _this.radius,
            0.0
        );

        var length = mouseOnBall.length();

        if ( length > 1.0 ) {

            mouseOnBall.normalize();

        } else {

            mouseOnBall.z = Math.sqrt( 1.0 - length * length );

        }

        _eye.copy( _this.object.position ).subSelf( _this.target );

        var projection = _this.object.up.clone().setLength( mouseOnBall.y );
        projection.addSelf( _this.object.up.clone().crossSelf( _eye ).setLength( mouseOnBall.x ) );
        projection.addSelf( _eye.setLength( mouseOnBall.z ) );

        return projection;

    };

    this.rotateCamera = function () {

        var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );

        if ( angle ) {

            var axis = ( new THREE.Vector3() ).cross( _rotateStart, _rotateEnd ).normalize(),
                quaternion = new THREE.Quaternion();

            angle *= _this.rotateSpeed;

            quaternion.setFromAxisAngle( axis, -angle );

            quaternion.multiplyVector3( _eye );
            quaternion.multiplyVector3( _this.object.up );

            quaternion.multiplyVector3( _rotateEnd );

            if ( _this.staticMoving ) {

                _rotateStart.copy( _rotateEnd );

            } else {

                quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
                quaternion.multiplyVector3( _rotateStart );

            }

        }

    };

    this.zoomCamera = function () {

        var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;

        if ( factor !== 1.0 && factor > 0.0 ) {

            _eye.multiplyScalar( factor );

            if ( _this.staticMoving ) {

                _zoomStart.copy( _zoomEnd );

            } else {

                _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;

            }

        }

    };

    this.panCamera = function () {

        var mouseChange = _panEnd.clone().subSelf( _panStart );

        if ( mouseChange.lengthSq() ) {

            mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );

            var pan = _eye.clone().crossSelf( _this.object.up ).setLength( mouseChange.x );
            pan.addSelf( _this.object.up.clone().setLength( mouseChange.y ) );

            _this.object.position.addSelf( pan );
            _this.target.addSelf( pan );

            if ( _this.staticMoving ) {

                _panStart = _panEnd;

            } else {

                _panStart.addSelf( mouseChange.sub( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );

            }

        }

    };

    this.checkDistances = function () {

        if ( !_this.noZoom || !_this.noPan ) {

            if ( _this.object.position.lengthSq() > _this.maxDistance * _this.maxDistance ) {

                _this.object.position.setLength( _this.maxDistance );

            }

            if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {

                _this.object.position.add( _this.target, _eye.setLength( _this.minDistance ) );

            }

        }

    };

    this.update = function () {

        _eye.copy( _this.object.position ).subSelf( _this.target );

        if ( !_this.noRotate ) {

            _this.rotateCamera();

        }

        if ( !_this.noZoom ) {

            _this.zoomCamera();

        }

        if ( !_this.noPan ) {

            _this.panCamera();

        }

        _this.object.position.add( _this.target, _eye );

        _this.checkDistances();

        _this.object.lookAt( _this.target );

        if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {

            _this.dispatchEvent( changeEvent );

            lastPosition.copy( _this.object.position );

        }

    };

    // listeners

    function keydown( event ) {

        if ( ! _this.enabled ) return;

        //event.preventDefault();

        if ( _state !== STATE.NONE ) {

            return;

        } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {

            _state = STATE.ROTATE;

        } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {

            _state = STATE.ZOOM;

        } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {

            _state = STATE.PAN;

        }

        if ( _state !== STATE.NONE ) {

            _keyPressed = true;

        }

    }

    function keyup( event ) {

        if ( ! _this.enabled ) return;

        if ( _state !== STATE.NONE ) {

            _state = STATE.NONE;

        }

    }

    function mousedown( event ) {

        if ( ! _this.enabled ) return;

        event.preventDefault();
        event.stopPropagation();

        if ( _state === STATE.NONE ) {

            _state = event.button;

            if ( _state === STATE.ROTATE && !_this.noRotate ) {

                _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );

            } else if ( _state === STATE.ZOOM && !_this.noZoom ) {

                _zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

            } else if ( !this.noPan ) {

                _panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

            }

        }

    }

    function mousemove( event ) {

        if ( ! _this.enabled ) return;

        if ( _keyPressed ) {

            _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
            _zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
            _panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

            _keyPressed = false;

        }

        if ( _state === STATE.NONE ) {

            return;

        } else if ( _state === STATE.ROTATE && !_this.noRotate ) {

            _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );

        } else if ( _state === STATE.ZOOM && !_this.noZoom ) {

            _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

        } else if ( _state === STATE.PAN && !_this.noPan ) {

            _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

        }

    }

    function mouseup( event ) {

        if ( ! _this.enabled ) return;

        event.preventDefault();
        event.stopPropagation();

        _state = STATE.NONE;

    }

    function mousewheel( event ) {

        if ( ! _this.enabled ) return;

        event.preventDefault();
        event.stopPropagation();

        var delta = 0;

        if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9

            delta = event.wheelDelta / 40;

        } else if ( event.detail ) { // Firefox

            delta = - event.detail / 3;

        }

        _zoomStart.y += ( 1 / delta ) * 0.05;

    }

    this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

    this.domElement.addEventListener( 'mousemove', mousemove, false );
    this.domElement.addEventListener( 'mousedown', mousedown, false );
    this.domElement.addEventListener( 'mouseup', mouseup, false );
    this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false );
    this.domElement.addEventListener( 'mousewheel', mousewheel, false );

    window.addEventListener( 'keydown', keydown, false );
    window.addEventListener( 'keyup', keyup, false );

    this.handleResize();

};
/**
 * @author qiao / https://github.com/qiao
 * @author mrdoob / http://mrdoob.com
 * @author alteredq / http://alteredqualia.com/
 */

THREE.OrbitControls = function ( object, domElement ) {

    THREE.EventTarget.call( this );

    this.object = object;
    this.domElement = ( domElement !== undefined ) ? domElement : document;

    // API

    this.center = new THREE.Vector3();

    this.userZoom = true;
    this.userZoomSpeed = 1.0;

    this.userRotate = true;
    this.userRotateSpeed = 1.0;

    this.autoRotate = false;
    this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60

    // internals

    var scope = this;

    var EPS = 0.000001;
    var PIXELS_PER_ROUND = 1800;

    var rotateStart = new THREE.Vector2();
    var rotateEnd = new THREE.Vector2();
    var rotateDelta = new THREE.Vector2();

    var zoomStart = new THREE.Vector2();
    var zoomEnd = new THREE.Vector2();
    var zoomDelta = new THREE.Vector2();

    var phiDelta = 0;
    var thetaDelta = 0;
    var scale = 1;

    var lastPosition = new THREE.Vector3();

    var STATE = { NONE : -1, ROTATE : 0, ZOOM : 1 };
    var state = STATE.NONE;

    // events

    var changeEvent = { type: 'change' };


    this.rotateLeft = function ( angle ) {

        if ( angle === undefined ) {

            angle = getAutoRotationAngle();

        }

        thetaDelta -= angle;

    };

    this.rotateRight = function ( angle ) {

        if ( angle === undefined ) {

            angle = getAutoRotationAngle();

        }

        thetaDelta += angle;

    };

    this.rotateUp = function ( angle ) {

        if ( angle === undefined ) {

            angle = getAutoRotationAngle();

        }

        phiDelta -= angle;

    };

    this.rotateDown = function ( angle ) {

        if ( angle === undefined ) {

            angle = getAutoRotationAngle();

        }

        phiDelta += angle;

    };

    this.zoomIn = function ( zoomScale ) {

        if ( zoomScale === undefined ) {

            zoomScale = getZoomScale();

        }

        scale /= zoomScale;

    };

    this.zoomOut = function ( zoomScale ) {

        if ( zoomScale === undefined ) {

            zoomScale = getZoomScale();

        }

        scale *= zoomScale;

    };

    this.update = function () {

        var position = this.object.position;
        var offset = position.clone().subSelf( this.center )

        // angle from z-axis around y-axis

        var theta = Math.atan2( offset.x, offset.z );

        // angle from y-axis

        var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );

        if ( this.autoRotate ) {

            this.rotateLeft( getAutoRotationAngle() );

        }

        theta += thetaDelta;
        phi += phiDelta;

        // restrict phi to be betwee EPS and PI-EPS

        phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );

        var radius = offset.length();
        offset.x = radius * Math.sin( phi ) * Math.sin( theta );
        offset.y = radius * Math.cos( phi );
        offset.z = radius * Math.sin( phi ) * Math.cos( theta );
        offset.multiplyScalar( scale );

        position.copy( this.center ).addSelf( offset );

        this.object.lookAt( this.center );

        thetaDelta = 0;
        phiDelta = 0;
        scale = 1;

        if ( lastPosition.distanceTo( this.object.position ) > 0 ) {

            this.dispatchEvent( changeEvent );

            lastPosition.copy( this.object.position );

        }

    };


    function getAutoRotationAngle() {

        return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;

    }

    function getZoomScale() {

        return Math.pow( 0.95, scope.userZoomSpeed );

    }

    function onMouseDown( event ) {

        if ( !scope.userRotate ) return;

        event.preventDefault();

        if ( event.button === 0 || event.button === 2 ) {

            state = STATE.ROTATE;

            rotateStart.set( event.clientX, event.clientY );

        } else if ( event.button === 1 ) {

            state = STATE.ZOOM;

            zoomStart.set( event.clientX, event.clientY );

        }

        document.addEventListener( 'mousemove', onMouseMove, false );
        document.addEventListener( 'mouseup', onMouseUp, false );

    }

    function onMouseMove( event ) {

        event.preventDefault();

        if ( state === STATE.ROTATE ) {

            rotateEnd.set( event.clientX, event.clientY );
            rotateDelta.sub( rotateEnd, rotateStart );

            scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed );
            scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed );

            rotateStart.copy( rotateEnd );

        } else if ( state === STATE.ZOOM ) {

            zoomEnd.set( event.clientX, event.clientY );
            zoomDelta.sub( zoomEnd, zoomStart );

            if ( zoomDelta.y > 0 ) {

                scope.zoomIn();

            } else {

                scope.zoomOut();

            }

            zoomStart.copy( zoomEnd );

        }

    }

    function onMouseUp( event ) {

        if ( ! scope.userRotate ) return;

        document.removeEventListener( 'mousemove', onMouseMove, false );
        document.removeEventListener( 'mouseup', onMouseUp, false );

        state = STATE.NONE;

    }

    function onMouseWheel( event ) {

        if ( ! scope.userZoom ) return;

        if ( event.wheelDelta > 0 ) {

            scope.zoomOut();

        } else {

            scope.zoomIn();

        }

    }

    this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
    this.domElement.addEventListener( 'mousedown', onMouseDown, false );
    this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );

};
/**
 * @author hughes
 */

THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {

    THREE.Geometry.call( this );

    radius = radius || 50;

    thetaStart = thetaStart !== undefined ? thetaStart : 0;
    thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
    segments = segments !== undefined ? Math.max( 3, segments ) : 8;

    var i, uvs = [],
    center = new THREE.Vector3(), centerUV = new THREE.UV( 0.5, 0.5 );

    this.vertices.push(center);
    uvs.push( centerUV );

    for ( i = 0; i <= segments; i ++ ) {

        var vertex = new THREE.Vector3();

        vertex.x = radius * Math.cos( thetaStart + i / segments * thetaLength );
        vertex.y = radius * Math.sin( thetaStart + i / segments * thetaLength );

        this.vertices.push( vertex );
        uvs.push( new THREE.UV( ( vertex.x / radius + 1 ) / 2, - ( vertex.y / radius + 1 ) / 2 + 1 ) );

    }

    var n = new THREE.Vector3( 0, 0, -1 );

    for ( i = 1; i <= segments; i ++ ) {

        var v1 = i;
        var v2 = i + 1 ;
        var v3 = 0;

        this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) );
        this.faceVertexUvs[ 0 ].push( [ uvs[ i ], uvs[ i + 1 ], centerUV ] );

    }

    this.computeCentroids();
    this.computeFaceNormals();

    this.boundingSphere = { radius: radius };

};

THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as
 */

THREE.CubeGeometry = function ( width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, sides ) {

    THREE.Geometry.call( this );

    var scope = this,
    width_half = width / 2,
    height_half = height / 2,
    depth_half = depth / 2;

    var mpx, mpy, mpz, mnx, mny, mnz;

    if ( materials !== undefined ) {

        if ( materials instanceof Array ) {

            this.materials = materials;

        } else {

            this.materials = [];

            for ( var i = 0; i < 6; i ++ ) {

                this.materials.push( materials );

            }

        }

        mpx = 0; mnx = 1; mpy = 2; mny = 3; mpz = 4; mnz = 5;

    } else {

        this.materials = [];

    }

    this.sides = { px: true, nx: true, py: true, ny: true, pz: true, nz: true };

    if ( sides != undefined ) {

        for ( var s in sides ) {

            if ( this.sides[ s ] !== undefined ) {

                this.sides[ s ] = sides[ s ];

            }

        }

    }

    this.sides.px && buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, mpx ); // px
    this.sides.nx && buildPlane( 'z', 'y',   1, - 1, depth, height, - width_half, mnx ); // nx
    this.sides.py && buildPlane( 'x', 'z',   1,   1, width, depth, height_half, mpy ); // py
    this.sides.ny && buildPlane( 'x', 'z',   1, - 1, width, depth, - height_half, mny ); // ny
    this.sides.pz && buildPlane( 'x', 'y',   1, - 1, width, height, depth_half, mpz ); // pz
    this.sides.nz && buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, mnz ); // nz

    function buildPlane( u, v, udir, vdir, width, height, depth, material ) {

        var w, ix, iy,
        gridX = segmentsWidth || 1,
        gridY = segmentsHeight || 1,
        width_half = width / 2,
        height_half = height / 2,
        offset = scope.vertices.length;

        if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) {

            w = 'z';

        } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) {

            w = 'y';
            gridY = segmentsDepth || 1;

        } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {

            w = 'x';
            gridX = segmentsDepth || 1;

        }

        var gridX1 = gridX + 1,
        gridY1 = gridY + 1,
        segment_width = width / gridX,
        segment_height = height / gridY,
        normal = new THREE.Vector3();

        normal[ w ] = depth > 0 ? 1 : - 1;

        for ( iy = 0; iy < gridY1; iy ++ ) {

            for ( ix = 0; ix < gridX1; ix ++ ) {

                var vector = new THREE.Vector3();
                vector[ u ] = ( ix * segment_width - width_half ) * udir;
                vector[ v ] = ( iy * segment_height - height_half ) * vdir;
                vector[ w ] = depth;

                scope.vertices.push( vector );

            }

        }

        for ( iy = 0; iy < gridY; iy++ ) {

            for ( ix = 0; ix < gridX; ix++ ) {

                var a = ix + gridX1 * iy;
                var b = ix + gridX1 * ( iy + 1 );
                var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
                var d = ( ix + 1 ) + gridX1 * iy;

                var face = new THREE.Face4( a + offset, b + offset, c + offset, d + offset );
                face.normal.copy( normal );
                face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() );
                face.materialIndex = material;

                scope.faces.push( face );
                scope.faceVertexUvs[ 0 ].push( [
                            new THREE.UV( ix / gridX, 1 - iy / gridY ),
                            new THREE.UV( ix / gridX, 1 - ( iy + 1 ) / gridY ),
                            new THREE.UV( ( ix + 1 ) / gridX, 1- ( iy + 1 ) / gridY ),
                            new THREE.UV( ( ix + 1 ) / gridX, 1 - iy / gridY )
                        ] );

            }

        }

    }

    this.computeCentroids();
    this.mergeVertices();

};

THREE.CubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, segmentsRadius, segmentsHeight, openEnded ) {

    THREE.Geometry.call( this );

    radiusTop = radiusTop !== undefined ? radiusTop : 20;
    radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
    height = height !== undefined ? height : 100;

    var heightHalf = height / 2;
    var segmentsX = segmentsRadius || 8;
    var segmentsY = segmentsHeight || 1;

    var x, y, vertices = [], uvs = [];

    for ( y = 0; y <= segmentsY; y ++ ) {

        var verticesRow = [];
        var uvsRow = [];

        var v = y / segmentsY;
        var radius = v * ( radiusBottom - radiusTop ) + radiusTop;

        for ( x = 0; x <= segmentsX; x ++ ) {

            var u = x / segmentsX;

            var vertex = new THREE.Vector3();
            vertex.x = radius * Math.sin( u * Math.PI * 2 );
            vertex.y = - v * height + heightHalf;
            vertex.z = radius * Math.cos( u * Math.PI * 2 );

            this.vertices.push( vertex );

            verticesRow.push( this.vertices.length - 1 );
            uvsRow.push( new THREE.UV( u, 1 - v ) );

        }

        vertices.push( verticesRow );
        uvs.push( uvsRow );

    }

    var tanTheta = ( radiusBottom - radiusTop ) / height;
    var na, nb;

    for ( x = 0; x < segmentsX; x ++ ) {

        if ( radiusTop !== 0 ) {

            na = this.vertices[ vertices[ 0 ][ x ] ].clone();
            nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone();

        } else {

            na = this.vertices[ vertices[ 1 ][ x ] ].clone();
            nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone();

        }

        na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize();
        nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize();

        for ( y = 0; y < segmentsY; y ++ ) {

            var v1 = vertices[ y ][ x ];
            var v2 = vertices[ y + 1 ][ x ];
            var v3 = vertices[ y + 1 ][ x + 1 ];
            var v4 = vertices[ y ][ x + 1 ];

            var n1 = na.clone();
            var n2 = na.clone();
            var n3 = nb.clone();
            var n4 = nb.clone();

            var uv1 = uvs[ y ][ x ].clone();
            var uv2 = uvs[ y + 1 ][ x ].clone();
            var uv3 = uvs[ y + 1 ][ x + 1 ].clone();
            var uv4 = uvs[ y ][ x + 1 ].clone();

            this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) );
            this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] );

        }

    }

    // top cap

    if ( !openEnded && radiusTop > 0 ) {

        this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) );

        for ( x = 0; x < segmentsX; x ++ ) {

            var v1 = vertices[ 0 ][ x ];
            var v2 = vertices[ 0 ][ x + 1 ];
            var v3 = this.vertices.length - 1;

            var n1 = new THREE.Vector3( 0, 1, 0 );
            var n2 = new THREE.Vector3( 0, 1, 0 );
            var n3 = new THREE.Vector3( 0, 1, 0 );

            var uv1 = uvs[ 0 ][ x ].clone();
            var uv2 = uvs[ 0 ][ x + 1 ].clone();
            var uv3 = new THREE.UV( uv2.u, 0 );

            this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
            this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );

        }

    }

    // bottom cap

    if ( !openEnded && radiusBottom > 0 ) {

        this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) );

        for ( x = 0; x < segmentsX; x ++ ) {

            var v1 = vertices[ y ][ x + 1 ];
            var v2 = vertices[ y ][ x ];
            var v3 = this.vertices.length - 1;

            var n1 = new THREE.Vector3( 0, - 1, 0 );
            var n2 = new THREE.Vector3( 0, - 1, 0 );
            var n3 = new THREE.Vector3( 0, - 1, 0 );

            var uv1 = uvs[ y ][ x + 1 ].clone();
            var uv2 = uvs[ y ][ x ].clone();
            var uv3 = new THREE.UV( uv2.u, 1 );

            this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
            this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );

        }

    }

    this.computeCentroids();
    this.computeFaceNormals();

}

THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Creates extruded geometry from a path shape.
 *
 * parameters = {
 *
 *  size: <float>, // size of the text
 *  height: <float>, // thickness to extrude text
 *  curveSegments: <int>, // number of points on the curves
 *  steps: <int>, // number of points for z-side extrusions / used for subdividing segements of extrude spline too
 *  amount: <int>, // Amount
 *
 *  bevelEnabled: <bool>, // turn on bevel
 *  bevelThickness: <float>, // how deep into text bevel goes
 *  bevelSize: <float>, // how far from text outline is bevel
 *  bevelSegments: <int>, // number of bevel layers
 *
 *  extrudePath: <THREE.CurvePath> // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined)
 *  frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals
 *
 *  material: <int> // material index for front and back faces
 *  extrudeMaterial: <int> // material index for extrusion and beveled faces
 *  uvGenerator: <Object> // object that provides UV generator functions
 *
 * }
 **/

THREE.ExtrudeGeometry = function ( shapes, options ) {

    if ( typeof( shapes ) === "undefined" ) {
        shapes = [];
        return;
    }

    THREE.Geometry.call( this );

    shapes = shapes instanceof Array ? shapes : [ shapes ];

    this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox();

    this.addShapeList( shapes, options );

    this.computeCentroids();
    this.computeFaceNormals();

    // can't really use automatic vertex normals
    // as then front and back sides get smoothed too
    // should do separate smoothing just for sides

    //this.computeVertexNormals();

    //console.log( "took", ( Date.now() - startTime ) );

};

THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype );

THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) {
    var sl = shapes.length;

    for ( var s = 0; s < sl; s ++ ) {
        var shape = shapes[ s ];
        this.addShape( shape, options );
    }
};

THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) {

    var amount = options.amount !== undefined ? options.amount : 100;

    var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10
    var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8
    var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;

    var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false

    var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;

    var steps = options.steps !== undefined ? options.steps : 1;

    var extrudePath = options.extrudePath;
    var extrudePts, extrudeByPath = false;

    var material = options.material;
    var extrudeMaterial = options.extrudeMaterial;

    // Use default WorldUVGenerator if no UV generators are specified.
    var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator;

    var shapebb = this.shapebb;
    //shapebb = shape.getBoundingBox();



    var splineTube, binormal, normal, position2;
    if ( extrudePath ) {

        extrudePts = extrudePath.getSpacedPoints( steps );

        extrudeByPath = true;
        bevelEnabled = false; // bevels not supported for path extrusion

        // SETUP TNB variables

        // Reuse TNB from TubeGeomtry for now.
        // TODO1 - have a .isClosed in spline?

        splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false);

        // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);

        binormal = new THREE.Vector3();
        normal = new THREE.Vector3();
        position2 = new THREE.Vector3();

    }

    // Safeguards if bevels are not enabled

    if ( ! bevelEnabled ) {

        bevelSegments = 0;
        bevelThickness = 0;
        bevelSize = 0;

    }

    // Variables initalization

    var ahole, h, hl; // looping of holes
    var scope = this;
    var bevelPoints = [];

    var shapesOffset = this.vertices.length;

    var shapePoints = shape.extractPoints();

    var vertices = shapePoints.shape;
    var holes = shapePoints.holes;

    var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ;

    if ( reverse ) {

        vertices = vertices.reverse();

        // Maybe we should also check if holes are in the opposite direction, just to be safe ...

        for ( h = 0, hl = holes.length; h < hl; h ++ ) {

            ahole = holes[ h ];

            if ( THREE.Shape.Utils.isClockWise( ahole ) ) {

                holes[ h ] = ahole.reverse();

            }

        }

        reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)!

    }


    var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes );

    /* Vertices */

    var contour = vertices; // vertices has all points but contour has only points of circumference

    for ( h = 0, hl = holes.length;  h < hl; h ++ ) {

        ahole = holes[ h ];

        vertices = vertices.concat( ahole );

    }


    function scalePt2 ( pt, vec, size ) {

        if ( !vec ) console.log( "die" );

        return vec.clone().multiplyScalar( size ).addSelf( pt );

    }

    var b, bs, t, z,
        vert, vlen = vertices.length,
        face, flen = faces.length,
        cont, clen = contour.length;


    // Find directions for point movement

    var RAD_TO_DEGREES = 180 / Math.PI;


    function getBevelVec( pt_i, pt_j, pt_k ) {

        // Algorithm 2

        return getBevelVec2( pt_i, pt_j, pt_k );

    }

    function getBevelVec1( pt_i, pt_j, pt_k ) {

        var anglea = Math.atan2( pt_j.y - pt_i.y, pt_j.x - pt_i.x );
        var angleb = Math.atan2( pt_k.y - pt_i.y, pt_k.x - pt_i.x );

        if ( anglea > angleb ) {

            angleb += Math.PI * 2;

        }

        var anglec = ( anglea + angleb ) / 2;


        //console.log('angle1', anglea * RAD_TO_DEGREES,'angle2', angleb * RAD_TO_DEGREES, 'anglec', anglec *RAD_TO_DEGREES);

        var x = - Math.cos( anglec );
        var y = - Math.sin( anglec );

        var vec = new THREE.Vector2( x, y ); //.normalize();

        return vec;

    }

    function getBevelVec2( pt_i, pt_j, pt_k ) {

        var a = THREE.ExtrudeGeometry.__v1,
            b = THREE.ExtrudeGeometry.__v2,
            v_hat = THREE.ExtrudeGeometry.__v3,
            w_hat = THREE.ExtrudeGeometry.__v4,
            p = THREE.ExtrudeGeometry.__v5,
            q = THREE.ExtrudeGeometry.__v6,
            v, w,
            v_dot_w_hat, q_sub_p_dot_w_hat,
            s, intersection;

        // good reading for line-line intersection
        // http://sputsoft.com/blog/2010/03/line-line-intersection.html

        // define a as vector j->i
        // define b as vectot k->i

        a.set( pt_i.x - pt_j.x, pt_i.y - pt_j.y );
        b.set( pt_i.x - pt_k.x, pt_i.y - pt_k.y );

        // get unit vectors

        v = a.normalize();
        w = b.normalize();

        // normals from pt i

        v_hat.set( -v.y, v.x );
        w_hat.set( w.y, -w.x );

        // pts from i

        p.copy( pt_i ).addSelf( v_hat );
        q.copy( pt_i ).addSelf( w_hat );

        if ( p.equals( q ) ) {

            //console.log("Warning: lines are straight");
            return w_hat.clone();

        }

        // Points from j, k. helps prevents points cross overover most of the time

        p.copy( pt_j ).addSelf( v_hat );
        q.copy( pt_k ).addSelf( w_hat );

        v_dot_w_hat = v.dot( w_hat );
        q_sub_p_dot_w_hat = q.subSelf( p ).dot( w_hat );

        // We should not reach these conditions

        if ( v_dot_w_hat === 0 ) {

            console.log( "Either infinite or no solutions!" );

            if ( q_sub_p_dot_w_hat === 0 ) {

                console.log( "Its finite solutions." );

            } else {

                console.log( "Too bad, no solutions." );

            }

        }

        s = q_sub_p_dot_w_hat / v_dot_w_hat;

        if ( s < 0 ) {

            // in case of emergecy, revert to algorithm 1.

            return getBevelVec1( pt_i, pt_j, pt_k );

        }

        intersection = v.multiplyScalar( s ).addSelf( p );

        return intersection.subSelf( pt_i ).clone(); // Don't normalize!, otherwise sharp corners become ugly

    }

    var contourMovements = [];

    for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {

        if ( j === il ) j = 0;
        if ( k === il ) k = 0;

        //  (j)---(i)---(k)
        // console.log('i,j,k', i, j , k)

        var pt_i = contour[ i ];
        var pt_j = contour[ j ];
        var pt_k = contour[ k ];

        contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] );

    }

    var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat();

    for ( h = 0, hl = holes.length; h < hl; h ++ ) {

        ahole = holes[ h ];

        oneHoleMovements = [];

        for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {

            if ( j === il ) j = 0;
            if ( k === il ) k = 0;

            //  (j)---(i)---(k)
            oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );

        }

        holesMovements.push( oneHoleMovements );
        verticesMovements = verticesMovements.concat( oneHoleMovements );

    }


    // Loop bevelSegments, 1 for the front, 1 for the back

    for ( b = 0; b < bevelSegments; b ++ ) {
    //for ( b = bevelSegments; b > 0; b -- ) {

        t = b / bevelSegments;
        z = bevelThickness * ( 1 - t );

        //z = bevelThickness * t;
        bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved
        //bs = bevelSize * t ; // linear

        // contract shape

        for ( i = 0, il = contour.length; i < il; i ++ ) {

            vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
            //vert = scalePt( contour[ i ], contourCentroid, bs, false );
            v( vert.x, vert.y,  - z );

        }

        // expand holes

        for ( h = 0, hl = holes.length; h < hl; h++ ) {

            ahole = holes[ h ];
            oneHoleMovements = holesMovements[ h ];

            for ( i = 0, il = ahole.length; i < il; i++ ) {

                vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
                //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true );

                v( vert.x, vert.y,  -z );

            }

        }

    }

    bs = bevelSize;

    // Back facing vertices

    for ( i = 0; i < vlen; i ++ ) {

        vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];

        if ( !extrudeByPath ) {

            v( vert.x, vert.y, 0 );

        } else {

            // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );

            normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x);
            binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y);

            position2.copy( extrudePts[0] ).addSelf(normal).addSelf(binormal);

            v( position2.x, position2.y, position2.z );

        }

    }

    // Add stepped vertices...
    // Including front facing vertices

    var s;

    for ( s = 1; s <= steps; s ++ ) {

        for ( i = 0; i < vlen; i ++ ) {

            vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];

            if ( !extrudeByPath ) {

                v( vert.x, vert.y, amount / steps * s );

            } else {

                // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );

                normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x );
                binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y );

                position2.copy( extrudePts[s] ).addSelf( normal ).addSelf( binormal );

                v( position2.x, position2.y, position2.z );

            }

        }

    }


    // Add bevel segments planes

    //for ( b = 1; b <= bevelSegments; b ++ ) {
    for ( b = bevelSegments - 1; b >= 0; b -- ) {

        t = b / bevelSegments;
        z = bevelThickness * ( 1 - t );
        //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) );
        bs = bevelSize * Math.sin ( t * Math.PI/2 ) ;

        // contract shape

        for ( i = 0, il = contour.length; i < il; i ++ ) {

            vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
            v( vert.x, vert.y,  amount + z );

        }

        // expand holes

        for ( h = 0, hl = holes.length; h < hl; h ++ ) {

            ahole = holes[ h ];
            oneHoleMovements = holesMovements[ h ];

            for ( i = 0, il = ahole.length; i < il; i ++ ) {

                vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );

                if ( !extrudeByPath ) {

                    v( vert.x, vert.y,  amount + z );

                } else {

                    v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );

                }

            }

        }

    }

    /* Faces */

    // Top and bottom faces

    buildLidFaces();

    // Sides faces

    buildSideFaces();


    /////  Internal functions

    function buildLidFaces() {

        if ( bevelEnabled ) {

            var layer = 0 ; // steps + 1
            var offset = vlen * layer;

            // Bottom faces

            for ( i = 0; i < flen; i ++ ) {

                face = faces[ i ];
                f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true );

            }

            layer = steps + bevelSegments * 2;
            offset = vlen * layer;

            // Top faces

            for ( i = 0; i < flen; i ++ ) {

                face = faces[ i ];
                f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false );

            }

        } else {

            // Bottom faces

            for ( i = 0; i < flen; i++ ) {

                face = faces[ i ];
                f3( face[ 2 ], face[ 1 ], face[ 0 ], true );

            }

            // Top faces

            for ( i = 0; i < flen; i ++ ) {

                face = faces[ i ];
                f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false );

            }
        }

    }

    // Create faces for the z-sides of the shape

    function buildSideFaces() {

        var layeroffset = 0;
        sidewalls( contour, layeroffset );
        layeroffset += contour.length;

        for ( h = 0, hl = holes.length;  h < hl; h ++ ) {

            ahole = holes[ h ];
            sidewalls( ahole, layeroffset );

            //, true
            layeroffset += ahole.length;

        }

    }

    function sidewalls( contour, layeroffset ) {

        var j, k;
        i = contour.length;

        while ( --i >= 0 ) {

            j = i;
            k = i - 1;
            if ( k < 0 ) k = contour.length - 1;

            //console.log('b', i,j, i-1, k,vertices.length);

            var s = 0, sl = steps  + bevelSegments * 2;

            for ( s = 0; s < sl; s ++ ) {

                var slen1 = vlen * s;
                var slen2 = vlen * ( s + 1 );

                var a = layeroffset + j + slen1,
                    b = layeroffset + k + slen1,
                    c = layeroffset + k + slen2,
                    d = layeroffset + j + slen2;

                f4( a, b, c, d, contour, s, sl, j, k );

            }
        }

    }


    function v( x, y, z ) {

        scope.vertices.push( new THREE.Vector3( x, y, z ) );

    }

    function f3( a, b, c, isBottom ) {

        a += shapesOffset;
        b += shapesOffset;
        c += shapesOffset;

        // normal, color, material
        scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) );

        var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c );

         scope.faceVertexUvs[ 0 ].push( uvs );

    }

    function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {

        a += shapesOffset;
        b += shapesOffset;
        c += shapesOffset;
        d += shapesOffset;

         scope.faces.push( new THREE.Face4( a, b, c, d, null, null, extrudeMaterial ) );

         var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d,
                                             stepIndex, stepsLength, contourIndex1, contourIndex2 );
         scope.faceVertexUvs[ 0 ].push( uvs );

    }

};

THREE.ExtrudeGeometry.WorldUVGenerator = {

    generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) {
        var ax = geometry.vertices[ indexA ].x,
            ay = geometry.vertices[ indexA ].y,

            bx = geometry.vertices[ indexB ].x,
            by = geometry.vertices[ indexB ].y,

            cx = geometry.vertices[ indexC ].x,
            cy = geometry.vertices[ indexC ].y;

        return [
            new THREE.UV( ax, ay ),
            new THREE.UV( bx, by ),
            new THREE.UV( cx, cy )
        ];

    },

    generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) {

        return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC );

    },

    generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions,
                                  indexA, indexB, indexC, indexD, stepIndex, stepsLength,
                                  contourIndex1, contourIndex2 ) {

        var ax = geometry.vertices[ indexA ].x,
            ay = geometry.vertices[ indexA ].y,
            az = geometry.vertices[ indexA ].z,

            bx = geometry.vertices[ indexB ].x,
            by = geometry.vertices[ indexB ].y,
            bz = geometry.vertices[ indexB ].z,

            cx = geometry.vertices[ indexC ].x,
            cy = geometry.vertices[ indexC ].y,
            cz = geometry.vertices[ indexC ].z,

            dx = geometry.vertices[ indexD ].x,
            dy = geometry.vertices[ indexD ].y,
            dz = geometry.vertices[ indexD ].z;

        if ( Math.abs( ay - by ) < 0.01 ) {
            return [
                new THREE.UV( ax, 1 - az ),
                new THREE.UV( bx, 1 - bz ),
                new THREE.UV( cx, 1 - cz ),
                new THREE.UV( dx, 1 - dz )
            ];
        } else {
            return [
                new THREE.UV( ay, 1 - az ),
                new THREE.UV( by, 1 - bz ),
                new THREE.UV( cy, 1 - cz ),
                new THREE.UV( dy, 1 - dz )
            ];
        }
    }
};

THREE.ExtrudeGeometry.__v1 = new THREE.Vector2();
THREE.ExtrudeGeometry.__v2 = new THREE.Vector2();
THREE.ExtrudeGeometry.__v3 = new THREE.Vector2();
THREE.ExtrudeGeometry.__v4 = new THREE.Vector2();
THREE.ExtrudeGeometry.__v5 = new THREE.Vector2();
THREE.ExtrudeGeometry.__v6 = new THREE.Vector2();
/**
 * @author jonobr1 / http://jonobr1.com
 *
 * Creates a one-sided polygonal geometry from a path shape. Similar to
 * ExtrudeGeometry.
 *
 * parameters = {
 *
 *    curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT.
 *
 *    material: <int> // material index for front and back faces
 *    uvGenerator: <Object> // object that provides UV generator functions
 *
 * }
 **/

THREE.ShapeGeometry = function ( shapes, options ) {

    THREE.Geometry.call( this );

    if ( shapes instanceof Array === false ) shapes = [ shapes ];

    this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox();

    this.addShapeList( shapes, options );

    this.computeCentroids();
    this.computeFaceNormals();

};

THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype );

/**
 * Add an array of shapes to THREE.ShapeGeometry.
 */
THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) {

    for ( var i = 0, l = shapes.length; i < l; i++ ) {

        this.addShape( shapes[ i ], options );

    }

    return this;

};

/**
 * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry.
 */
THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) {

    if ( options === undefined ) options = {};

    var material = options.material;
    var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator;

    var shapebb = this.shapebb;

    //

    var i, l, hole, s;

    var shapesOffset = this.vertices.length;
    var shapePoints = shape.extractPoints();

    var vertices = shapePoints.shape;
    var holes = shapePoints.holes;

    var reverse = !THREE.Shape.Utils.isClockWise( vertices );

    if ( reverse ) {

        vertices = vertices.reverse();

        // Maybe we should also check if holes are in the opposite direction, just to be safe...

        for ( i = 0, l = holes.length; i < l; i++ ) {

            hole = holes[ i ];

            if ( THREE.Shape.Utils.isClockWise( hole ) ) {

                holes[ i ] = hole.reverse();

            }

        }

        reverse = false;

    }

    var faces = THREE.Shape.Utils.triangulateShape( vertices, holes );

    // Vertices

    var contour = vertices;

    for ( i = 0, l = holes.length; i < l; i++ ) {

        hole = holes[ i ];
        vertices = vertices.concat( hole );

    }

    //

    var vert, vlen = vertices.length;
    var face, flen = faces.length;
    var cont, clen = contour.length;

    for ( i = 0; i < vlen; i++ ) {

        vert = vertices[ i ];

        this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) );

    }

    for ( i = 0; i < flen; i++ ) {

        face = faces[ i ];

        var a = face[ 2 ] + shapesOffset;
        var b = face[ 1 ] + shapesOffset;
        var c = face[ 0 ] + shapesOffset;

        this.faces.push( new THREE.Face3( a, b, c, null, null, material ) );
        this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) );

    }

};
/**
 * @author astrodud / http://astrodud.isgreat.org/
 * @author zz85 / https://github.com/zz85
 */

THREE.LatheGeometry = function ( points, steps, angle ) {

    THREE.Geometry.call( this );

    var _steps = steps || 12;
    var _angle = angle || 2 * Math.PI;

    var _newV = [];
    var _matrix = new THREE.Matrix4().makeRotationZ( _angle / _steps );

    for ( var j = 0; j < points.length; j ++ ) {

        _newV[ j ] = points[ j ].clone();
        this.vertices.push( _newV[ j ] );

    }

    var i, il = _steps + 1;

    for ( i = 0; i < il; i ++ ) {

        for ( var j = 0; j < _newV.length; j ++ ) {

            _newV[ j ] = _matrix.multiplyVector3( _newV[ j ].clone() );
            this.vertices.push( _newV[ j ] );

        }

    }

    for ( i = 0; i < _steps; i ++ ) {

        for ( var k = 0, kl = points.length; k < kl - 1; k ++ ) {

            var a = i * kl + k;
            var b = ( ( i + 1 ) % il ) * kl + k;
            var c = ( ( i + 1 ) % il ) * kl + ( k + 1 ) % kl;
            var d = i * kl + ( k + 1 ) % kl;

            this.faces.push( new THREE.Face4( a, b, c, d ) );

            this.faceVertexUvs[ 0 ].push( [

                new THREE.UV( 1 - i / _steps, k / kl ),
                new THREE.UV( 1 - ( i + 1 ) / _steps, k / kl ),
                new THREE.UV( 1 - ( i + 1 ) / _steps, ( k + 1 ) / kl ),
                new THREE.UV( 1 - i / _steps, ( k + 1 ) / kl )

            ] );

        }

    }

    this.computeCentroids();
    this.computeFaceNormals();
    this.computeVertexNormals();

};

THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
 */

THREE.PlaneGeometry = function ( width, height, segmentsWidth, segmentsheight ) {

    THREE.Geometry.call( this );

    var ix, iz,
    width_half = width / 2,
    height_half = height / 2,
    gridX = segmentsWidth || 1,
    gridZ = segmentsheight || 1,
    gridX1 = gridX + 1,
    gridZ1 = gridZ + 1,
    segment_width = width / gridX,
    segment_height = height / gridZ,
    normal = new THREE.Vector3( 0, 0, 1 );

    for ( iz = 0; iz < gridZ1; iz ++ ) {

        for ( ix = 0; ix < gridX1; ix ++ ) {

            var x = ix * segment_width - width_half;
            var y = iz * segment_height - height_half;

            this.vertices.push( new THREE.Vector3( x, - y, 0 ) );

        }

    }

    for ( iz = 0; iz < gridZ; iz ++ ) {

        for ( ix = 0; ix < gridX; ix ++ ) {

            var a = ix + gridX1 * iz;
            var b = ix + gridX1 * ( iz + 1 );
            var c = ( ix + 1 ) + gridX1 * ( iz + 1 );
            var d = ( ix + 1 ) + gridX1 * iz;

            var face = new THREE.Face4( a, b, c, d );
            face.normal.copy( normal );
            face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() );

            this.faces.push( face );
            this.faceVertexUvs[ 0 ].push( [
                new THREE.UV( ix / gridX, 1 - iz / gridZ ),
                new THREE.UV( ix / gridX, 1 - ( iz + 1 ) / gridZ ),
                new THREE.UV( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ),
                new THREE.UV( ( ix + 1 ) / gridX, 1 - iz / gridZ )
            ] );

        }

    }

    this.computeCentroids();

};

THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.SphereGeometry = function ( radius, segmentsWidth, segmentsHeight, phiStart, phiLength, thetaStart, thetaLength ) {

    THREE.Geometry.call( this );

    radius = radius || 50;

    phiStart = phiStart !== undefined ? phiStart : 0;
    phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;

    thetaStart = thetaStart !== undefined ? thetaStart : 0;
    thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;

    var segmentsX = Math.max( 3, Math.floor( segmentsWidth ) || 8 );
    var segmentsY = Math.max( 2, Math.floor( segmentsHeight ) || 6 );

    var x, y, vertices = [], uvs = [];

    for ( y = 0; y <= segmentsY; y ++ ) {

        var verticesRow = [];
        var uvsRow = [];

        for ( x = 0; x <= segmentsX; x ++ ) {

            var u = x / segmentsX;
            var v = y / segmentsY;

            var vertex = new THREE.Vector3();
            vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
            vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
            vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );

            this.vertices.push( vertex );

            verticesRow.push( this.vertices.length - 1 );
            uvsRow.push( new THREE.UV( u, 1 - v ) );

        }

        vertices.push( verticesRow );
        uvs.push( uvsRow );

    }

    for ( y = 0; y < segmentsY; y ++ ) {

        for ( x = 0; x < segmentsX; x ++ ) {

            var v1 = vertices[ y ][ x + 1 ];
            var v2 = vertices[ y ][ x ];
            var v3 = vertices[ y + 1 ][ x ];
            var v4 = vertices[ y + 1 ][ x + 1 ];

            var n1 = this.vertices[ v1 ].clone().normalize();
            var n2 = this.vertices[ v2 ].clone().normalize();
            var n3 = this.vertices[ v3 ].clone().normalize();
            var n4 = this.vertices[ v4 ].clone().normalize();

            var uv1 = uvs[ y ][ x + 1 ].clone();
            var uv2 = uvs[ y ][ x ].clone();
            var uv3 = uvs[ y + 1 ][ x ].clone();
            var uv4 = uvs[ y + 1 ][ x + 1 ].clone();

            if ( Math.abs( this.vertices[ v1 ].y ) == radius ) {

                this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) );
                this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] );

            } else if ( Math.abs( this.vertices[ v3 ].y ) ==  radius ) {

                this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
                this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );

            } else {

                this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) );
                this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] );

            }

        }

    }

    this.computeCentroids();
    this.computeFaceNormals();

    this.boundingSphere = { radius: radius };

};

THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * @author alteredq / http://alteredqualia.com/
 *
 * For creating 3D text geometry in three.js
 *
 * Text = 3D Text
 *
 * parameters = {
 *  size:             <float>,     // size of the text
 *  height:         <float>,     // thickness to extrude text
 *  curveSegments:     <int>,        // number of points on the curves
 *
 *  font:             <string>,        // font name
 *  weight:         <string>,        // font weight (normal, bold)
 *  style:             <string>,        // font style  (normal, italics)
 *
 *  bevelEnabled:    <bool>,            // turn on bevel
 *  bevelThickness: <float>,         // how deep into text bevel goes
 *  bevelSize:        <float>,         // how far from text outline is bevel
 *  }
 *
 */

/*    Usage Examples

    // TextGeometry wrapper

    var text3d = new TextGeometry( text, options );

    // Complete manner

    var textShapes = THREE.FontUtils.generateShapes( text, options );
    var text3d = new ExtrudeGeometry( textShapes, options );

*/


THREE.TextGeometry = function ( text, parameters ) {

    var textShapes = THREE.FontUtils.generateShapes( text, parameters );

    // translate parameters to ExtrudeGeometry API

    parameters.amount = parameters.height !== undefined ? parameters.height : 50;

    // defaults

    if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
    if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
    if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;

    THREE.ExtrudeGeometry.call( this, textShapes, parameters );

};

THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype );
/**
 * @author oosmoxiecode
 * @author mrdoob / http://mrdoob.com/
 * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888
 */

THREE.TorusGeometry = function ( radius, tube, segmentsR, segmentsT, arc ) {

    THREE.Geometry.call( this );

    var scope = this;

    this.radius = radius || 100;
    this.tube = tube || 40;
    this.segmentsR = segmentsR || 8;
    this.segmentsT = segmentsT || 6;
    this.arc = arc || Math.PI * 2;

    var center = new THREE.Vector3(), uvs = [], normals = [];

    for ( var j = 0; j <= this.segmentsR; j ++ ) {

        for ( var i = 0; i <= this.segmentsT; i ++ ) {

            var u = i / this.segmentsT * this.arc;
            var v = j / this.segmentsR * Math.PI * 2;

            center.x = this.radius * Math.cos( u );
            center.y = this.radius * Math.sin( u );

            var vertex = new THREE.Vector3();
            vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u );
            vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u );
            vertex.z = this.tube * Math.sin( v );

            this.vertices.push( vertex );

            uvs.push( new THREE.UV( i / this.segmentsT, j / this.segmentsR ) );
            normals.push( vertex.clone().subSelf( center ).normalize() );

        }
    }


    for ( var j = 1; j <= this.segmentsR; j ++ ) {

        for ( var i = 1; i <= this.segmentsT; i ++ ) {

            var a = ( this.segmentsT + 1 ) * j + i - 1;
            var b = ( this.segmentsT + 1 ) * ( j - 1 ) + i - 1;
            var c = ( this.segmentsT + 1 ) * ( j - 1 ) + i;
            var d = ( this.segmentsT + 1 ) * j + i;

            var face = new THREE.Face4( a, b, c, d, [ normals[ a ], normals[ b ], normals[ c ], normals[ d ] ] );
            face.normal.addSelf( normals[ a ] );
            face.normal.addSelf( normals[ b ] );
            face.normal.addSelf( normals[ c ] );
            face.normal.addSelf( normals[ d ] );
            face.normal.normalize();

            this.faces.push( face );

            this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] );
        }

    }

    this.computeCentroids();

};

THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author oosmoxiecode
 * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
 */

THREE.TorusKnotGeometry = function ( radius, tube, segmentsR, segmentsT, p, q, heightScale ) {

    THREE.Geometry.call( this );

    var scope = this;

    this.radius = radius || 200;
    this.tube = tube || 40;
    this.segmentsR = segmentsR || 64;
    this.segmentsT = segmentsT || 8;
    this.p = p || 2;
    this.q = q || 3;
    this.heightScale = heightScale || 1;
    this.grid = new Array(this.segmentsR);

    var tang = new THREE.Vector3();
    var n = new THREE.Vector3();
    var bitan = new THREE.Vector3();

    for ( var i = 0; i < this.segmentsR; ++ i ) {

        this.grid[ i ] = new Array( this.segmentsT );

        for ( var j = 0; j < this.segmentsT; ++ j ) {

            var u = i / this.segmentsR * 2 * this.p * Math.PI;
            var v = j / this.segmentsT * 2 * Math.PI;
            var p1 = getPos( u, v, this.q, this.p, this.radius, this.heightScale );
            var p2 = getPos( u + 0.01, v, this.q, this.p, this.radius, this.heightScale );
            var cx, cy;

            tang.sub( p2, p1 );
            n.add( p2, p1 );

            bitan.cross( tang, n );
            n.cross( bitan, tang );
            bitan.normalize();
            n.normalize();

            cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
            cy = this.tube * Math.sin( v );

            p1.x += cx * n.x + cy * bitan.x;
            p1.y += cx * n.y + cy * bitan.y;
            p1.z += cx * n.z + cy * bitan.z;

            this.grid[ i ][ j ] = vert( p1.x, p1.y, p1.z );

        }

    }

    for ( var i = 0; i < this.segmentsR; ++ i ) {

        for ( var j = 0; j < this.segmentsT; ++ j ) {

            var ip = ( i + 1 ) % this.segmentsR;
            var jp = ( j + 1 ) % this.segmentsT;

            var a = this.grid[ i ][ j ];
            var b = this.grid[ ip ][ j ];
            var c = this.grid[ ip ][ jp ];
            var d = this.grid[ i ][ jp ];

            var uva = new THREE.UV( i / this.segmentsR, j / this.segmentsT );
            var uvb = new THREE.UV( ( i + 1 ) / this.segmentsR, j / this.segmentsT );
            var uvc = new THREE.UV( ( i + 1 ) / this.segmentsR, ( j + 1 ) / this.segmentsT );
            var uvd = new THREE.UV( i / this.segmentsR, ( j + 1 ) / this.segmentsT );

            this.faces.push( new THREE.Face4( a, b, c, d ) );
            this.faceVertexUvs[ 0 ].push( [ uva,uvb,uvc, uvd ] );

        }
    }

    this.computeCentroids();
    this.computeFaceNormals();
    this.computeVertexNormals();

    function vert( x, y, z ) {

        return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1;

    }

    function getPos( u, v, in_q, in_p, radius, heightScale ) {

        var cu = Math.cos( u );
        var cv = Math.cos( v );
        var su = Math.sin( u );
        var quOverP = in_q / in_p * u;
        var cs = Math.cos( quOverP );

        var tx = radius * ( 2 + cs ) * 0.5 * cu;
        var ty = radius * ( 2 + cs ) * su * 0.5;
        var tz = heightScale * radius * Math.sin( quOverP ) * 0.5;

        return new THREE.Vector3( tx, ty, tz );

    }

};

THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author WestLangley / https://github.com/WestLangley
 * @author zz85 / https://github.com/zz85
 * @author miningold / https://github.com/miningold
 *
 * Modified from the TorusKnotGeometry by @oosmoxiecode
 *
 * Creates a tube which extrudes along a 3d spline
 *
 * Uses parallel transport frames as described in
 * http://www.cs.indiana.edu/pub/techreports/TR425.pdf
 */

THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, debug ) {

    THREE.Geometry.call( this );

    this.path = path;
    this.segments = segments || 64;
    this.radius = radius || 1;
    this.segmentsRadius = segmentsRadius || 8;
    this.closed = closed || false;
    if ( debug ) this.debug = new THREE.Object3D();

    this.grid = [];

    var scope = this,

        tangent,
        normal,
        binormal,

        numpoints = this.segments + 1,

        x, y, z,
        tx, ty, tz,
        u, v,

        cx, cy,
        pos, pos2 = new THREE.Vector3(),
        i, j,
        ip, jp,
        a, b, c, d,
        uva, uvb, uvc, uvd;

    var frames = new THREE.TubeGeometry.FrenetFrames(path, segments, closed),
        tangents = frames.tangents,
        normals = frames.normals,
        binormals = frames.binormals;

    // proxy internals
    this.tangents = tangents;
    this.normals = normals;
    this.binormals = binormals;


    function vert( x, y, z ) {

        return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1;

    }




    // consruct the grid

    for ( i = 0; i < numpoints; i++ ) {

        this.grid[ i ] = [];

        u = i / ( numpoints - 1 );

        pos = path.getPointAt( u );

        tangent = tangents[ i ];
        normal = normals[ i ];
        binormal = binormals[ i ];

        if ( this.debug ) {

            this.debug.add(new THREE.ArrowHelper(tangent, pos, radius, 0x0000ff));
            this.debug.add(new THREE.ArrowHelper(normal, pos, radius, 0xff0000));
            this.debug.add(new THREE.ArrowHelper(binormal, pos, radius, 0x00ff00));

        }

        for ( j = 0; j < this.segmentsRadius; j++ ) {

            v = j / this.segmentsRadius * 2 * Math.PI;

            cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
            cy = this.radius * Math.sin( v );

            pos2.copy( pos );
            pos2.x += cx * normal.x + cy * binormal.x;
            pos2.y += cx * normal.y + cy * binormal.y;
            pos2.z += cx * normal.z + cy * binormal.z;

            this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );

        }
    }


    // construct the mesh

    for ( i = 0; i < this.segments; i++ ) {

        for ( j = 0; j < this.segmentsRadius; j++ ) {

            ip = ( closed ) ? (i + 1) % this.segments : i + 1;
            jp = (j + 1) % this.segmentsRadius;

            a = this.grid[ i ][ j ];        // *** NOT NECESSARILY PLANAR ! ***
            b = this.grid[ ip ][ j ];
            c = this.grid[ ip ][ jp ];
            d = this.grid[ i ][ jp ];

            uva = new THREE.UV( i / this.segments, j / this.segmentsRadius );
            uvb = new THREE.UV( ( i + 1 ) / this.segments, j / this.segmentsRadius );
            uvc = new THREE.UV( ( i + 1 ) / this.segments, ( j + 1 ) / this.segmentsRadius );
            uvd = new THREE.UV( i / this.segments, ( j + 1 ) / this.segmentsRadius );

            this.faces.push( new THREE.Face4( a, b, c, d ) );
            this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvc, uvd ] );

        }
    }

    this.computeCentroids();
    this.computeFaceNormals();
    this.computeVertexNormals();

};

THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype );


// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) {

    var
        tangent = new THREE.Vector3(),
        normal = new THREE.Vector3(),
        binormal = new THREE.Vector3(),

        tangents = [],
        normals = [],
        binormals = [],

        vec = new THREE.Vector3(),
        mat = new THREE.Matrix4(),

        numpoints = segments + 1,
        theta,
        epsilon = 0.0001,
        smallest,

        tx, ty, tz,
        i, u, v;


    // expose internals
    this.tangents = tangents;
    this.normals = normals;
    this.binormals = binormals;

    // compute the tangent vectors for each segment on the path

    for ( i = 0; i < numpoints; i++ ) {

        u = i / ( numpoints - 1 );

        tangents[ i ] = path.getTangentAt( u );
        tangents[ i ].normalize();

    }

    initialNormal3();

    function initialNormal1(lastBinormal) {
        // fixed start binormal. Has dangers of 0 vectors
        normals[ 0 ] = new THREE.Vector3();
        binormals[ 0 ] = new THREE.Vector3();
        if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 );
        normals[ 0 ].cross( lastBinormal, tangents[ 0 ] ).normalize();
        binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] ).normalize();
    }

    function initialNormal2() {

        // This uses the Frenet-Serret formula for deriving binormal
        var t2 = path.getTangentAt( epsilon );

        normals[ 0 ] = new THREE.Vector3().sub( t2, tangents[ 0 ] ).normalize();
        binormals[ 0 ] = new THREE.Vector3().cross( tangents[ 0 ], normals[ 0 ] );

        normals[ 0 ].cross( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
        binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] ).normalize();

    }

    function initialNormal3() {
        // select an initial normal vector perpenicular to the first tangent vector,
        // and in the direction of the smallest tangent xyz component

        normals[ 0 ] = new THREE.Vector3();
        binormals[ 0 ] = new THREE.Vector3();
        smallest = Number.MAX_VALUE;
        tx = Math.abs( tangents[ 0 ].x );
        ty = Math.abs( tangents[ 0 ].y );
        tz = Math.abs( tangents[ 0 ].z );

        if ( tx <= smallest ) {
            smallest = tx;
            normal.set( 1, 0, 0 );
        }

        if ( ty <= smallest ) {
            smallest = ty;
            normal.set( 0, 1, 0 );
        }

        if ( tz <= smallest ) {
            normal.set( 0, 0, 1 );
        }

        vec.cross( tangents[ 0 ], normal ).normalize();

        normals[ 0 ].cross( tangents[ 0 ], vec );
        binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] );
    }


    // compute the slowly-varying normal and binormal vectors for each segment on the path

    for ( i = 1; i < numpoints; i++ ) {

        normals[ i ] = normals[ i-1 ].clone();

        binormals[ i ] = binormals[ i-1 ].clone();

        vec.cross( tangents[ i-1 ], tangents[ i ] );

        if ( vec.length() > epsilon ) {

            vec.normalize();

            theta = Math.acos( tangents[ i-1 ].dot( tangents[ i ] ) );

            mat.makeRotationAxis( vec, theta ).multiplyVector3( normals[ i ] );

        }

        binormals[ i ].cross( tangents[ i ], normals[ i ] );

    }


    // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same

    if ( closed ) {

        theta = Math.acos( normals[ 0 ].dot( normals[ numpoints-1 ] ) );
        theta /= ( numpoints - 1 );

        if ( tangents[ 0 ].dot( vec.cross( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) {

            theta = -theta;

        }

        for ( i = 1; i < numpoints; i++ ) {

            // twist a little...
            mat.makeRotationAxis( tangents[ i ], theta * i ).multiplyVector3( normals[ i ] );
            binormals[ i ].cross( tangents[ i ], normals[ i ] );

        }

    }
};
/**
 * @author clockworkgeek / https://github.com/clockworkgeek
 * @author timothypratley / https://github.com/timothypratley
 */

THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) {

    THREE.Geometry.call( this );

    radius = radius || 1;
    detail = detail || 0;

    var that = this;

    for ( var i = 0, l = vertices.length; i < l; i ++ ) {

        prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) );

    }

    var midpoints = [], p = this.vertices;

    for ( var i = 0, l = faces.length; i < l; i ++ ) {

        make( p[ faces[ i ][ 0 ] ], p[ faces[ i ][ 1 ] ], p[ faces[ i ][ 2 ] ], detail );

    }

    this.mergeVertices();

    // Apply radius

    for ( var i = 0, l = this.vertices.length; i < l; i ++ ) {

        this.vertices[ i ].multiplyScalar( radius );

    }


    // Project vector onto sphere's surface

    function prepare( vector ) {

        var vertex = vector.normalize().clone();
        vertex.index = that.vertices.push( vertex ) - 1;

        // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle.

        var u = azimuth( vector ) / 2 / Math.PI + 0.5;
        var v = inclination( vector ) / Math.PI + 0.5;
        vertex.uv = new THREE.UV( u, 1 - v );

        return vertex;

    }


    // Approximate a curved face with recursively sub-divided triangles.

    function make( v1, v2, v3, detail ) {

        if ( detail < 1 ) {

            var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] );
            face.centroid.addSelf( v1 ).addSelf( v2 ).addSelf( v3 ).divideScalar( 3 );
            face.normal = face.centroid.clone().normalize();
            that.faces.push( face );

            var azi = azimuth( face.centroid );
            that.faceVertexUvs[ 0 ].push( [
                correctUV( v1.uv, v1, azi ),
                correctUV( v2.uv, v2, azi ),
                correctUV( v3.uv, v3, azi )
            ] );

        } else {

            detail -= 1;

            // split triangle into 4 smaller triangles

            make( v1, midpoint( v1, v2 ), midpoint( v1, v3 ), detail ); // top quadrant
            make( midpoint( v1, v2 ), v2, midpoint( v2, v3 ), detail ); // left quadrant
            make( midpoint( v1, v3 ), midpoint( v2, v3 ), v3, detail ); // right quadrant
            make( midpoint( v1, v2 ), midpoint( v2, v3 ), midpoint( v1, v3 ), detail ); // center quadrant

        }

    }

    function midpoint( v1, v2 ) {

        if ( !midpoints[ v1.index ] ) midpoints[ v1.index ] = [];
        if ( !midpoints[ v2.index ] ) midpoints[ v2.index ] = [];

        var mid = midpoints[ v1.index ][ v2.index ];

        if ( mid === undefined ) {

            // generate mean point and project to surface with prepare()

            midpoints[ v1.index ][ v2.index ] = midpoints[ v2.index ][ v1.index ] = mid = prepare(
                new THREE.Vector3().add( v1, v2 ).divideScalar( 2 )
            );
        }

        return mid;

    }


    // Angle around the Y axis, counter-clockwise when looking from above.

    function azimuth( vector ) {

        return Math.atan2( vector.z, -vector.x );

    }


    // Angle above the XZ plane.

    function inclination( vector ) {

        return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );

    }


    // Texture fixing helper. Spheres have some odd behaviours.

    function correctUV( uv, vector, azimuth ) {

        if ( ( azimuth < 0 ) && ( uv.u === 1 ) ) uv = new THREE.UV( uv.u - 1, uv.v );
        if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.UV( azimuth / 2 / Math.PI + 0.5, uv.v );
        return uv;

    }

    this.computeCentroids();

    this.boundingSphere = { radius: radius };

};

THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author timothypratley / https://github.com/timothypratley
 */

THREE.IcosahedronGeometry = function ( radius, detail ) {

    var t = ( 1 + Math.sqrt( 5 ) ) / 2;

    var vertices = [
        [ -1,  t,  0 ], [  1, t, 0 ], [ -1, -t,  0 ], [  1, -t,  0 ],
        [  0, -1,  t ], [  0, 1, t ], [  0, -1, -t ], [  0,  1, -t ],
        [  t,  0, -1 ], [  t, 0, 1 ], [ -t,  0, -1 ], [ -t,  0,  1 ]
    ];

    var faces = [
        [ 0, 11,  5 ], [ 0,  5,  1 ], [  0,  1,  7 ], [  0,  7, 10 ], [  0, 10, 11 ],
        [ 1,  5,  9 ], [ 5, 11,  4 ], [ 11, 10,  2 ], [ 10,  7,  6 ], [  7,  1,  8 ],
        [ 3,  9,  4 ], [ 3,  4,  2 ], [  3,  2,  6 ], [  3,  6,  8 ], [  3,  8,  9 ],
        [ 4,  9,  5 ], [ 2,  4, 11 ], [  6,  2, 10 ], [  8,  6,  7 ], [  9,  8,  1 ]
    ];

    THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail );

};

THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author timothypratley / https://github.com/timothypratley
 */

THREE.OctahedronGeometry = function ( radius, detail ) {

    var vertices = [
        [ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ]
    ];

    var faces = [
        [ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ]
    ];

    THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail );
};

THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author timothypratley / https://github.com/timothypratley
 */

THREE.TetrahedronGeometry = function ( radius, detail ) {

    var vertices = [
        [ 1,  1,  1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ]
    ];

    var faces = [
        [ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ]
    ];

    THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail );

};

THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author zz85 / https://github.com/zz85
 * Parametric Surfaces Geometry
 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
 *
 * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements, useTris );
 *
 */

THREE.ParametricGeometry = function ( func, slices, stacks, useTris ) {

    THREE.Geometry.call( this );

    var verts = this.vertices;
    var faces = this.faces;
    var uvs = this.faceVertexUvs[ 0 ];

    useTris = (useTris === undefined) ? false : useTris;

    var i, il, j, p;
    var u, v;

    var stackCount = stacks + 1;
    var sliceCount = slices + 1;

    for ( i = 0; i <= stacks; i ++ ) {

        v = i / stacks;

        for ( j = 0; j <= slices; j ++ ) {

            u = j / slices;

            p = func( u, v );
            verts.push( p );

        }
    }

    var a, b, c, d;
    var uva, uvb, uvc, uvd;

    for ( i = 0; i < stacks; i ++ ) {

        for ( j = 0; j < slices; j ++ ) {

            a = i * sliceCount + j;
            b = i * sliceCount + j + 1;
            c = (i + 1) * sliceCount + j;
            d = (i + 1) * sliceCount + j + 1;

            uva = new THREE.UV( j / slices, i / stacks );
            uvb = new THREE.UV( ( j + 1 ) / slices, i / stacks );
            uvc = new THREE.UV( j / slices, ( i + 1 ) / stacks );
            uvd = new THREE.UV( ( j + 1 ) / slices, ( i + 1 ) / stacks );

            if ( useTris ) {

                faces.push( new THREE.Face3( a, b, c ) );
                faces.push( new THREE.Face3( b, d, c ) );

                uvs.push( [ uva, uvb, uvc ] );
                uvs.push( [ uvb, uvd, uvc ] );

            } else {

                faces.push( new THREE.Face4( a, b, d, c ) );
                uvs.push( [ uva, uvb, uvd, uvc ] );

            }

        }

    }

    // console.log(this);

    // magic bullet
    // var diff = this.mergeVertices();
    // console.log('removed ', diff, ' vertices by merging');

    this.computeCentroids();
    this.computeFaceNormals();
    this.computeVertexNormals();

};

THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author qiao / https://github.com/qiao
 * @fileoverview This is a convex hull generator using the incremental method.
 * The complexity is O(n^2) where n is the number of vertices.
 * O(nlogn) algorithms do exist, but they are much more complicated.
 *
 * Benchmark:
 *
 *  Platform: CPU: P7350 @2.00GHz Engine: V8
 *
 *  Num Vertices    Time(ms)
 *
 *     10           1
 *     20           3
 *     30           19
 *     40           48
 *     50           107
 */

THREE.ConvexGeometry = function( vertices ) {

    THREE.Geometry.call( this );

    var faces = [ [ 0, 1, 2 ], [ 0, 2, 1 ] ];

    for ( var i = 3; i < vertices.length; i++ ) {

        addPoint( i );

    }


    function addPoint( vertexId ) {

        var vertex = vertices[ vertexId ].clone();

        var mag = vertex.length();
        vertex.x += mag * randomOffset();
        vertex.y += mag * randomOffset();
        vertex.z += mag * randomOffset();

        var hole = [];

        for ( var f = 0; f < faces.length; ) {

            var face = faces[ f ];

            // for each face, if the vertex can see it,
            // then we try to add the face's edges into the hole.
            if ( visible( face, vertex ) ) {

                for ( var e = 0; e < 3; e++ ) {

                    var edge = [ face[ e ], face[ ( e + 1 ) % 3 ] ];
                    var boundary = true;

                    // remove duplicated edges.
                    for ( var h = 0; h < hole.length; h++ ) {

                        if ( equalEdge( hole[ h ], edge ) ) {

                            hole[ h ] = hole[ hole.length - 1 ];
                            hole.pop();
                            boundary = false;
                            break;

                        }

                    }

                    if ( boundary ) {

                        hole.push( edge );

                    }

                }

                // remove faces[ f ]
                faces[ f ] = faces[ faces.length - 1 ];
                faces.pop();

            } else { // not visible

                f++;

            }
        }

        // construct the new faces formed by the edges of the hole and the vertex
        for ( var h = 0; h < hole.length; h++ ) {

            faces.push( [
                hole[ h ][ 0 ],
                hole[ h ][ 1 ],
                vertexId
            ] );

        }
    }

    /**
     * Whether the face is visible from the vertex
     */
    function visible( face, vertex ) {

        var va = vertices[ face[ 0 ] ];
        var vb = vertices[ face[ 1 ] ];
        var vc = vertices[ face[ 2 ] ];

        var n = normal( va, vb, vc );

        // distance from face to origin
        var dist = n.dot( va );

        return n.dot( vertex ) >= dist;

    }

    /**
     * Face normal
     */
    function normal( va, vb, vc ) {

        var cb = new THREE.Vector3();
        var ab = new THREE.Vector3();

        cb.sub( vc, vb );
        ab.sub( va, vb );
        cb.crossSelf( ab );

        if ( !cb.isZero() ) {

            cb.normalize();

        }

        return cb;

    }

    /**
     * Detect whether two edges are equal.
     * Note that when constructing the convex hull, two same edges can only
     * be of the negative direction.
     */
    function equalEdge( ea, eb ) {

        return ea[ 0 ] === eb[ 1 ] && ea[ 1 ] === eb[ 0 ];

    }

    /**
     * Create a random offset between -1e-6 and 1e-6.
     */
    function randomOffset() {

        return ( Math.random() - 0.5 ) * 2 * 1e-6;

    }


    /**
     * XXX: Not sure if this is the correct approach. Need someone to review.
     */
    function vertexUv( vertex ) {

        var mag = vertex.length();
        return new THREE.UV( vertex.x / mag, vertex.y / mag );

    }

    // Push vertices into `this.vertices`, skipping those inside the hull
    var id = 0;
    var newId = new Array( vertices.length ); // map from old vertex id to new id

    for ( var i = 0; i < faces.length; i++ ) {

         var face = faces[ i ];

         for ( var j = 0; j < 3; j++ ) {

                if ( newId[ face[ j ] ] === undefined ) {

                        newId[ face[ j ] ] = id++;
                        this.vertices.push( vertices[ face[ j ] ] );

                }

                face[ j ] = newId[ face[ j ] ];

         }

    }

    // Convert faces into instances of THREE.Face3
    for ( var i = 0; i < faces.length; i++ ) {

        this.faces.push( new THREE.Face3(
                faces[ i ][ 0 ],
                faces[ i ][ 1 ],
                faces[ i ][ 2 ]
        ) );

    }

    // Compute UVs
    for ( var i = 0; i < this.faces.length; i++ ) {

        var face = this.faces[ i ];

        this.faceVertexUvs[ 0 ].push( [
            vertexUv( this.vertices[ face.a ] ),
            vertexUv( this.vertices[ face.b ] ),
            vertexUv( this.vertices[ face.c ])
        ] );

    }


    this.computeCentroids();
    this.computeFaceNormals();
    this.computeVertexNormals();

};

THREE.ConvexGeometry.prototype = Object.create( THREE.Geometry.prototype );
/**
 * @author sroucheray / http://sroucheray.org/
 * @author mrdoob / http://mrdoob.com/
 */

THREE.AxisHelper = function () {

    THREE.Object3D.call( this );

    var lineGeometry = new THREE.Geometry();
    lineGeometry.vertices.push( new THREE.Vector3() );
    lineGeometry.vertices.push( new THREE.Vector3( 0, 100, 0 ) );

    var coneGeometry = new THREE.CylinderGeometry( 0, 5, 25, 5, 1 );

    var line, cone;

    // x

    line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color : 0xff0000 } ) );
    line.rotation.z = - Math.PI / 2;
    this.add( line );

    cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color : 0xff0000 } ) );
    cone.position.x = 100;
    cone.rotation.z = - Math.PI / 2;
    this.add( cone );

    // y

    line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color : 0x00ff00 } ) );
    this.add( line );

    cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color : 0x00ff00 } ) );
    cone.position.y = 100;
    this.add( cone );

    // z

    line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color : 0x0000ff } ) );
    line.rotation.x = Math.PI / 2;
    this.add( line );

    cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color : 0x0000ff } ) );
    cone.position.z = 100;
    cone.rotation.x = Math.PI / 2;
    this.add( cone );

};

THREE.AxisHelper.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author WestLangley / http://github.com/WestLangley
 * @author zz85 / https://github.com/zz85
 *
 * Creates an arrow for visualizing directions
 *
 * Parameters:
 *  dir - Vector3
 *  origin - Vector3
 *  length - Number
 *  hex - color in hex value
 */

THREE.ArrowHelper = function ( dir, origin, length, hex ) {

    THREE.Object3D.call( this );

    if ( hex === undefined ) hex = 0xffff00;
    if ( length === undefined ) length = 20;

    var lineGeometry = new THREE.Geometry();
    lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) );
    lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) );

    this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) );
    this.add( this.line );

    var coneGeometry = new THREE.CylinderGeometry( 0, 0.05, 0.25, 5, 1 );

    this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) );
    this.cone.position.set( 0, 1, 0 );
    this.add( this.cone );

    if ( origin instanceof THREE.Vector3 ) this.position = origin;

    this.setDirection( dir );
    this.setLength( length );

};

THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype );

THREE.ArrowHelper.prototype.setDirection = function ( dir ) {

    var axis = new THREE.Vector3( 0, 1, 0 ).crossSelf( dir );

    var radians = Math.acos( new THREE.Vector3( 0, 1, 0 ).dot( dir.clone().normalize() ) );

    this.matrix = new THREE.Matrix4().makeRotationAxis( axis.normalize(), radians );

    this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );

};

THREE.ArrowHelper.prototype.setLength = function ( length ) {

    this.scale.set( length, length, length );

};

THREE.ArrowHelper.prototype.setColor = function ( hex ) {

    this.line.material.color.setHex( hex );
    this.cone.material.color.setHex( hex );

};
/**
 * @author alteredq / http://alteredqualia.com/
 *
 *    - shows frustum, line of sight and up of the camera
 *    - suitable for fast updates
 *     - based on frustum visualization in lightgl.js shadowmap example
 *        http://evanw.github.com/lightgl.js/tests/shadowmap.html
 */

THREE.CameraHelper = function ( camera ) {

    THREE.Line.call( this );

    var scope = this;

    this.geometry = new THREE.Geometry();
    this.material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } );
    this.type = THREE.LinePieces;

    this.matrixWorld = camera.matrixWorld;
    this.matrixAutoUpdate = false;

    this.pointMap = {};

    // colors

    var hexFrustum = 0xffaa00;
    var hexCone = 0xff0000;
    var hexUp = 0x00aaff;
    var hexTarget = 0xffffff;
    var hexCross = 0x333333;

    // near

    addLine( "n1", "n2", hexFrustum );
    addLine( "n2", "n4", hexFrustum );
    addLine( "n4", "n3", hexFrustum );
    addLine( "n3", "n1", hexFrustum );

    // far

    addLine( "f1", "f2", hexFrustum );
    addLine( "f2", "f4", hexFrustum );
    addLine( "f4", "f3", hexFrustum );
    addLine( "f3", "f1", hexFrustum );

    // sides

    addLine( "n1", "f1", hexFrustum );
    addLine( "n2", "f2", hexFrustum );
    addLine( "n3", "f3", hexFrustum );
    addLine( "n4", "f4", hexFrustum );

    // cone

    addLine( "p", "n1", hexCone );
    addLine( "p", "n2", hexCone );
    addLine( "p", "n3", hexCone );
    addLine( "p", "n4", hexCone );

    // up

    addLine( "u1", "u2", hexUp );
    addLine( "u2", "u3", hexUp );
    addLine( "u3", "u1", hexUp );

    // target

    addLine( "c", "t", hexTarget );
    addLine( "p", "c", hexCross );

    // cross

    addLine( "cn1", "cn2", hexCross );
    addLine( "cn3", "cn4", hexCross );

    addLine( "cf1", "cf2", hexCross );
    addLine( "cf3", "cf4", hexCross );

    this.camera = camera;

    function addLine( a, b, hex ) {

        addPoint( a, hex );
        addPoint( b, hex );

    }

    function addPoint( id, hex ) {

        scope.geometry.vertices.push( new THREE.Vector3() );
        scope.geometry.colors.push( new THREE.Color( hex ) );

        if ( scope.pointMap[ id ] === undefined ) scope.pointMap[ id ] = [];

        scope.pointMap[ id ].push( scope.geometry.vertices.length - 1 );

    }

    this.update( camera );

};

THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype );

THREE.CameraHelper.prototype.update = function () {

    var scope = this;

    var w = 1, h = 1;

    // we need just camera projection matrix
    // world matrix must be identity

    THREE.CameraHelper.__c.projectionMatrix.copy( this.camera.projectionMatrix );

    // center / target

    setPoint( "c", 0, 0, -1 );
    setPoint( "t", 0, 0,  1 );

    // near

    setPoint( "n1", -w, -h, -1 );
    setPoint( "n2",  w, -h, -1 );
    setPoint( "n3", -w,  h, -1 );
    setPoint( "n4",  w,  h, -1 );

    // far

    setPoint( "f1", -w, -h, 1 );
    setPoint( "f2",  w, -h, 1 );
    setPoint( "f3", -w,  h, 1 );
    setPoint( "f4",  w,  h, 1 );

    // up

    setPoint( "u1",  w * 0.7, h * 1.1, -1 );
    setPoint( "u2", -w * 0.7, h * 1.1, -1 );
    setPoint( "u3",        0, h * 2,   -1 );

    // cross

    setPoint( "cf1", -w,  0, 1 );
    setPoint( "cf2",  w,  0, 1 );
    setPoint( "cf3",  0, -h, 1 );
    setPoint( "cf4",  0,  h, 1 );

    setPoint( "cn1", -w,  0, -1 );
    setPoint( "cn2",  w,  0, -1 );
    setPoint( "cn3",  0, -h, -1 );
    setPoint( "cn4",  0,  h, -1 );

    function setPoint( point, x, y, z ) {

        THREE.CameraHelper.__v.set( x, y, z );
        THREE.CameraHelper.__projector.unprojectVector( THREE.CameraHelper.__v, THREE.CameraHelper.__c );

        var points = scope.pointMap[ point ];

        if ( points !== undefined ) {

            for ( var i = 0, il = points.length; i < il; i ++ ) {

                scope.geometry.vertices[ points[ i ] ].copy( THREE.CameraHelper.__v );

            }

        }

    }

    this.geometry.verticesNeedUpdate = true;

};

THREE.CameraHelper.__projector = new THREE.Projector();
THREE.CameraHelper.__v = new THREE.Vector3();
THREE.CameraHelper.__c = new THREE.Camera();

/*
 *    @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
 *
 *    Subdivision Geometry Modifier
 *        using Catmull-Clark Subdivision Surfaces
 *        for creating smooth geometry meshes
 *
 *    Note: a modifier modifies vertices and faces of geometry,
 *        so use THREE.GeometryUtils.clone() if orignal geoemtry needs to be retained
 *
 *    Readings:
 *        http://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface
 *        http://www.rorydriscoll.com/2008/08/01/catmull-clark-subdivision-the-basics/
 *        http://xrt.wikidot.com/blog:31
 *        "Subdivision Surfaces in Character Animation"
 *
 *    Supports:
 *        Closed and Open geometries.
 *
 *    TODO:
 *        crease vertex and "semi-sharp" features
 *        selective subdivision
 */

THREE.SubdivisionModifier = function( subdivisions ) {

    this.subdivisions = (subdivisions === undefined ) ? 1 : subdivisions;

    // Settings
    this.useOldVertexColors = false;
    this.supportUVs = true;
    this.debug = false;

};

// Applies the "modify" pattern
THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {

    var repeats = this.subdivisions;

    while ( repeats-- > 0 ) {
        this.smooth( geometry );
    }

};

// Performs an iteration of Catmull-Clark Subdivision
THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {

    //debug( 'running smooth' );

    // New set of vertices, faces and uvs
    var newVertices = [], newFaces = [], newUVs = [];

    function v( x, y, z ) {
        newVertices.push( new THREE.Vector3( x, y, z ) );
    }

    var scope = this;

    function debug() {
        if (scope.debug) console.log.apply(console, arguments);
    }

    function warn() {
        if (console)
        console.log.apply(console, arguments);
    }

    function f4( a, b, c, d, oldFace, orders, facei ) {

        // TODO move vertex selection over here!

        var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.materialIndex );

        if (scope.useOldVertexColors) {

            newFace.vertexColors = [];

            var color, tmpColor, order;
            for (var i=0;i<4;i++) {
                order = orders[i];

                color = new THREE.Color(),
                color.setRGB(0,0,0);

                for (var j=0, jl=0; j<order.length;j++) {
                    tmpColor = oldFace.vertexColors[order[j]-1];
                    color.r += tmpColor.r;
                    color.g += tmpColor.g;
                    color.b += tmpColor.b;
                }

                color.r /= order.length;
                color.g /= order.length;
                color.b /= order.length;

                newFace.vertexColors[i] = color;

            }

        }

        newFaces.push( newFace );

        if (scope.supportUVs) {

            var aUv = [
                getUV(a, ''),
                getUV(b, facei),
                getUV(c, facei),
                getUV(d, facei)
            ];

            if (!aUv[0]) debug('a :( ', a+':'+facei);
            else if (!aUv[1]) debug('b :( ', b+':'+facei);
            else if (!aUv[2]) debug('c :( ', c+':'+facei);
            else if (!aUv[3]) debug('d :( ', d+':'+facei);
            else
                newUVs.push( aUv );

        }
    }

    function edge_hash( a, b ) {

        return Math.min( a, b ) + "_" + Math.max( a, b );

    }

    function computeEdgeFaces( geometry ) {

        var i, il, v1, v2, j, k,
            face, faceIndices, faceIndex,
            edge,
            hash,
            edgeFaceMap = {};

        function mapEdgeHash( hash, i ) {

            if ( edgeFaceMap[ hash ] === undefined ) {

                edgeFaceMap[ hash ] = [];

            }

            edgeFaceMap[ hash ].push( i );
        }


        // construct vertex -> face map

        for( i = 0, il = geometry.faces.length; i < il; i ++ ) {

            face = geometry.faces[ i ];

            if ( face instanceof THREE.Face3 ) {

                hash = edge_hash( face.a, face.b );
                mapEdgeHash( hash, i );

                hash = edge_hash( face.b, face.c );
                mapEdgeHash( hash, i );

                hash = edge_hash( face.c, face.a );
                mapEdgeHash( hash, i );

            } else if ( face instanceof THREE.Face4 ) {

                hash = edge_hash( face.a, face.b );
                mapEdgeHash( hash, i );

                hash = edge_hash( face.b, face.c );
                mapEdgeHash( hash, i );

                hash = edge_hash( face.c, face.d );
                mapEdgeHash( hash, i );

                hash = edge_hash( face.d, face.a );
                mapEdgeHash( hash, i );

            }

        }

        // extract faces

        // var edges = [];
        //
        // var numOfEdges = 0;
        // for (i in edgeFaceMap) {
        //     numOfEdges++;
        //
        //     edge = edgeFaceMap[i];
        //     edges.push(edge);
        //
        // }

        //debug('edgeFaceMap', edgeFaceMap, 'geometry.edges',geometry.edges, 'numOfEdges', numOfEdges);

        return edgeFaceMap;

    }

    var originalPoints = oldGeometry.vertices;
    var originalFaces = oldGeometry.faces;

    var newPoints = originalPoints.concat(); // Vertices

    var facePoints = [], edgePoints = {};

    var sharpEdges = {}, sharpVertices = [], sharpFaces = [];

    var uvForVertices = {}; // Stored in {vertex}:{old face} format

    var originalVerticesLength = originalPoints.length;

    function getUV(vertexNo, oldFaceNo) {
        var j,jl;

        var key = vertexNo+':'+oldFaceNo;
        var theUV = uvForVertices[key];

        if (!theUV) {
            if (vertexNo>=originalVerticesLength && vertexNo < (originalVerticesLength + originalFaces.length)) {
                debug('face pt');
            } else {
                debug('edge pt');
            }

            warn('warning, UV not found for', key);

            return null;
        }

        return theUV;

        // Original faces -> Vertex Nos.
        // new Facepoint -> Vertex Nos.
        // edge Points

    }

    function addUV(vertexNo, oldFaceNo, value) {

        var key = vertexNo+':'+oldFaceNo;
        if (!(key in uvForVertices)) {
            uvForVertices[key] = value;
        } else {
            warn('dup vertexNo', vertexNo, 'oldFaceNo', oldFaceNo, 'value', value, 'key', key, uvForVertices[key]);
        }
    }

    // Step 1
    //    For each face, add a face point
    //    Set each face point to be the centroid of all original points for the respective face.
    // debug(oldGeometry);
    var i, il, j, jl, face;

    // For Uvs
    var uvs = oldGeometry.faceVertexUvs[0];
    var abcd = 'abcd', vertice;

    debug('originalFaces, uvs, originalVerticesLength', originalFaces.length, uvs.length, originalVerticesLength);
    if (scope.supportUVs)
    for (i=0, il = uvs.length; i<il; i++ ) {
        for (j=0,jl=uvs[i].length;j<jl;j++) {
            vertice = originalFaces[i][abcd.charAt(j)];

            addUV(vertice, i, uvs[i][j]);

        }
    }

    if (uvs.length == 0) scope.supportUVs = false;

    // Additional UVs check, if we index original
    var uvCount = 0;
    for (var u in uvForVertices) {
        uvCount++;
    }
    if (!uvCount) {
        scope.supportUVs = false;
        debug('no uvs');
    }

    debug('-- Original Faces + Vertices UVs completed', uvForVertices, 'vs', uvs.length);

    var avgUv ;
    for (i=0, il = originalFaces.length; i<il ;i++) {
        face = originalFaces[ i ];
        facePoints.push( face.centroid );
        newPoints.push( face.centroid );


        if (!scope.supportUVs) continue;

        // Prepare subdivided uv

        avgUv = new THREE.UV();

        if ( face instanceof THREE.Face3 ) {
            avgUv.u = getUV( face.a, i ).u + getUV( face.b, i ).u + getUV( face.c, i ).u;
            avgUv.v = getUV( face.a, i ).v + getUV( face.b, i ).v + getUV( face.c, i ).v;
            avgUv.u /= 3;
            avgUv.v /= 3;

        } else if ( face instanceof THREE.Face4 ) {
            avgUv.u = getUV( face.a, i ).u + getUV( face.b, i ).u + getUV( face.c, i ).u + getUV( face.d, i ).u;
            avgUv.v = getUV( face.a, i ).v + getUV( face.b, i ).v + getUV( face.c, i ).v + getUV( face.d, i ).v;
            avgUv.u /= 4;
            avgUv.v /= 4;
        }

        addUV(originalVerticesLength + i, '', avgUv);

    }

    debug('-- added UVs for new Faces', uvForVertices);

    // Step 2
    //    For each edge, add an edge point.
    //    Set each edge point to be the average of the two neighbouring face points and its two original endpoints.

    var edgeFaceMap = computeEdgeFaces ( oldGeometry ); // Edge Hash -> Faces Index
    var edge, faceIndexA, faceIndexB, avg;

    // debug('edgeFaceMap', edgeFaceMap);

    var edgeCount = 0;

    var edgeVertex, edgeVertexA, edgeVertexB;

    ////

    var vertexEdgeMap = {}; // Gives edges connecting from each vertex
    var vertexFaceMap = {}; // Gives faces connecting from each vertex

    function addVertexEdgeMap(vertex, edge) {
        if (vertexEdgeMap[vertex]===undefined) {
            vertexEdgeMap[vertex] = [];
        }

        vertexEdgeMap[vertex].push(edge);
    }

    function addVertexFaceMap(vertex, face, edge) {
        if (vertexFaceMap[vertex]===undefined) {
            vertexFaceMap[vertex] = {};
        }

        vertexFaceMap[vertex][face] = edge;
        // vertexFaceMap[vertex][face] = null;
    }

    // Prepares vertexEdgeMap and vertexFaceMap
    for (i in edgeFaceMap) { // This is for every edge
        edge = edgeFaceMap[i];

        edgeVertex = i.split('_');
        edgeVertexA = edgeVertex[0];
        edgeVertexB = edgeVertex[1];

        // Maps an edgeVertex to connecting edges
        addVertexEdgeMap(edgeVertexA, [edgeVertexA, edgeVertexB] );
        addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] );


        for (j=0,jl=edge.length;j<jl;j++) {
            face = edge[j];

            addVertexFaceMap(edgeVertexA, face, i);
            addVertexFaceMap(edgeVertexB, face, i);
        }

        if (edge.length < 2) {
            // edge is "sharp";
            sharpEdges[i] = true;
            sharpVertices[edgeVertexA] = true;
            sharpVertices[edgeVertexB] = true;

        }

    }

    debug('vertexEdgeMap',vertexEdgeMap, 'vertexFaceMap', vertexFaceMap);


    for (i in edgeFaceMap) {
        edge = edgeFaceMap[i];

        faceIndexA = edge[0]; // face index a
        faceIndexB = edge[1]; // face index b

        edgeVertex = i.split('_');
        edgeVertexA = edgeVertex[0];
        edgeVertexB = edgeVertex[1];


        avg = new THREE.Vector3();

        //debug(i, faceIndexB,facePoints[faceIndexB]);

        if (sharpEdges[i]) {
            //debug('warning, ', i, 'edge has only 1 connecting face', edge);

            // For a sharp edge, average the edge end points.
            avg.addSelf(originalPoints[edgeVertexA]);
            avg.addSelf(originalPoints[edgeVertexB]);

            avg.multiplyScalar(0.5);

            sharpVertices[newPoints.length] = true;

        } else {

            avg.addSelf(facePoints[faceIndexA]);
            avg.addSelf(facePoints[faceIndexB]);

            avg.addSelf(originalPoints[edgeVertexA]);
            avg.addSelf(originalPoints[edgeVertexB]);

            avg.multiplyScalar(0.25);

        }

        edgePoints[i] = originalVerticesLength + originalFaces.length + edgeCount;

        newPoints.push( avg );

        edgeCount ++;

        if (!scope.supportUVs) {
            continue;
        }

        // debug('faceIndexAB', faceIndexA, faceIndexB, sharpEdges[i]);

        // Prepare subdivided uv

        avgUv = new THREE.UV();

        avgUv.u = getUV(edgeVertexA, faceIndexA).u + getUV(edgeVertexB, faceIndexA).u;
        avgUv.v = getUV(edgeVertexA, faceIndexA).v + getUV(edgeVertexB, faceIndexA).v;
        avgUv.u /= 2;
        avgUv.v /= 2;

        addUV(edgePoints[i], faceIndexA, avgUv);

        if (!sharpEdges[i]) {
        avgUv = new THREE.UV();

        avgUv.u = getUV(edgeVertexA, faceIndexB).u + getUV(edgeVertexB, faceIndexB).u;
        avgUv.v = getUV(edgeVertexA, faceIndexB).v + getUV(edgeVertexB, faceIndexB).v;
        avgUv.u /= 2;
        avgUv.v /= 2;

        addUV(edgePoints[i], faceIndexB, avgUv);
        }

    }

    debug('-- Step 2 done');

    // Step 3
    //    For each face point, add an edge for every edge of the face,
    //    connecting the face point to each edge point for the face.


    var facePt, currentVerticeIndex;

    var hashAB, hashBC, hashCD, hashDA, hashCA;

    var abc123 = ['123', '12', '2', '23'];
    var bca123 = ['123', '23', '3', '31'];
    var cab123 = ['123', '31', '1', '12'];
    var abc1234 = ['1234', '12', '2', '23'];
    var bcd1234 = ['1234', '23', '3', '34'];
    var cda1234 = ['1234', '34', '4', '41'];
    var dab1234 = ['1234', '41', '1', '12'];


    for (i=0, il = facePoints.length; i<il ;i++) { // for every face
        facePt = facePoints[i];
        face = originalFaces[i];
        currentVerticeIndex = originalVerticesLength+ i;

        if ( face instanceof THREE.Face3 ) {

            // create 3 face4s

            hashAB = edge_hash( face.a, face.b );
            hashBC = edge_hash( face.b, face.c );
            hashCA = edge_hash( face.c, face.a );

            f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc123, i );
            f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCA], face, bca123, i );
            f4( currentVerticeIndex, edgePoints[hashCA], face.a, edgePoints[hashAB], face, cab123, i );

        } else if ( face instanceof THREE.Face4 ) {
            // create 4 face4s

            hashAB = edge_hash( face.a, face.b );
            hashBC = edge_hash( face.b, face.c );
            hashCD = edge_hash( face.c, face.d );
            hashDA = edge_hash( face.d, face.a );

            f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc1234, i );
            f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCD], face, bcd1234, i );
            f4( currentVerticeIndex, edgePoints[hashCD], face.d, edgePoints[hashDA], face, cda1234, i );
            f4( currentVerticeIndex, edgePoints[hashDA], face.a, edgePoints[hashAB], face, dab1234, i );


        } else {
            debug('face should be a face!', face);
        }
    }

    newVertices = newPoints;

    // debug('original ', oldGeometry.vertices.length, oldGeometry.faces.length );
    // debug('new points', newPoints.length, 'faces', newFaces.length );

    // Step 4

    //    For each original point P,
    //        take the average F of all n face points for faces touching P,
    //        and take the average R of all n edge midpoints for edges touching P,
    //        where each edge midpoint is the average of its two endpoint vertices.
    //    Move each original point to the point


    var F = new THREE.Vector3();
    var R = new THREE.Vector3();

    var n;
    for (i=0, il = originalPoints.length; i<il; i++) {
        // (F + 2R + (n-3)P) / n

        if (vertexEdgeMap[i]===undefined) continue;

        F.set(0,0,0);
        R.set(0,0,0);
        var newPos =  new THREE.Vector3(0,0,0);

        var f =0;
        for (j in vertexFaceMap[i]) {
            F.addSelf(facePoints[j]);
            f++;
        }

        var sharpEdgeCount = 0;

        n = vertexEdgeMap[i].length;

        for (j=0;j<n;j++) {
            if (
                sharpEdges[
                    edge_hash(vertexEdgeMap[i][j][0],vertexEdgeMap[i][j][1])
                ]) {
                    sharpEdgeCount++;
                }
        }

        if ( sharpEdgeCount==2 ) {
            continue;
            // Do not move vertex if there's 2 connecting sharp edges.
        }

        /*
        if (sharpEdgeCount>2) {
            // TODO
        }
        */

        F.divideScalar(f);



        for (j=0; j<n;j++) {
            edge = vertexEdgeMap[i][j];
            var midPt = originalPoints[edge[0]].clone().addSelf(originalPoints[edge[1]]).divideScalar(2);
            R.addSelf(midPt);
            // R.addSelf(originalPoints[edge[0]]);
            // R.addSelf(originalPoints[edge[1]]);
        }

        R.divideScalar(n);

        newPos.addSelf(originalPoints[i]);
        newPos.multiplyScalar(n - 3);

        newPos.addSelf(F);
        newPos.addSelf(R.multiplyScalar(2));
        newPos.divideScalar(n);

        newVertices[i] = newPos;


    }

    var newGeometry = oldGeometry; // Let's pretend the old geometry is now new :P

    newGeometry.vertices = newVertices;
    newGeometry.faces = newFaces;
    newGeometry.faceVertexUvs[ 0 ] = newUVs;

    delete newGeometry.__tmpVertices; // makes __tmpVertices undefined :P

    newGeometry.computeCentroids();
    newGeometry.computeFaceNormals();
    newGeometry.computeVertexNormals();

};
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.ImmediateRenderObject = function ( ) {

    THREE.Object3D.call( this );

    this.render = function ( renderCallback ) { };

};

THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype );
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.LensFlare = function ( texture, size, distance, blending, color ) {

    THREE.Object3D.call( this );

    this.lensFlares = [];

    this.positionScreen = new THREE.Vector3();
    this.customUpdateCallback = undefined;

    if( texture !== undefined ) {

        this.add( texture, size, distance, blending, color );

    }

};

THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype );


/*
 * Add: adds another flare
 */

THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) {

    if( size === undefined ) size = -1;
    if( distance === undefined ) distance = 0;
    if( opacity === undefined ) opacity = 1;
    if( color === undefined ) color = new THREE.Color( 0xffffff );
    if( blending === undefined ) blending = THREE.NormalBlending;

    distance = Math.min( distance, Math.max( 0, distance ) );

    this.lensFlares.push( { texture: texture,             // THREE.Texture
                            size: size,                 // size in pixels (-1 = use texture.width)
                            distance: distance,         // distance (0-1) from light source (0=at light source)
                            x: 0, y: 0, z: 0,            // screen position (-1 => 1) z = 0 is ontop z = 1 is back
                            scale: 1,                     // scale
                            rotation: 1,                 // rotation
                            opacity: opacity,            // opacity
                            color: color,                // color
                            blending: blending } );        // blending

};


/*
 * Update lens flares update positions on all flares based on the screen position
 * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.
 */

THREE.LensFlare.prototype.updateLensFlares = function () {

    var f, fl = this.lensFlares.length;
    var flare;
    var vecX = -this.positionScreen.x * 2;
    var vecY = -this.positionScreen.y * 2;

    for( f = 0; f < fl; f ++ ) {

        flare = this.lensFlares[ f ];

        flare.x = this.positionScreen.x + vecX * flare.distance;
        flare.y = this.positionScreen.y + vecY * flare.distance;

        flare.wantedRotation = flare.x * Math.PI * 0.25;
        flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;

    }

};












/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.MorphBlendMesh = function( geometry, material ) {

    THREE.Mesh.call( this, geometry, material );

    this.animationsMap = {};
    this.animationsList = [];

    // prepare default animation
    // (all frames played together in 1 second)

    var numFrames = this.geometry.morphTargets.length;

    var name = "__default";

    var startFrame = 0;
    var endFrame = numFrames - 1;

    var fps = numFrames / 1;

    this.createAnimation( name, startFrame, endFrame, fps );
    this.setAnimationWeight( name, 1 );

};

THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype );

THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) {

    var animation = {

        startFrame: start,
        endFrame: end,

        length: end - start + 1,

        fps: fps,
        duration: ( end - start ) / fps,

        lastFrame: 0,
        currentFrame: 0,

        active: false,

        time: 0,
        direction: 1,
        weight: 1,

        directionBackwards: false,
        mirroredLoop: false

    };

    this.animationsMap[ name ] = animation;
    this.animationsList.push( animation );

};

THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) {

    var pattern = /([a-z]+)(\d+)/;

    var firstAnimation, frameRanges = {};

    var geometry = this.geometry;

    for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {

        var morph = geometry.morphTargets[ i ];
        var chunks = morph.name.match( pattern );

        if ( chunks && chunks.length > 1 ) {

            var name = chunks[ 1 ];
            var num = chunks[ 2 ];

            if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity };

            var range = frameRanges[ name ];

            if ( i < range.start ) range.start = i;
            if ( i > range.end ) range.end = i;

            if ( ! firstAnimation ) firstAnimation = name;

        }

    }

    for ( var name in frameRanges ) {

        var range = frameRanges[ name ];
        this.createAnimation( name, range.start, range.end, fps );

    }

    this.firstAnimation = firstAnimation;

};

THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.direction = 1;
        animation.directionBackwards = false;

    }

};

THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.direction = -1;
        animation.directionBackwards = true;

    }

};

THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.fps = fps;
        animation.duration = ( animation.end - animation.start ) / animation.fps;

    }

};

THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.duration = duration;
        animation.fps = ( animation.end - animation.start ) / animation.duration;

    }

};

THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.weight = weight;

    }

};

THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.time = time;

    }

};

THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) {

    var time = 0;

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        time = animation.time;

    }

    return time;

};

THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) {

    var duration = -1;

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        duration = animation.duration;

    }

    return duration;

};

THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.time = 0;
        animation.active = true;

    } else {

        console.warn( "animation[" + name + "] undefined" );

    }

};

THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) {

    var animation = this.animationsMap[ name ];

    if ( animation ) {

        animation.active = false;

    }

};

THREE.MorphBlendMesh.prototype.update = function ( delta ) {

    for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {

        var animation = this.animationsList[ i ];

        if ( ! animation.active ) continue;

        var frameTime = animation.duration / animation.length;

        animation.time += animation.direction * delta;

        if ( animation.mirroredLoop ) {

            if ( animation.time > animation.duration || animation.time < 0 ) {

                animation.direction *= -1;

                if ( animation.time > animation.duration ) {

                    animation.time = animation.duration;
                    animation.directionBackwards = true;

                }

                if ( animation.time < 0 ) {

                    animation.time = 0;
                    animation.directionBackwards = false;

                }

            }

        } else {

            animation.time = animation.time % animation.duration;

            if ( animation.time < 0 ) animation.time += animation.duration;

        }

        var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
        var weight = animation.weight;

        if ( keyframe !== animation.currentFrame ) {

            this.morphTargetInfluences[ animation.lastFrame ] = 0;
            this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight;

            this.morphTargetInfluences[ keyframe ] = 0;

            animation.lastFrame = animation.currentFrame;
            animation.currentFrame = keyframe;

        }

        var mix = ( animation.time % frameTime ) / frameTime;

        if ( animation.directionBackwards ) mix = 1 - mix;

        this.morphTargetInfluences[ animation.currentFrame ] = mix * weight;
        this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;

    }

};
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.LensFlarePlugin = function ( ) {

    var _gl, _renderer, _lensFlare = {};

    this.init = function ( renderer ) {

        _gl = renderer.context;
        _renderer = renderer;

        _lensFlare.vertices = new Float32Array( 8 + 8 );
        _lensFlare.faces = new Uint16Array( 6 );

        var i = 0;
        _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1;    // vertex
        _lensFlare.vertices[ i++ ] = 0;  _lensFlare.vertices[ i++ ] = 0;    // uv... etc.

        _lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = -1;
        _lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 0;

        _lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 1;
        _lensFlare.vertices[ i++ ] = 1;  _lensFlare.vertices[ i++ ] = 1;

        _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1;
        _lensFlare.vertices[ i++ ] = 0;  _lensFlare.vertices[ i++ ] = 1;

        i = 0;
        _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2;
        _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3;

        // buffers

        _lensFlare.vertexBuffer     = _gl.createBuffer();
        _lensFlare.elementBuffer    = _gl.createBuffer();

        _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
        _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW );

        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
        _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW );

        // textures

        _lensFlare.tempTexture      = _gl.createTexture();
        _lensFlare.occlusionTexture = _gl.createTexture();

        _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
        _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );

        _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
        _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );

        if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) {

            _lensFlare.hasVertexTexture = false;
            _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ] );

        } else {

            _lensFlare.hasVertexTexture = true;
            _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ] );

        }

        _lensFlare.attributes = {};
        _lensFlare.uniforms = {};

        _lensFlare.attributes.vertex       = _gl.getAttribLocation ( _lensFlare.program, "position" );
        _lensFlare.attributes.uv           = _gl.getAttribLocation ( _lensFlare.program, "uv" );

        _lensFlare.uniforms.renderType     = _gl.getUniformLocation( _lensFlare.program, "renderType" );
        _lensFlare.uniforms.map            = _gl.getUniformLocation( _lensFlare.program, "map" );
        _lensFlare.uniforms.occlusionMap   = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" );
        _lensFlare.uniforms.opacity        = _gl.getUniformLocation( _lensFlare.program, "opacity" );
        _lensFlare.uniforms.color          = _gl.getUniformLocation( _lensFlare.program, "color" );
        _lensFlare.uniforms.scale          = _gl.getUniformLocation( _lensFlare.program, "scale" );
        _lensFlare.uniforms.rotation       = _gl.getUniformLocation( _lensFlare.program, "rotation" );
        _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" );

        _lensFlare.attributesEnabled = false;

    };


    /*
     * Render lens flares
     * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
     *         reads these back and calculates occlusion.
     *         Then _lensFlare.update_lensFlares() is called to re-position and
     *         update transparency of flares. Then they are rendered.
     *
     */

    this.render = function ( scene, camera, viewportWidth, viewportHeight ) {

        var flares = scene.__webglFlares,
            nFlares = flares.length;

        if ( ! nFlares ) return;

        var tempPosition = new THREE.Vector3();

        var invAspect = viewportHeight / viewportWidth,
            halfViewportWidth = viewportWidth * 0.5,
            halfViewportHeight = viewportHeight * 0.5;

        var size = 16 / viewportHeight,
            scale = new THREE.Vector2( size * invAspect, size );

        var screenPosition = new THREE.Vector3( 1, 1, 0 ),
            screenPositionPixels = new THREE.Vector2( 1, 1 );

        var uniforms = _lensFlare.uniforms,
            attributes = _lensFlare.attributes;

        // set _lensFlare program and reset blending

        _gl.useProgram( _lensFlare.program );

        if ( ! _lensFlare.attributesEnabled ) {

            _gl.enableVertexAttribArray( _lensFlare.attributes.vertex );
            _gl.enableVertexAttribArray( _lensFlare.attributes.uv );

            _lensFlare.attributesEnabled = true;

        }

        // loop through all lens flares to update their occlusion and positions
        // setup gl and common used attribs/unforms

        _gl.uniform1i( uniforms.occlusionMap, 0 );
        _gl.uniform1i( uniforms.map, 1 );

        _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
        _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 );
        _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );

        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );

        _gl.disable( _gl.CULL_FACE );
        _gl.depthMask( false );

        var i, j, jl, flare, sprite;

        for ( i = 0; i < nFlares; i ++ ) {

            size = 16 / viewportHeight;
            scale.set( size * invAspect, size );

            // calc object screen position

            flare = flares[ i ];

            tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );

            camera.matrixWorldInverse.multiplyVector3( tempPosition );
            camera.projectionMatrix.multiplyVector3( tempPosition );

            // setup arrays for gl programs

            screenPosition.copy( tempPosition )

            screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth;
            screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight;

            // screen cull

            if ( _lensFlare.hasVertexTexture || (
                screenPositionPixels.x > 0 &&
                screenPositionPixels.x < viewportWidth &&
                screenPositionPixels.y > 0 &&
                screenPositionPixels.y < viewportHeight ) ) {

                // save current RGB to temp texture

                _gl.activeTexture( _gl.TEXTURE1 );
                _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
                _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );


                // render pink quad

                _gl.uniform1i( uniforms.renderType, 0 );
                _gl.uniform2f( uniforms.scale, scale.x, scale.y );
                _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );

                _gl.disable( _gl.BLEND );
                _gl.enable( _gl.DEPTH_TEST );

                _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );


                // copy result to occlusionMap

                _gl.activeTexture( _gl.TEXTURE0 );
                _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
                _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );


                // restore graphics

                _gl.uniform1i( uniforms.renderType, 1 );
                _gl.disable( _gl.DEPTH_TEST );

                _gl.activeTexture( _gl.TEXTURE1 );
                _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
                _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );


                // update object positions

                flare.positionScreen.copy( screenPosition )

                if ( flare.customUpdateCallback ) {

                    flare.customUpdateCallback( flare );

                } else {

                    flare.updateLensFlares();

                }

                // render flares

                _gl.uniform1i( uniforms.renderType, 2 );
                _gl.enable( _gl.BLEND );

                for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {

                    sprite = flare.lensFlares[ j ];

                    if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {

                        screenPosition.x = sprite.x;
                        screenPosition.y = sprite.y;
                        screenPosition.z = sprite.z;

                        size = sprite.size * sprite.scale / viewportHeight;

                        scale.x = size * invAspect;
                        scale.y = size;

                        _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
                        _gl.uniform2f( uniforms.scale, scale.x, scale.y );
                        _gl.uniform1f( uniforms.rotation, sprite.rotation );

                        _gl.uniform1f( uniforms.opacity, sprite.opacity );
                        _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );

                        _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
                        _renderer.setTexture( sprite.texture, 1 );

                        _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );

                    }

                }

            }

        }

        // restore gl

        _gl.enable( _gl.CULL_FACE );
        _gl.enable( _gl.DEPTH_TEST );
        _gl.depthMask( true );

    };

    function createProgram ( shader ) {

        var program = _gl.createProgram();

        var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
        var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );

        _gl.shaderSource( fragmentShader, shader.fragmentShader );
        _gl.shaderSource( vertexShader, shader.vertexShader );

        _gl.compileShader( fragmentShader );
        _gl.compileShader( vertexShader );

        _gl.attachShader( program, fragmentShader );
        _gl.attachShader( program, vertexShader );

        _gl.linkProgram( program );

        return program;

    };

};/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.ShadowMapPlugin = function ( ) {

    var _gl,
    _renderer,
    _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,

    _frustum = new THREE.Frustum(),
    _projScreenMatrix = new THREE.Matrix4(),

    _min = new THREE.Vector3(),
    _max = new THREE.Vector3();

    this.init = function ( renderer ) {

        _gl = renderer.context;
        _renderer = renderer;

        var depthShader = THREE.ShaderLib[ "depthRGBA" ];
        var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );

        _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
        _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
        _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } );
        _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } );

        _depthMaterial._shadowPass = true;
        _depthMaterialMorph._shadowPass = true;
        _depthMaterialSkin._shadowPass = true;
        _depthMaterialMorphSkin._shadowPass = true;

    };

    this.render = function ( scene, camera ) {

        if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return;

        this.update( scene, camera );

    };

    this.update = function ( scene, camera ) {

        var i, il, j, jl, n,

        shadowMap, shadowMatrix, shadowCamera,
        program, buffer, material,
        webglObject, object, light,
        renderList,

        lights = [],
        k = 0,

        fog = null;

        // set GL state for depth map

        _gl.clearColor( 1, 1, 1, 1 );
        _gl.disable( _gl.BLEND );

        _gl.enable( _gl.CULL_FACE );
        _gl.frontFace( _gl.CCW );

        if ( _renderer.shadowMapCullFrontFaces ) {

            _gl.cullFace( _gl.FRONT );

        } else {

            _gl.cullFace( _gl.BACK );

        }

        _renderer.setDepthTest( true );

        // preprocess lights
        //     - skip lights that are not casting shadows
        //    - create virtual lights for cascaded shadow maps

        for ( i = 0, il = scene.__lights.length; i < il; i ++ ) {

            light = scene.__lights[ i ];

            if ( ! light.castShadow ) continue;

            if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) {

                for ( n = 0; n < light.shadowCascadeCount; n ++ ) {

                    var virtualLight;

                    if ( ! light.shadowCascadeArray[ n ] ) {

                        virtualLight = createVirtualLight( light, n );
                        virtualLight.originalCamera = camera;

                        var gyro = new THREE.Gyroscope();
                        gyro.position = light.shadowCascadeOffset;

                        gyro.add( virtualLight );
                        gyro.add( virtualLight.target );

                        camera.add( gyro );

                        light.shadowCascadeArray[ n ] = virtualLight;

                        console.log( "Created virtualLight", virtualLight );

                    } else {

                        virtualLight = light.shadowCascadeArray[ n ];

                    }

                    updateVirtualLight( light, n );

                    lights[ k ] = virtualLight;
                    k ++;

                }

            } else {

                lights[ k ] = light;
                k ++;

            }

        }

        // render depth map

        for ( i = 0, il = lights.length; i < il; i ++ ) {

            light = lights[ i ];

            if ( ! light.shadowMap ) {

                var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };

                light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
                light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );

                light.shadowMatrix = new THREE.Matrix4();

            }

            if ( ! light.shadowCamera ) {

                if ( light instanceof THREE.SpotLight ) {

                    light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );

                } else if ( light instanceof THREE.DirectionalLight ) {

                    light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );

                } else {

                    console.error( "Unsupported light type for shadow" );
                    continue;

                }

                scene.add( light.shadowCamera );

                if ( _renderer.autoUpdateScene ) scene.updateMatrixWorld();

            }

            if ( light.shadowCameraVisible && ! light.cameraHelper ) {

                light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
                light.shadowCamera.add( light.cameraHelper );

            }

            if ( light.isVirtual && virtualLight.originalCamera == camera ) {

                updateShadowCamera( camera, light );

            }

            shadowMap = light.shadowMap;
            shadowMatrix = light.shadowMatrix;
            shadowCamera = light.shadowCamera;

            shadowCamera.position.copy( light.matrixWorld.getPosition() );
            shadowCamera.lookAt( light.target.matrixWorld.getPosition() );
            shadowCamera.updateMatrixWorld();

            shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );

            if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;
            if ( light.shadowCameraVisible ) light.cameraHelper.update();

            // compute shadow matrix

            shadowMatrix.set( 0.5, 0.0, 0.0, 0.5,
                              0.0, 0.5, 0.0, 0.5,
                              0.0, 0.0, 0.5, 0.5,
                              0.0, 0.0, 0.0, 1.0 );

            shadowMatrix.multiplySelf( shadowCamera.projectionMatrix );
            shadowMatrix.multiplySelf( shadowCamera.matrixWorldInverse );

            // update camera matrices and frustum

            if ( ! shadowCamera._viewMatrixArray ) shadowCamera._viewMatrixArray = new Float32Array( 16 );
            if ( ! shadowCamera._projectionMatrixArray ) shadowCamera._projectionMatrixArray = new Float32Array( 16 );

            shadowCamera.matrixWorldInverse.flattenToArray( shadowCamera._viewMatrixArray );
            shadowCamera.projectionMatrix.flattenToArray( shadowCamera._projectionMatrixArray );

            _projScreenMatrix.multiply( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
            _frustum.setFromMatrix( _projScreenMatrix );

            // render shadow map

            _renderer.setRenderTarget( shadowMap );
            _renderer.clear();

            // set object matrices & frustum culling

            renderList = scene.__webglObjects;

            for ( j = 0, jl = renderList.length; j < jl; j ++ ) {

                webglObject = renderList[ j ];
                object = webglObject.object;

                webglObject.render = false;

                if ( object.visible && object.castShadow ) {

                    if ( ! ( object instanceof THREE.Mesh ) || ! ( object.frustumCulled ) || _frustum.contains( object ) ) {

                        object._modelViewMatrix.multiply( shadowCamera.matrixWorldInverse, object.matrixWorld );

                        webglObject.render = true;

                    }

                }

            }

            // render regular objects

            for ( j = 0, jl = renderList.length; j < jl; j ++ ) {

                webglObject = renderList[ j ];

                if ( webglObject.render ) {

                    object = webglObject.object;
                    buffer = webglObject.buffer;

                    // culling is overriden globally for all objects
                    // while rendering depth map

                    if ( object.customDepthMaterial ) {

                        material = object.customDepthMaterial;

                    } else if ( object instanceof THREE.SkinnedMesh ) {

                        material = object.geometry.morphTargets.length ? _depthMaterialMorphSkin : _depthMaterialSkin;

                    } else if ( object.geometry.morphTargets.length ) {

                        material = _depthMaterialMorph;

                    } else {

                        material = _depthMaterial;

                    }

                    if ( buffer instanceof THREE.BufferGeometry ) {

                        _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );

                    } else {

                        _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object );

                    }

                }

            }

            // set matrices and render immediate objects

            renderList = scene.__webglObjectsImmediate;

            for ( j = 0, jl = renderList.length; j < jl; j ++ ) {

                webglObject = renderList[ j ];
                object = webglObject.object;

                if ( object.visible && object.castShadow ) {

                    object._modelViewMatrix.multiply( shadowCamera.matrixWorldInverse, object.matrixWorld );

                    _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object );

                }

            }

        }

        // restore GL state

        var clearColor = _renderer.getClearColor(),
        clearAlpha = _renderer.getClearAlpha();

        _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
        _gl.enable( _gl.BLEND );

        if ( _renderer.shadowMapCullFrontFaces ) {

            _gl.cullFace( _gl.BACK );

        }

    };

    function createVirtualLight( light, cascade ) {

        var virtualLight = new THREE.DirectionalLight();

        virtualLight.isVirtual = true;

        virtualLight.onlyShadow = true;
        virtualLight.castShadow = true;

        virtualLight.shadowCameraNear = light.shadowCameraNear;
        virtualLight.shadowCameraFar = light.shadowCameraFar;

        virtualLight.shadowCameraLeft = light.shadowCameraLeft;
        virtualLight.shadowCameraRight = light.shadowCameraRight;
        virtualLight.shadowCameraBottom = light.shadowCameraBottom;
        virtualLight.shadowCameraTop = light.shadowCameraTop;

        virtualLight.shadowCameraVisible = light.shadowCameraVisible;

        virtualLight.shadowDarkness = light.shadowDarkness;

        virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
        virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ];
        virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ];

        virtualLight.pointsWorld = [];
        virtualLight.pointsFrustum = [];

        var pointsWorld = virtualLight.pointsWorld,
            pointsFrustum = virtualLight.pointsFrustum;

        for ( var i = 0; i < 8; i ++ ) {

            pointsWorld[ i ] = new THREE.Vector3();
            pointsFrustum[ i ] = new THREE.Vector3();

        }

        var nearZ = light.shadowCascadeNearZ[ cascade ];
        var farZ = light.shadowCascadeFarZ[ cascade ];

        pointsFrustum[ 0 ].set( -1, -1, nearZ );
        pointsFrustum[ 1 ].set(  1, -1, nearZ );
        pointsFrustum[ 2 ].set( -1,  1, nearZ );
        pointsFrustum[ 3 ].set(  1,  1, nearZ );

        pointsFrustum[ 4 ].set( -1, -1, farZ );
        pointsFrustum[ 5 ].set(  1, -1, farZ );
        pointsFrustum[ 6 ].set( -1,  1, farZ );
        pointsFrustum[ 7 ].set(  1,  1, farZ );

        return virtualLight;

    }

    // Synchronize virtual light with the original light

    function updateVirtualLight( light, cascade ) {

        var virtualLight = light.shadowCascadeArray[ cascade ];

        virtualLight.position.copy( light.position );
        virtualLight.target.position.copy( light.target.position );
        virtualLight.lookAt( virtualLight.target );

        virtualLight.shadowCameraVisible = light.shadowCameraVisible;
        virtualLight.shadowDarkness = light.shadowDarkness;

        virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];

        var nearZ = light.shadowCascadeNearZ[ cascade ];
        var farZ = light.shadowCascadeFarZ[ cascade ];

        var pointsFrustum = virtualLight.pointsFrustum;

        pointsFrustum[ 0 ].z = nearZ;
        pointsFrustum[ 1 ].z = nearZ;
        pointsFrustum[ 2 ].z = nearZ;
        pointsFrustum[ 3 ].z = nearZ;

        pointsFrustum[ 4 ].z = farZ;
        pointsFrustum[ 5 ].z = farZ;
        pointsFrustum[ 6 ].z = farZ;
        pointsFrustum[ 7 ].z = farZ;

    }

    // Fit shadow camera's ortho frustum to camera frustum

    function updateShadowCamera( camera, light ) {

        var shadowCamera = light.shadowCamera,
            pointsFrustum = light.pointsFrustum,
            pointsWorld = light.pointsWorld;

        _min.set( Infinity, Infinity, Infinity );
        _max.set( -Infinity, -Infinity, -Infinity );

        for ( var i = 0; i < 8; i ++ ) {

            var p = pointsWorld[ i ];

            p.copy( pointsFrustum[ i ] );
            THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera );

            shadowCamera.matrixWorldInverse.multiplyVector3( p );

            if ( p.x < _min.x ) _min.x = p.x;
            if ( p.x > _max.x ) _max.x = p.x;

            if ( p.y < _min.y ) _min.y = p.y;
            if ( p.y > _max.y ) _max.y = p.y;

            if ( p.z < _min.z ) _min.z = p.z;
            if ( p.z > _max.z ) _max.z = p.z;

        }

        shadowCamera.left = _min.x;
        shadowCamera.right = _max.x;
        shadowCamera.top = _max.y;
        shadowCamera.bottom = _min.y;

        // can't really fit near/far
        //shadowCamera.near = _min.z;
        //shadowCamera.far = _max.z;

        shadowCamera.updateProjectionMatrix();

    }

};

THREE.ShadowMapPlugin.__projector = new THREE.Projector();
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.SpritePlugin = function ( ) {

    var _gl, _renderer, _sprite = {};

    this.init = function ( renderer ) {

        _gl = renderer.context;
        _renderer = renderer;

        _sprite.vertices = new Float32Array( 8 + 8 );
        _sprite.faces    = new Uint16Array( 6 );

        var i = 0;

        _sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = -1;    // vertex 0
        _sprite.vertices[ i++ ] = 0;  _sprite.vertices[ i++ ] = 0;    // uv 0

        _sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = -1;    // vertex 1
        _sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 0;    // uv 1

        _sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 1;    // vertex 2
        _sprite.vertices[ i++ ] = 1;  _sprite.vertices[ i++ ] = 1;    // uv 2

        _sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = 1;    // vertex 3
        _sprite.vertices[ i++ ] = 0;  _sprite.vertices[ i++ ] = 1;    // uv 3

        i = 0;

        _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2;
        _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3;

        _sprite.vertexBuffer  = _gl.createBuffer();
        _sprite.elementBuffer = _gl.createBuffer();

        _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
        _gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW );

        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
        _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW );

        _sprite.program = createProgram( THREE.ShaderSprite[ "sprite" ] );

        _sprite.attributes = {};
        _sprite.uniforms = {};

        _sprite.attributes.position           = _gl.getAttribLocation ( _sprite.program, "position" );
        _sprite.attributes.uv                 = _gl.getAttribLocation ( _sprite.program, "uv" );

        _sprite.uniforms.uvOffset             = _gl.getUniformLocation( _sprite.program, "uvOffset" );
        _sprite.uniforms.uvScale              = _gl.getUniformLocation( _sprite.program, "uvScale" );

        _sprite.uniforms.rotation             = _gl.getUniformLocation( _sprite.program, "rotation" );
        _sprite.uniforms.scale                = _gl.getUniformLocation( _sprite.program, "scale" );
        _sprite.uniforms.alignment            = _gl.getUniformLocation( _sprite.program, "alignment" );

        _sprite.uniforms.color                = _gl.getUniformLocation( _sprite.program, "color" );
        _sprite.uniforms.map                  = _gl.getUniformLocation( _sprite.program, "map" );
        _sprite.uniforms.opacity              = _gl.getUniformLocation( _sprite.program, "opacity" );

        _sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" );
        _sprite.uniforms.affectedByDistance   = _gl.getUniformLocation( _sprite.program, "affectedByDistance" );
        _sprite.uniforms.screenPosition          = _gl.getUniformLocation( _sprite.program, "screenPosition" );
        _sprite.uniforms.modelViewMatrix      = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" );
        _sprite.uniforms.projectionMatrix     = _gl.getUniformLocation( _sprite.program, "projectionMatrix" );

        _sprite.attributesEnabled = false;

    };

    this.render = function ( scene, camera, viewportWidth, viewportHeight ) {

        var sprites = scene.__webglSprites,
            nSprites = sprites.length;

        if ( ! nSprites ) return;

        var attributes = _sprite.attributes,
            uniforms = _sprite.uniforms;

        var invAspect = viewportHeight / viewportWidth;

        var halfViewportWidth = viewportWidth * 0.5,
            halfViewportHeight = viewportHeight * 0.5;

        var mergeWith3D = true;

        // setup gl

        _gl.useProgram( _sprite.program );

        if ( ! _sprite.attributesEnabled ) {

            _gl.enableVertexAttribArray( attributes.position );
            _gl.enableVertexAttribArray( attributes.uv );

            _sprite.attributesEnabled = true;

        }

        _gl.disable( _gl.CULL_FACE );
        _gl.enable( _gl.BLEND );
        _gl.depthMask( true );

        _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
        _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 );
        _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );

        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );

        _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera._projectionMatrixArray );

        _gl.activeTexture( _gl.TEXTURE0 );
        _gl.uniform1i( uniforms.map, 0 );

        // update positions and sort

        var i, sprite, screenPosition, size, scale = [];

        for( i = 0; i < nSprites; i ++ ) {

            sprite = sprites[ i ];

            if ( ! sprite.visible || sprite.opacity === 0 ) continue;

            if( ! sprite.useScreenCoordinates ) {

                sprite._modelViewMatrix.multiply( camera.matrixWorldInverse, sprite.matrixWorld );
                sprite.z = - sprite._modelViewMatrix.elements[14];

            } else {

                sprite.z = - sprite.position.z;

            }

        }

        sprites.sort( painterSort );

        // render all sprites

        for( i = 0; i < nSprites; i ++ ) {

            sprite = sprites[ i ];

            if ( ! sprite.visible || sprite.opacity === 0 ) continue;

            if ( sprite.map && sprite.map.image && sprite.map.image.width ) {

                if ( sprite.useScreenCoordinates ) {

                    _gl.uniform1i( uniforms.useScreenCoordinates, 1 );
                    _gl.uniform3f( uniforms.screenPosition, ( sprite.position.x - halfViewportWidth  ) / halfViewportWidth,
                                                            ( halfViewportHeight - sprite.position.y ) / halfViewportHeight,
                                                              Math.max( 0, Math.min( 1, sprite.position.z ) ) );

                } else {

                    _gl.uniform1i( uniforms.useScreenCoordinates, 0 );
                    _gl.uniform1i( uniforms.affectedByDistance, sprite.affectedByDistance ? 1 : 0 );
                    _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );

                }

                size = sprite.map.image.width / ( sprite.scaleByViewport ? viewportHeight : 1 );

                scale[ 0 ] = size * invAspect * sprite.scale.x;
                scale[ 1 ] = size * sprite.scale.y;

                _gl.uniform2f( uniforms.uvScale, sprite.uvScale.x, sprite.uvScale.y );
                _gl.uniform2f( uniforms.uvOffset, sprite.uvOffset.x, sprite.uvOffset.y );
                _gl.uniform2f( uniforms.alignment, sprite.alignment.x, sprite.alignment.y );

                _gl.uniform1f( uniforms.opacity, sprite.opacity );
                _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );

                _gl.uniform1f( uniforms.rotation, sprite.rotation );
                _gl.uniform2fv( uniforms.scale, scale );

                if ( sprite.mergeWith3D && !mergeWith3D ) {

                    _gl.enable( _gl.DEPTH_TEST );
                    mergeWith3D = true;

                } else if ( ! sprite.mergeWith3D && mergeWith3D ) {

                    _gl.disable( _gl.DEPTH_TEST );
                    mergeWith3D = false;

                }

                _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
                _renderer.setTexture( sprite.map, 0 );

                _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );

            }

        }

        // restore gl

        _gl.enable( _gl.CULL_FACE );
        _gl.enable( _gl.DEPTH_TEST );
        _gl.depthMask( true );

    };

    function createProgram ( shader ) {

        var program = _gl.createProgram();

        var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
        var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );

        _gl.shaderSource( fragmentShader, shader.fragmentShader );
        _gl.shaderSource( vertexShader, shader.vertexShader );

        _gl.compileShader( fragmentShader );
        _gl.compileShader( vertexShader );

        _gl.attachShader( program, fragmentShader );
        _gl.attachShader( program, vertexShader );

        _gl.linkProgram( program );

        return program;

    };

    function painterSort ( a, b ) {

        return b.z - a.z;

    };

};/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.DepthPassPlugin = function ( ) {

    this.enabled = false;
    this.renderTarget = null;

    var _gl,
    _renderer,
    _depthMaterial, _depthMaterialMorph,

    _frustum = new THREE.Frustum(),
    _projScreenMatrix = new THREE.Matrix4();

    this.init = function ( renderer ) {

        _gl = renderer.context;
        _renderer = renderer;

        var depthShader = THREE.ShaderLib[ "depthRGBA" ];
        var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );

        _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
        _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );

        _depthMaterial._shadowPass = true;
        _depthMaterialMorph._shadowPass = true;

    };

    this.render = function ( scene, camera ) {

        if ( ! this.enabled ) return;

        this.update( scene, camera );

    };

    this.update = function ( scene, camera ) {

        var i, il, j, jl, n,

        program, buffer, material,
        webglObject, object, light,
        renderList,

        fog = null;

        // set GL state for depth map

        _gl.clearColor( 1, 1, 1, 1 );
        _gl.disable( _gl.BLEND );

        _renderer.setDepthTest( true );

        // update scene

        if ( _renderer.autoUpdateScene ) scene.updateMatrixWorld();

        // update camera matrices and frustum

        if ( ! camera._viewMatrixArray ) camera._viewMatrixArray = new Float32Array( 16 );
        if ( ! camera._projectionMatrixArray ) camera._projectionMatrixArray = new Float32Array( 16 );

        camera.matrixWorldInverse.getInverse( camera.matrixWorld );

        camera.matrixWorldInverse.flattenToArray( camera._viewMatrixArray );
        camera.projectionMatrix.flattenToArray( camera._projectionMatrixArray );

        _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
        _frustum.setFromMatrix( _projScreenMatrix );

        // render depth map

        _renderer.setRenderTarget( this.renderTarget );
        _renderer.clear();

        // set object matrices & frustum culling

        renderList = scene.__webglObjects;

        for ( j = 0, jl = renderList.length; j < jl; j ++ ) {

            webglObject = renderList[ j ];
            object = webglObject.object;

            webglObject.render = false;

            if ( object.visible ) {

                if ( ! ( object instanceof THREE.Mesh ) || ! ( object.frustumCulled ) || _frustum.contains( object ) ) {

                    //object.matrixWorld.flattenToArray( object._modelMatrixArray );
                    object._modelViewMatrix.multiply( camera.matrixWorldInverse, object.matrixWorld);

                    webglObject.render = true;

                }

            }

        }

        // render regular objects

        for ( j = 0, jl = renderList.length; j < jl; j ++ ) {

            webglObject = renderList[ j ];

            if ( webglObject.render ) {

                object = webglObject.object;
                buffer = webglObject.buffer;

                if ( object.material ) _renderer.setMaterialFaces( object.material );

                if ( object.customDepthMaterial ) {

                    material = object.customDepthMaterial;

                } else if ( object.geometry.morphTargets.length ) {

                    material = _depthMaterialMorph;

                } else {

                    material = _depthMaterial;

                }

                if ( buffer instanceof THREE.BufferGeometry ) {

                    _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object );

                } else {

                    _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object );

                }

            }

        }

        // set matrices and render immediate objects

        renderList = scene.__webglObjectsImmediate;

        for ( j = 0, jl = renderList.length; j < jl; j ++ ) {

            webglObject = renderList[ j ];
            object = webglObject.object;

            if ( object.visible && object.castShadow ) {

                /*
                if ( object.matrixAutoUpdate ) {

                    object.matrixWorld.flattenToArray( object._modelMatrixArray );

                }
                */

                object._modelViewMatrix.multiply( camera.matrixWorldInverse, object.matrixWorld);

                _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object );

            }

        }

        // restore GL state

        var clearColor = _renderer.getClearColor(),
        clearAlpha = _renderer.getClearAlpha();

        _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
        _gl.enable( _gl.BLEND );

    };

};

/**
 * @author mikael emtinger / http://gomo.se/
 *
 */

THREE.ShaderFlares = {

    'lensFlareVertexTexture': {

        vertexShader: [

            "uniform vec3 screenPosition;",
            "uniform vec2 scale;",
            "uniform float rotation;",
            "uniform int renderType;",

            "uniform sampler2D occlusionMap;",

            "attribute vec2 position;",
            "attribute vec2 uv;",

            "varying vec2 vUV;",
            "varying float vVisibility;",

            "void main() {",

                "vUV = uv;",

                "vec2 pos = position;",

                "if( renderType == 2 ) {",

                    "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.5, 0.1 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.9, 0.1 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.9, 0.5 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.9, 0.9 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.5, 0.9 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.1, 0.9 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.1, 0.5 ) ) +",
                                      "texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",

                    "vVisibility = (       visibility.r / 9.0 ) *",
                                  "( 1.0 - visibility.g / 9.0 ) *",
                                  "(       visibility.b / 9.0 ) *",
                                  "( 1.0 - visibility.a / 9.0 );",

                    "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
                    "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",

                "}",

                "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",

            "}"

        ].join( "\n" ),

        fragmentShader: [

            "precision mediump float;",

            "uniform sampler2D map;",
            "uniform float opacity;",
            "uniform int renderType;",
            "uniform vec3 color;",

            "varying vec2 vUV;",
            "varying float vVisibility;",

            "void main() {",

                // pink square

                "if( renderType == 0 ) {",

                    "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );",

                // restore

                "} else if( renderType == 1 ) {",

                    "gl_FragColor = texture2D( map, vUV );",

                // flare

                "} else {",

                    "vec4 texture = texture2D( map, vUV );",
                    "texture.a *= opacity * vVisibility;",
                    "gl_FragColor = texture;",
                    "gl_FragColor.rgb *= color;",

                "}",

            "}"
        ].join( "\n" )

    },


    'lensFlare': {

        vertexShader: [

            "uniform vec3 screenPosition;",
            "uniform vec2 scale;",
            "uniform float rotation;",
            "uniform int renderType;",

            "attribute vec2 position;",
            "attribute vec2 uv;",

            "varying vec2 vUV;",

            "void main() {",

                "vUV = uv;",

                "vec2 pos = position;",

                "if( renderType == 2 ) {",

                    "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
                    "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",

                "}",

                "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",

            "}"

        ].join( "\n" ),

        fragmentShader: [

            "precision mediump float;",

            "uniform sampler2D map;",
            "uniform sampler2D occlusionMap;",
            "uniform float opacity;",
            "uniform int renderType;",
            "uniform vec3 color;",

            "varying vec2 vUV;",

            "void main() {",

                // pink square

                "if( renderType == 0 ) {",

                    "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );",

                // restore

                "} else if( renderType == 1 ) {",

                    "gl_FragColor = texture2D( map, vUV );",

                // flare

                "} else {",

                    "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a +",
                                       "texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a +",
                                       "texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a +",
                                       "texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;",

                    "visibility = ( 1.0 - visibility / 4.0 );",

                    "vec4 texture = texture2D( map, vUV );",
                    "texture.a *= opacity * visibility;",
                    "gl_FragColor = texture;",
                    "gl_FragColor.rgb *= color;",

                "}",

            "}"

        ].join( "\n" )

    }

};
/**
 * @author mikael emtinger / http://gomo.se/
 *
 */

THREE.ShaderSprite = {

    'sprite': {

        vertexShader: [

            "uniform int useScreenCoordinates;",
            "uniform int affectedByDistance;",
            "uniform vec3 screenPosition;",
            "uniform mat4 modelViewMatrix;",
            "uniform mat4 projectionMatrix;",
            "uniform float rotation;",
            "uniform vec2 scale;",
            "uniform vec2 alignment;",
            "uniform vec2 uvOffset;",
            "uniform vec2 uvScale;",

            "attribute vec2 position;",
            "attribute vec2 uv;",

            "varying vec2 vUV;",

            "void main() {",

                "vUV = uvOffset + uv * uvScale;",

                "vec2 alignedPosition = position + alignment;",

                "vec2 rotatedPosition;",
                "rotatedPosition.x = ( cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y ) * scale.x;",
                "rotatedPosition.y = ( sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y ) * scale.y;",

                "vec4 finalPosition;",

                "if( useScreenCoordinates != 0 ) {",

                    "finalPosition = vec4( screenPosition.xy + rotatedPosition, screenPosition.z, 1.0 );",

                "} else {",

                    "finalPosition = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );",
                    "finalPosition.xy += rotatedPosition * ( affectedByDistance == 1 ? 1.0 : finalPosition.z );",

                "}",

                "gl_Position = finalPosition;",

            "}"

        ].join( "\n" ),

        fragmentShader: [

            "precision mediump float;",

            "uniform vec3 color;",
            "uniform sampler2D map;",
            "uniform float opacity;",

            "varying vec2 vUV;",

            "void main() {",

                "vec4 texture = texture2D( map, vUV );",
                "gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );",

            "}"

        ].join( "\n" )

    }

};
/**
 * @author alteredq / http://alteredqualia.com/
 *
 */


THREE.ShaderSkin = {

    /* ------------------------------------------------------------------------------------------
    //    Simple skin shader
    //        - per-pixel Blinn-Phong diffuse term mixed with half-Lambert wrap-around term (per color component)
    //        - physically based specular term (Kelemen/Szirmay-Kalos specular reflectance)
    //
    //        - diffuse map
    //        - bump map
    //        - specular map
    //        - point, directional and hemisphere lights (use with "lights: true" material option)
    //        - fog (use with "fog: true" material option)
    //        - shadow maps
    //
    // ------------------------------------------------------------------------------------------ */

    'skinSimple' : {

        uniforms: THREE.UniformsUtils.merge( [

            THREE.UniformsLib[ "fog" ],
            THREE.UniformsLib[ "lights" ],
            THREE.UniformsLib[ "shadowmap" ],

            {

            "enableBump"    : { type: "i", value: 0 },
            "enableSpecular": { type: "i", value: 0 },

            "tDiffuse"    : { type: "t", value: null },
            "tBeckmann"    : { type: "t", value: null },

            "uDiffuseColor":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
            "uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
            "uAmbientColor":  { type: "c", value: new THREE.Color( 0x050505 ) },
            "uOpacity":       { type: "f", value: 1 },

            "uRoughness":               { type: "f", value: 0.15 },
            "uSpecularBrightness":     { type: "f", value: 0.75 },

            "bumpMap"    : { type: "t", value: null },
            "bumpScale" : { type: "f", value: 1 },

            "specularMap" : { type: "t", value: null },

            "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },

            "uWrapRGB":    { type: "v3", value: new THREE.Vector3( 0.75, 0.375, 0.1875 ) }

            }

        ] ),

        fragmentShader: [

            "#define USE_BUMPMAP",
            "#extension GL_OES_standard_derivatives : enable",

            "uniform bool enableBump;",
            "uniform bool enableSpecular;",

            "uniform vec3 uAmbientColor;",
            "uniform vec3 uDiffuseColor;",
            "uniform vec3 uSpecularColor;",
            "uniform float uOpacity;",

            "uniform float uRoughness;",
            "uniform float uSpecularBrightness;",

            "uniform vec3 uWrapRGB;",

            "uniform sampler2D tDiffuse;",
            "uniform sampler2D tBeckmann;",

            "uniform sampler2D specularMap;",

            "varying vec3 vNormal;",
            "varying vec2 vUv;",

            "uniform vec3 ambientLightColor;",

            "#if MAX_DIR_LIGHTS > 0",

                "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
                "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",

            "#endif",

            "#if MAX_HEMI_LIGHTS > 0",

                "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
                "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
                "uniform vec3 hemisphereLightPosition[ MAX_HEMI_LIGHTS ];",

            "#endif",

            "#if MAX_POINT_LIGHTS > 0",

                "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
                "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
                "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

            "#endif",

            "varying vec3 vViewPosition;",

            THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
            THREE.ShaderChunk[ "fog_pars_fragment" ],
            THREE.ShaderChunk[ "bumpmap_pars_fragment" ],

            // Fresnel term

            "float fresnelReflectance( vec3 H, vec3 V, float F0 ) {",

                "float base = 1.0 - dot( V, H );",
                "float exponential = pow( base, 5.0 );",

                "return exponential + F0 * ( 1.0 - exponential );",

            "}",

            // Kelemen/Szirmay-Kalos specular BRDF

            "float KS_Skin_Specular( vec3 N,",         // Bumped surface normal
                                    "vec3 L,",         // Points to light
                                    "vec3 V,",         // Points to eye
                                    "float m,",      // Roughness
                                    "float rho_s",     // Specular brightness
                                    ") {",

                "float result = 0.0;",
                "float ndotl = dot( N, L );",

                "if( ndotl > 0.0 ) {",

                    "vec3 h = L + V;", // Unnormalized half-way vector
                    "vec3 H = normalize( h );",

                    "float ndoth = dot( N, H );",

                    "float PH = pow( 2.0 * texture2D( tBeckmann, vec2( ndoth, m ) ).x, 10.0 );",

                    "float F = fresnelReflectance( H, V, 0.028 );",
                    "float frSpec = max( PH * F / dot( h, h ), 0.0 );",

                    "result = ndotl * rho_s * frSpec;", // BRDF * dot(N,L) * rho_s

                "}",

                "return result;",

            "}",

            "void main() {",

                "gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",

                "vec4 colDiffuse = texture2D( tDiffuse, vUv );",
                "colDiffuse.rgb *= colDiffuse.rgb;",

                "gl_FragColor = gl_FragColor * colDiffuse;",

                "vec3 normal = normalize( vNormal );",
                "vec3 viewPosition = normalize( vViewPosition );",

                "float specularStrength;",

                "if ( enableSpecular ) {",

                    "vec4 texelSpecular = texture2D( specularMap, vUv );",
                    "specularStrength = texelSpecular.r;",

                "} else {",

                    "specularStrength = 1.0;",

                "}",

                "#ifdef USE_BUMPMAP",

                    "if ( enableBump ) normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",

                "#endif",

                // point lights

                "vec3 specularTotal = vec3( 0.0 );",

                "#if MAX_POINT_LIGHTS > 0",

                    "vec3 pointTotal = vec3( 0.0 );",

                    "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",

                        "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",

                        "vec3 lVector = lPosition.xyz + vViewPosition.xyz;",

                        "float lDistance = 1.0;",

                        "if ( pointLightDistance[ i ] > 0.0 )",
                            "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",

                        "lVector = normalize( lVector );",

                        "float pointDiffuseWeightFull = max( dot( normal, lVector ), 0.0 );",
                        "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, lVector ) + 0.5, 0.0 );",
                        "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), uWrapRGB );",

                        "float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",

                        "pointTotal    += lDistance * uDiffuseColor * pointLightColor[ i ] * pointDiffuseWeight;",
                        "specularTotal += lDistance * uSpecularColor * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",

                    "}",

                "#endif",

                // directional lights

                "#if MAX_DIR_LIGHTS > 0",

                    "vec3 dirTotal = vec3( 0.0 );",

                    "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",

                        "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",

                        "vec3 dirVector = normalize( lDirection.xyz );",

                        "float dirDiffuseWeightFull = max( dot( normal, dirVector ), 0.0 );",
                        "float dirDiffuseWeightHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
                        "vec3 dirDiffuseWeight = mix( vec3 ( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), uWrapRGB );",

                        "float dirSpecularWeight =  KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",

                        "dirTotal        += uDiffuseColor * directionalLightColor[ i ] * dirDiffuseWeight;",
                        "specularTotal += uSpecularColor * directionalLightColor[ i ] * dirSpecularWeight * specularStrength;",

                    "}",

                "#endif",

                // hemisphere lights

                "#if MAX_HEMI_LIGHTS > 0",

                    "vec3 hemiTotal = vec3( 0.0 );",

                    "for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",

                        "vec4 lPosition = viewMatrix * vec4( hemisphereLightPosition[ i ], 1.0 );",
                        "vec3 lVector = normalize( lPosition.xyz + vViewPosition.xyz );",

                        "float dotProduct = dot( normal, lVector );",
                        "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",

                        "hemiTotal += uDiffuseColor * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",

                        // specular (sky light)

                        "float hemiSpecularWeight = 0.0;",
                        "hemiSpecularWeight += KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",

                        // specular (ground light)

                        "vec3 lVectorGround = normalize( -lPosition.xyz + vViewPosition.xyz );",
                        "hemiSpecularWeight += KS_Skin_Specular( normal, lVectorGround, viewPosition, uRoughness, uSpecularBrightness );",

                        "specularTotal += uSpecularColor * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * specularStrength;",

                    "}",

                "#endif",

                // all lights contribution summation

                "vec3 totalLight = vec3( 0.0 );",

                "#if MAX_DIR_LIGHTS > 0",
                    "totalLight += dirTotal;",
                "#endif",

                "#if MAX_POINT_LIGHTS > 0",
                    "totalLight += pointTotal;",
                "#endif",

                "#if MAX_HEMI_LIGHTS > 0",
                    "totalLight += hemiTotal;",
                "#endif",

                "gl_FragColor.xyz = gl_FragColor.xyz * ( totalLight + ambientLightColor * uAmbientColor ) + specularTotal;",

                THREE.ShaderChunk[ "shadowmap_fragment" ],
                THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
                THREE.ShaderChunk[ "fog_fragment" ],

            "}"

        ].join("\n"),

        vertexShader: [

            "uniform vec4 offsetRepeat;",

            "varying vec3 vNormal;",
            "varying vec2 vUv;",

            "varying vec3 vViewPosition;",

            THREE.ShaderChunk[ "shadowmap_pars_vertex" ],

            "void main() {",

                "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
                "vec4 mPosition = modelMatrix * vec4( position, 1.0 );",

                "vViewPosition = -mvPosition.xyz;",

                "vNormal = normalMatrix * normal;",

                "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",

                "gl_Position = projectionMatrix * mvPosition;",

                THREE.ShaderChunk[ "shadowmap_vertex" ],

            "}"

        ].join( "\n" )

    },

    /* ------------------------------------------------------------------------------------------
    //    Skin shader
    //        - Blinn-Phong diffuse term (using normal + diffuse maps)
    //        - subsurface scattering approximation by four blur layers
    //        - physically based specular term (Kelemen/Szirmay-Kalos specular reflectance)
    //
    //        - point and directional lights (use with "lights: true" material option)
    //
    //        - based on Nvidia Advanced Skin Rendering GDC 2007 presentation
    //          and GPU Gems 3 Chapter 14. Advanced Techniques for Realistic Real-Time Skin Rendering
    //
    //            http://developer.download.nvidia.com/presentations/2007/gdc/Advanced_Skin.pdf
    //            http://http.developer.nvidia.com/GPUGems3/gpugems3_ch14.html
    // ------------------------------------------------------------------------------------------ */

    'skin' : {

        uniforms: THREE.UniformsUtils.merge( [

            THREE.UniformsLib[ "fog" ],
            THREE.UniformsLib[ "lights" ],

            {

            "passID": { type: "i", value: 0 },

            "tDiffuse"    : { type: "t", value: null },
            "tNormal"    : { type: "t", value: null },

            "tBlur1"    : { type: "t", value: null },
            "tBlur2"    : { type: "t", value: null },
            "tBlur3"    : { type: "t", value: null },
            "tBlur4"    : { type: "t", value: null },

            "tBeckmann"    : { type: "t", value: null },

            "uNormalScale": { type: "f", value: 1.0 },

            "uDiffuseColor":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
            "uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
            "uAmbientColor":  { type: "c", value: new THREE.Color( 0x050505 ) },
            "uOpacity":       { type: "f", value: 1 },

            "uRoughness":               { type: "f", value: 0.15 },
            "uSpecularBrightness":     { type: "f", value: 0.75 }

            }

        ] ),

        fragmentShader: [

            "uniform vec3 uAmbientColor;",
            "uniform vec3 uDiffuseColor;",
            "uniform vec3 uSpecularColor;",
            "uniform float uOpacity;",

            "uniform float uRoughness;",
            "uniform float uSpecularBrightness;",

            "uniform int passID;",

            "uniform sampler2D tDiffuse;",
            "uniform sampler2D tNormal;",

            "uniform sampler2D tBlur1;",
            "uniform sampler2D tBlur2;",
            "uniform sampler2D tBlur3;",
            "uniform sampler2D tBlur4;",

            "uniform sampler2D tBeckmann;",

            "uniform float uNormalScale;",

            "varying vec3 vTangent;",
            "varying vec3 vBinormal;",
            "varying vec3 vNormal;",
            "varying vec2 vUv;",

            "uniform vec3 ambientLightColor;",

            "#if MAX_DIR_LIGHTS > 0",
                "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
                "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
            "#endif",

            "#if MAX_POINT_LIGHTS > 0",
                "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
                "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
            "#endif",

            "varying vec3 vViewPosition;",

            THREE.ShaderChunk[ "fog_pars_fragment" ],

            "float fresnelReflectance( vec3 H, vec3 V, float F0 ) {",

                "float base = 1.0 - dot( V, H );",
                "float exponential = pow( base, 5.0 );",

                "return exponential + F0 * ( 1.0 - exponential );",

            "}",

            // Kelemen/Szirmay-Kalos specular BRDF

            "float KS_Skin_Specular( vec3 N,",         // Bumped surface normal
                                    "vec3 L,",         // Points to light
                                    "vec3 V,",         // Points to eye
                                    "float m,",      // Roughness
                                    "float rho_s",     // Specular brightness
                                    ") {",

                "float result = 0.0;",
                "float ndotl = dot( N, L );",

                "if( ndotl > 0.0 ) {",

                    "vec3 h = L + V;", // Unnormalized half-way vector
                    "vec3 H = normalize( h );",

                    "float ndoth = dot( N, H );",

                    "float PH = pow( 2.0 * texture2D( tBeckmann, vec2( ndoth, m ) ).x, 10.0 );",
                    "float F = fresnelReflectance( H, V, 0.028 );",
                    "float frSpec = max( PH * F / dot( h, h ), 0.0 );",

                    "result = ndotl * rho_s * frSpec;", // BRDF * dot(N,L) * rho_s

                "}",

                "return result;",

            "}",

            "void main() {",

                "gl_FragColor = vec4( 1.0 );",

                "vec4 mColor = vec4( uDiffuseColor, uOpacity );",
                "vec4 mSpecular = vec4( uSpecularColor, uOpacity );",

                "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
                "normalTex.xy *= uNormalScale;",
                "normalTex = normalize( normalTex );",

                "vec4 colDiffuse = texture2D( tDiffuse, vUv );",
                "colDiffuse *= colDiffuse;",

                "gl_FragColor = gl_FragColor * colDiffuse;",

                "mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
                "vec3 finalNormal = tsb * normalTex;",

                "vec3 normal = normalize( finalNormal );",
                "vec3 viewPosition = normalize( vViewPosition );",

                // point lights

                "vec3 specularTotal = vec3( 0.0 );",

                "#if MAX_POINT_LIGHTS > 0",

                    "vec4 pointTotal = vec4( vec3( 0.0 ), 1.0 );",

                    "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",

                        "vec3 pointVector = normalize( vPointLight[ i ].xyz );",
                        "float pointDistance = vPointLight[ i ].w;",

                        "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",

                        "pointTotal  += pointDistance * vec4( pointLightColor[ i ], 1.0 ) * ( mColor * pointDiffuseWeight );",

                        "if ( passID == 1 )",
                            "specularTotal += pointDistance * mSpecular.xyz * pointLightColor[ i ] * KS_Skin_Specular( normal, pointVector, viewPosition, uRoughness, uSpecularBrightness );",

                    "}",

                "#endif",

                // directional lights

                "#if MAX_DIR_LIGHTS > 0",

                    "vec4 dirTotal = vec4( vec3( 0.0 ), 1.0 );",

                    "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",

                        "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",

                        "vec3 dirVector = normalize( lDirection.xyz );",

                        "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",

                        "dirTotal  += vec4( directionalLightColor[ i ], 1.0 ) * ( mColor * dirDiffuseWeight );",

                        "if ( passID == 1 )",
                            "specularTotal += mSpecular.xyz * directionalLightColor[ i ] * KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",

                    "}",

                "#endif",

                // all lights contribution summation

                "vec4 totalLight = vec4( vec3( 0.0 ), uOpacity );",

                "#if MAX_DIR_LIGHTS > 0",
                    "totalLight += dirTotal;",
                "#endif",

                "#if MAX_POINT_LIGHTS > 0",
                    "totalLight += pointTotal;",
                "#endif",

                "gl_FragColor = gl_FragColor * totalLight;",

                "if ( passID == 0 ) {",

                    "gl_FragColor = vec4( sqrt( gl_FragColor.xyz ), gl_FragColor.w );",

                "} else if ( passID == 1 ) {",

                    //"#define VERSION1",

                    "#ifdef VERSION1",

                        "vec3 nonblurColor = sqrt( gl_FragColor.xyz );",

                    "#else",

                        "vec3 nonblurColor = gl_FragColor.xyz;",

                    "#endif",

                    "vec3 blur1Color = texture2D( tBlur1, vUv ).xyz;",
                    "vec3 blur2Color = texture2D( tBlur2, vUv ).xyz;",
                    "vec3 blur3Color = texture2D( tBlur3, vUv ).xyz;",
                    "vec3 blur4Color = texture2D( tBlur4, vUv ).xyz;",


                    //"gl_FragColor = vec4( blur1Color, gl_FragColor.w );",

                    //"gl_FragColor = vec4( vec3( 0.22, 0.5, 0.7 ) * nonblurColor + vec3( 0.2, 0.5, 0.3 ) * blur1Color + vec3( 0.58, 0.0, 0.0 ) * blur2Color, gl_FragColor.w );",

                    //"gl_FragColor = vec4( vec3( 0.25, 0.6, 0.8 ) * nonblurColor + vec3( 0.15, 0.25, 0.2 ) * blur1Color + vec3( 0.15, 0.15, 0.0 ) * blur2Color + vec3( 0.45, 0.0, 0.0 ) * blur3Color, gl_FragColor.w );",


                    "gl_FragColor = vec4( vec3( 0.22,  0.437, 0.635 ) * nonblurColor + ",
                                         "vec3( 0.101, 0.355, 0.365 ) * blur1Color + ",
                                         "vec3( 0.119, 0.208, 0.0 )   * blur2Color + ",
                                         "vec3( 0.114, 0.0,   0.0 )   * blur3Color + ",
                                         "vec3( 0.444, 0.0,   0.0 )   * blur4Color",
                                         ", gl_FragColor.w );",

                    "gl_FragColor.xyz *= pow( colDiffuse.xyz, vec3( 0.5 ) );",

                    "gl_FragColor.xyz += ambientLightColor * uAmbientColor * colDiffuse.xyz + specularTotal;",

                    "#ifndef VERSION1",

                        "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",

                    "#endif",

                "}",

                THREE.ShaderChunk[ "fog_fragment" ],

            "}"

        ].join("\n"),

        vertexShader: [

            "attribute vec4 tangent;",

            "#ifdef VERTEX_TEXTURES",

                "uniform sampler2D tDisplacement;",
                "uniform float uDisplacementScale;",
                "uniform float uDisplacementBias;",

            "#endif",

            "varying vec3 vTangent;",
            "varying vec3 vBinormal;",
            "varying vec3 vNormal;",
            "varying vec2 vUv;",

            "#if MAX_POINT_LIGHTS > 0",

                "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
                "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

                "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",

            "#endif",

            "varying vec3 vViewPosition;",

            "void main() {",

                "vec4 mPosition = modelMatrix * vec4( position, 1.0 );",

                "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",

                "vViewPosition = -mvPosition.xyz;",

                "vNormal = normalize( normalMatrix * normal );",

                // tangent and binormal vectors

                "vTangent = normalize( normalMatrix * tangent.xyz );",

                "vBinormal = cross( vNormal, vTangent ) * tangent.w;",
                "vBinormal = normalize( vBinormal );",

                "vUv = uv;",

                // point lights

                "#if MAX_POINT_LIGHTS > 0",

                    "for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",

                        "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",

                        "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                        "float lDistance = 1.0;",

                        "if ( pointLightDistance[ i ] > 0.0 )",
                            "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",

                        "lVector = normalize( lVector );",

                        "vPointLight[ i ] = vec4( lVector, lDistance );",

                    "}",

                "#endif",

                // displacement mapping

                "#ifdef VERTEX_TEXTURES",

                    "vec3 dv = texture2D( tDisplacement, uv ).xyz;",
                    "float df = uDisplacementScale * dv.x + uDisplacementBias;",
                    "vec4 displacedPosition = vec4( vNormal.xyz * df, 0.0 ) + mvPosition;",
                    "gl_Position = projectionMatrix * displacedPosition;",

                "#else",

                    "gl_Position = projectionMatrix * mvPosition;",

                "#endif",

            "}"

        ].join("\n"),

        vertexShaderUV: [

            "attribute vec4 tangent;",

            "#ifdef VERTEX_TEXTURES",

                "uniform sampler2D tDisplacement;",
                "uniform float uDisplacementScale;",
                "uniform float uDisplacementBias;",

            "#endif",

            "varying vec3 vTangent;",
            "varying vec3 vBinormal;",
            "varying vec3 vNormal;",
            "varying vec2 vUv;",

            "#if MAX_POINT_LIGHTS > 0",

                "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
                "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",

                "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",

            "#endif",

            "varying vec3 vViewPosition;",

            "void main() {",

                "vec4 mPosition = modelMatrix * vec4( position, 1.0 );",

                "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",

                "vViewPosition = -mvPosition.xyz;",

                "vNormal = normalize( normalMatrix * normal );",

                // tangent and binormal vectors

                "vTangent = normalize( normalMatrix * tangent.xyz );",

                "vBinormal = cross( vNormal, vTangent ) * tangent.w;",
                "vBinormal = normalize( vBinormal );",

                "vUv = uv;",

                // point lights

                "#if MAX_POINT_LIGHTS > 0",

                    "for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",

                        "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",

                        "vec3 lVector = lPosition.xyz - mvPosition.xyz;",

                        "float lDistance = 1.0;",

                        "if ( pointLightDistance[ i ] > 0.0 )",
                            "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",

                        "lVector = normalize( lVector );",

                        "vPointLight[ i ] = vec4( lVector, lDistance );",

                    "}",

                "#endif",

                "gl_Position = vec4( uv.x * 2.0 - 1.0, uv.y * 2.0 - 1.0, 0.0, 1.0 );",

            "}"

        ].join("\n")

    },

    /* ------------------------------------------------------------------------------------------
    // Beckmann distribution function
    //    - to be used in specular term of skin shader
    //    - render a screen-aligned quad to precompute a 512 x 512 texture
    //
    //        - from http://developer.nvidia.com/node/171
     ------------------------------------------------------------------------------------------ */

    "beckmann" : {

        uniforms: {},

        vertexShader: [

            "varying vec2 vUv;",

            "void main() {",

                "vUv = uv;",
                "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

            "}"

        ].join("\n"),

        fragmentShader: [

            "varying vec2 vUv;",

            "float PHBeckmann( float ndoth, float m ) {",

                "float alpha = acos( ndoth );",
                "float ta = tan( alpha );",

                "float val = 1.0 / ( m * m * pow( ndoth, 4.0 ) ) * exp( -( ta * ta ) / ( m * m ) );",
                "return val;",

            "}",

            "float KSTextureCompute( vec2 tex ) {",

                // Scale the value to fit within [0,1]  invert upon lookup.

                "return 0.5 * pow( PHBeckmann( tex.x, tex.y ), 0.1 );",

            "}",

            "void main() {",

                "float x = KSTextureCompute( vUv );",

                "gl_FragColor = vec4( x, x, x, 1.0 );",

            "}"

        ].join("\n")

    }

};
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Wii Opera SDK - Drawing Class v2.6.16 2008-12-14                         //
// (c) 2007-2008 Daniel Gump. All Rights Reserved.                          //
// http://wiioperasdk.com, http://hullbreachonline.com                      //
// hullbreach@hullbreachonline.com                                          //
//                                                                          //
//  Wii is a trademark of Nintendo Co., Ltd.                                //
//  Opera is a trademark of Opera, ASA.                                     //
//  This software package is not associated with either company             //
//  but was created to support users of both.  Its alternative name         //
//  when supporting other products is the HULLBREACH SDK.                   //
//                                                                          //
//  Redistribution and use in source and binary forms, with or without      //
//  modification, are permitted provided that the following conditions      //
//  are met:                                                                //
//    * Redistributions of source code must retain the above copyright      //
//      notice, this list of conditions and the following disclaimer.       //
//    * Redistributions in binary form must reproduce the above copyright   //
//      notice, this list of conditions and the following disclaimer in     //
//      the documentation and/or other materials provided with the          //
//      distribution.                                                       //
//    * Neither the names HULLBREACH ONLINE nor WII OPERA SDK nor the names //
//      of its contributors may be used to endorse or promote products      //
//      derived from this software without specific prior written           //
//      permission.                                                         //
//    * If the explicit purpose of the software is not to support the       //
//      Nintendo Wii or the Opera Web browser, then the names of such must  //
//      not be used in any derived product. The name shall be the           //
//      HULLBREACH SDK with a reference link to http://hullbreachonline.    //
//                                                                          //
//  THIS SOFTWARE IS PROVIDED BY Daniel Gump ''AS IS'' AND ANY EXPRESS OR   //
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED          //
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  //
//  DISCLAIMED. IN NO EVENT SHALL Daniel Gump BE LIABLE FOR ANY DIRECT,     //
//  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES      //
//  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR      //
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      //
//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,     //
//  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING   //
//  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      //
//  POSSIBILITY OF SUCH DAMAGE.                                             //
//////////////////////////////////////////////////////////////////////////////

function Drawing(){
	this.WIREFRAME = 1; this.FILL = 2;
	ZOOM = 1;
	CANVAS = null;
	TEXTURES = null;
}
Drawing.prototype.initialize = function(canvas){
	CANVAS = canvas.getContext("2d");
	CANVAS.lineJoin = "round";
	CANVAS.lineWidth = 1;
}
Drawing.prototype.loadTextures = function(textures){ TEXTURES = textures; }
Drawing.prototype.setFillColor = function(r,g,b){ CANVAS.fillStyle = "rgb("+(r>255?255:(r<0?0:r|0))+", "+(g>255?255:(g<0?0:g|0))+", "+(b>255?255:(b<0?0:b|0))+")"; }
Drawing.prototype.setFillColorA = function(r,g,b,a){ CANVAS.fillStyle = "rgba("+(r>255?255:(r<0?0:r|0))+", "+(g>255?255:(g<0?0:g|0))+", "+(b>255?255:(b<0?0:b|0))+", "+(a>255?1:(a<0?0:a/255))+")"; }
Drawing.prototype.setLineColor = function(r,g,b){ CANVAS.strokeStyle = "rgb("+(r>255?255:(r<0?0:r|0))+", "+(g>255?255:(g<0?0:g|0))+", "+(b>255?255:(b<0?0:b|0))+")"; }
Drawing.prototype.setLineColorA = function(r,g,b,a){ CANVAS.strokeStyle = "rgba("+(r>255?255:(r<0?0:r|0))+", "+(g>255?255:(g<0?0:g|0))+", "+(b>255?255:(b<0?0:b|0))+", "+(a>255?1:(a<0?0:a/255))+")"; }
Drawing.prototype.clipCircle = function(centerx,centery,radius){ CANVAS.beginPath(); CANVAS.arc(centerx,centery,radius,0,6.28318531,false); CANVAS.clip(); }
Drawing.prototype.clipRectangle = function(x1,y1,x2,y2){ CANVAS.beginPath(); CANVAS.strokeRect(x1,y1,x2-x1,y2-y1); CANVAS.clip(); }
Drawing.prototype.drawCircle = function(centerx,centery,radius,style){
	CANVAS.beginPath();
	CANVAS.arc(centerx, centery, radius, 0, Math.PI*2, false);
	if(style & this.FILL) CANVAS.fill();
	if(style & this.WIREFRAME) CANVAS.stroke();
}
Drawing.prototype.drawImage = function(x1,y1,x2,y2,img,angle){
	if(img.complete){
		x1|=0;
		y1|=0;
		x2|=0;
		y2|=0;
		if(x2<x1) x2=x1+1;
		if(y2<y1) y2=y1+1;
		var centerx = (x1+x2)>>1;
		var centery = (y1+y2)>>1;

		CANVAS.save();
		CANVAS.translate(centerx, centery);
		if(angle) CANVAS.rotate(angle*0.01745329);
		CANVAS.drawImage(img, x1-centerx, y1-centery, x2-x1, y2-y1);
		CANVAS.restore();
	}
}
Drawing.prototype.drawLine = function(x1, y1, x2, y2){ CANVAS.beginPath(); CANVAS.moveTo(x1|0, y1|0); CANVAS.lineTo(x2|0, y2|0); CANVAS.stroke(); }
Drawing.prototype.drawRectangle = function(x1, y1, x2, y2, style, angle){
	x1|=0;
	y1|=0;
	x2|=0;
	y2|=0;
	
	if(!angle){
		if(style & this.FILL) CANVAS.fillRect(x1, y1, x2-x1, y2-y1);
		if(style & this.WIREFRAME) CANVAS.strokeRect(x1, y1, x2-x1, y2-y1);
	}else{
		var centerx = (x1+x2)>>1; var centery = (y1+y2)>>1;

		CANVAS.save();
		CANVAS.translate(centerx, centery);
		CANVAS.rotate(angle*DEGTORAD);
		if(style & this.FILL) CANVAS.fillRect(x1-centerx, y1-centery, x2-x1, y2-y1);
		if(style & this.WIREFRAME) CANVAS.strokeRect(x1-centerx, y1-centery, x2-x1, y2-y1);
		CANVAS.restore();
	}
}
Drawing.prototype.drawScene = function(array,style){
	var piOver2 = 1.570796326794897;
	var piOver4 = 0.785398163397448;
	var sqrt2half = 1.414213562373095;

	for(tri=array.length;--tri>=0;){
		var x1 = array[tri][0];
		var y1 = array[tri][1];
		var x2 = array[tri][2];
		var y2 = array[tri][3];
		var x3 = array[tri][4];
		var y3 = array[tri][5];
		shade=array[tri][10];

		if(TEXTURES && array[tri][9]>=0){
			CANVAS.save();

			var u = (x2-x3)*(x2-x3)+(y2-y3)*(y2-y3);
			var v = (x1-x3)*(x1-x3)+(y1-y3)*(y1-y3);
			var w = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);

			var canvasRot = 0.5*Math.acos((w+v-u)/(2*Math.sqrt(w*v)));
			var scale = Math.cos(canvasRot)*sqrt2half;

			CANVAS.translate(x1,y1);
			CANVAS.rotate(Math.atan2(y2-y1,x2-x1)-piOver2+canvasRot);
			CANVAS.scale(Math.tan(canvasRot),1);
			CANVAS.rotate(piOver4);
			CANVAS.scale(Math.sqrt(w)*scale,Math.sqrt(v)*scale);
			//CANVAS.transform(x2-x1,y2-y1,x3-x1,y3-y1, x1,y1);
			CANVAS.drawImage((canvasimg = TEXTURES[array[tri][9]]), 0,0, canvasimg.width,canvasimg.height, 0,0, 1,1);
			CANVAS.restore();

			if(shade!=0){
				CANVAS.beginPath();
				CANVAS.moveTo(x1,y1);
				CANVAS.lineTo(x2,y2);
				CANVAS.lineTo(x3,y3);
				CANVAS.lineTo(x1,y1);
				if(shade>0){
					if(shade>1) shade=1;
					CANVAS.fillStyle = "rgba(255,255,255,"+(shade)+")";
					CANVAS.strokeStyle = "rgba(255,255,255,"+(shade*.5)+")";
				}else if(shade<0){
					if(shade<-1) shade=-1;
					CANVAS.fillStyle = "rgba(0,0,0,"+(-shade)+")";
					CANVAS.strokeStyle = "rgba(0,0,0,"+(-shade*.5)+")";
				}
				if(style & this.FILL) CANVAS.fill();
				if(style & this.WIREFRAME) CANVAS.stroke();
			}
		}else{
			var red = array[tri][6];
			var green = array[tri][7];
			var blue = array[tri][8];
			if(shade!=0){
				red=(red*=++shade)>255?255:(red<0?0:red);
				green=(green*=shade)>255?255:(green<0?0:green);
				blue=(blue*=shade)>255?255:(blue<0?0:blue);
			}
			var color = "rgb("+(red|0)+","+(green|0)+","+(blue|0)+")";
			CANVAS.beginPath();
			CANVAS.moveTo(x1,y1);
			CANVAS.lineTo(x2,y2);
			CANVAS.lineTo(x3,y3);
			CANVAS.lineTo(x1,y1);
			if(style & this.FILL){ CANVAS.fillStyle = color; CANVAS.fill(); }
			if(style & this.WIREFRAME){ CANVAS.strokeStyle = color; CANVAS.stroke(); }
		}
	}
}

Drawing.prototype.drawFloor = function(x1,x2,y1,x3,x4,y2,img){
	if((x2|=0)==(x1|=0)) x2++;
	if((y2|=0)==(y1|=0)) y2++;
	if((x4|=0)==(x3|=0)) x4++;
	var absdy=(dy = y2-y1)<0?-dy:dy;

	var sourceD = img.width-1, sourceY = (img.height-1)*(dx2 = x4-x3)/dy;
	var destX = (x3-x1)/dy;
	var tempY = 0;
	var destW2 = (dx1 = x2-x1);

	var absscale = (fullscale = 1.5*(dy>>31?-1:1)+dy/img.height)>>31?-(fullscale-1):(fullscale+1);
	var destwfullscale = fullscale*(dx2-dx1+1)/dy;

	while(tempY<0?-tempY:tempY<=absdy){
		CANVAS.drawImage(img, 0, sourceY*tempY/destW2, sourceD, 1, x1+destX*tempY, tempY+y1, destW2, absscale);
		tempY+=fullscale;
		destW2+=destwfullscale;
	}	
}
Drawing.prototype.drawWall = function(x1,y1,y2,x2,y3,y4,img){
	if(x2==x1) x2++;
	if(y2==y1) y2++;
	if(y4==y3) y4++;
	var dx = x2-x1, dy1 = y2-y1, dy2 = y4-y3;
	var absdx=dx<0?-dx:dx;

	var sourceH = img.height-1, sourceX = (img.width-1)*dy2/dx;
	var destY = (y3-y1)/dx;
	var tempX = 0;

	var fullscale = 1.5*(dx<0?-1:1)+dx/img.width;
	var absscale = fullscale<0?(-fullscale-1):(fullscale+1);
	var desthfullscale = fullscale*(dy2-dy1+1)/dx;

	while(tempX<0?-tempX:tempX<=absdx){
		CANVAS.drawImage(img, sourceX*tempX/dy1, 0, 1, sourceH, tempX+x1, y1+destY*tempX, absscale, dy1);
		tempX+=fullscale;
		dy1+=desthfullscale;
	}	
}
Drawing.prototype.zoom = function(zoom,width,height){
	ZOOM = zoom;
	CANVAS.translate(width>>1, height>>1);
	CANVAS.scale(ZOOM, ZOOM);
	CANVAS.translate(-width>>1, -height>>1);
}
Drawing.prototype.unZoom = function(width,height){
	CANVAS.translate(width>>1, height>>1);
	CANVAS.scale(1/ZOOM, 1/ZOOM);
	CANVAS.translate(-width>>1, -height>>1);
	ZOOM = 1;
}
Drawing.prototype.clear = function(x1, y1, x2, y2){ CANVAS.clearRect(x1, y1, x2-x1, y2-y1); }

Draw = new Drawing();var jWorkflow=function(){return{order:function(h,j){var i=[],f,d=null,g=function(){var a=false;return{take:function(){a=true},pass:function(b){var c;a=false;if(f.length){c=f.shift();b=c.func.apply(c.context,[b,g]);a||g.pass(b)}else d.func&&d.func.apply(d.context,[])}}}(),e={andThen:function(a,b){if(typeof a!=="function")throw"expected function but was "+typeof a;i.push({func:a,context:b});return e},chill:function(a){return e.andThen(function(b,c){c.take();setTimeout(function(){c.pass(b)},a)})},start:function(a,
b){d={func:a,context:b};f=i.slice();g.pass()}};return h?e.andThen(h,j):e}}}();if(typeof module==="object"&&typeof require==="function")module.exports=jWorkflow;
/*
  OpenLayers.js -- OpenLayers Map Viewer Library

  Copyright 2005-2010 OpenLayers Contributors, released under the Clear BSD
  license. Full license text below taken from http://svn.openlayers.org/trunk/openlayers/license.txt

        Copyright 2005-2011 OpenLayers Contributors. All rights reserved. See
        authors.txt for full list.
         
        Redistribution and use in source and binary forms, with or without modification,
        are permitted provided that the following conditions are met:
         
        1. Redistributions of source code must retain the above copyright notice, this
        list of conditions and the following disclaimer.
         
        2. Redistributions in binary form must reproduce the above copyright notice,
        this list of conditions and the following disclaimer in the documentation and/or
        other materials provided with the distribution.
         
        THIS SOFTWARE IS PROVIDED BY OPENLAYERS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
        OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
        MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
        SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
        LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
        OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
        ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         
        The views and conclusions contained in the software and documentation are those
        of the authors and should not be interpreted as representing official policies,
        either expressed or implied, of OpenLayers Contributors.

  Includes compressed code under the following licenses:

  (For uncompressed versions of the code used please see the
  OpenLayers SVN repository: <http://openlayers.org/>)

*/

/**  
*  
*  Contains portions of Rico <http://openrico.org/>
* 
*  Copyright 2005 Sabre Airline Solutions  
*  
*  Licensed under the Apache License, Version 2.0 (the "License"); you
*  may not use this file except in compliance with the License. You
*  may obtain a copy of the License at
*  
*         http://www.apache.org/licenses/LICENSE-2.0  
*  
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
*  implied. See the License for the specific language governing
*  permissions and limitations under the License. 
*
**/

/**
 * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
 * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

/**
 * Contains portions of Gears <http://code.google.com/apis/gears/>
 *
 * Copyright 2007, Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. Neither the name of Google Inc. nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Sets up google.gears.*, which is *the only* supported way to access Gears.
 *
 * Circumvent this file at your own risk!
 *
 * In the future, Gears may automatically define google.gears.* without this
 * file. Gears may use these objects to transparently fix bugs and compatibility
 * issues. Applications that use the code below will continue to work seamlessly
 * when that happens.
 */
var OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers=="object"&&OpenLayers.singleFile);var scriptLocation;window.OpenLayers={_scriptName:(!singleFile)?"lib/OpenLayers.js":"OpenLayers.js",_getScriptLocation:function(){if(scriptLocation!=undefined){return scriptLocation;}
scriptLocation="";var isOL=new RegExp("(^|(.*?\\/))("+OpenLayers._scriptName+")(\\?|$)");var scripts=document.getElementsByTagName('script');for(var i=0,len=scripts.length;i<len;i++){var src=scripts[i].getAttribute('src');if(src){var match=src.match(isOL);if(match){scriptLocation=match[1];break;}}}
return scriptLocation;}};if(!singleFile){var jsfiles=new Array("OpenLayers/Util.js","OpenLayers/BaseTypes.js","OpenLayers/BaseTypes/Class.js","OpenLayers/BaseTypes/Bounds.js","OpenLayers/BaseTypes/Element.js","OpenLayers/BaseTypes/LonLat.js","OpenLayers/BaseTypes/Pixel.js","OpenLayers/BaseTypes/Size.js","OpenLayers/Console.js","OpenLayers/Tween.js","Rico/Corner.js","Rico/Color.js","OpenLayers/Ajax.js","OpenLayers/Events.js","OpenLayers/Request.js","OpenLayers/Request/XMLHttpRequest.js","OpenLayers/Projection.js","OpenLayers/Map.js","OpenLayers/Layer.js","OpenLayers/Icon.js","OpenLayers/Marker.js","OpenLayers/Marker/Box.js","OpenLayers/Popup.js","OpenLayers/Tile.js","OpenLayers/Tile/Image.js","OpenLayers/Tile/Image/IFrame.js","OpenLayers/Tile/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.js","OpenLayers/Layer/Google/v3.js","OpenLayers/Layer/VirtualEarth.js","OpenLayers/Layer/Yahoo.js","OpenLayers/Layer/HTTPRequest.js","OpenLayers/Layer/Grid.js","OpenLayers/Layer/MapGuide.js","OpenLayers/Layer/MapServer.js","OpenLayers/Layer/MapServer/Untiled.js","OpenLayers/Layer/KaMap.js","OpenLayers/Layer/KaMapCache.js","OpenLayers/Layer/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/ArcGIS93Rest.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/WMS/Post.js","OpenLayers/Layer/WMTS.js","OpenLayers/Layer/ArcIMS.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/XYZ.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.js","OpenLayers/Layer/Zoomify.js","OpenLayers/Popup/Anchored.js","OpenLayers/Popup/AnchoredBubble.js","OpenLayers/Popup/Framed.js","OpenLayers/Popup/FramedCloud.js","OpenLayers/Feature.js","OpenLayers/Feature/Vector.js","OpenLayers/Feature/WFS.js","OpenLayers/Handler.js","OpenLayers/Handler/Click.js","OpenLayers/Handler/Hover.js","OpenLayers/Handler/Point.js","OpenLayers/Handler/Path.js","OpenLayers/Handler/Polygon.js","OpenLayers/Handler/Feature.js","OpenLayers/Handler/Drag.js","OpenLayers/Handler/RegularPolygon.js","OpenLayers/Handler/Box.js","OpenLayers/Handler/MouseWheel.js","OpenLayers/Handler/Keyboard.js","OpenLayers/Control.js","OpenLayers/Control/Attribution.js","OpenLayers/Control/Button.js","OpenLayers/Control/ZoomBox.js","OpenLayers/Control/ZoomToMaxExtent.js","OpenLayers/Control/DragPan.js","OpenLayers/Control/Navigation.js","OpenLayers/Control/MouseDefaults.js","OpenLayers/Control/MousePosition.js","OpenLayers/Control/OverviewMap.js","OpenLayers/Control/KeyboardDefaults.js","OpenLayers/Control/PanZoom.js","OpenLayers/Control/PanZoomBar.js","OpenLayers/Control/ArgParser.js","OpenLayers/Control/Permalink.js","OpenLayers/Control/Scale.js","OpenLayers/Control/ScaleLine.js","OpenLayers/Control/Snapping.js","OpenLayers/Control/Split.js","OpenLayers/Control/LayerSwitcher.js","OpenLayers/Control/DrawFeature.js","OpenLayers/Control/DragFeature.js","OpenLayers/Control/ModifyFeature.js","OpenLayers/Control/Panel.js","OpenLayers/Control/SelectFeature.js","OpenLayers/Control/NavigationHistory.js","OpenLayers/Control/Measure.js","OpenLayers/Control/WMSGetFeatureInfo.js","OpenLayers/Control/WMTSGetFeatureInfo.js","OpenLayers/Control/Graticule.js","OpenLayers/Control/TransformFeature.js","OpenLayers/Control/SLDSelect.js","OpenLayers/Geometry.js","OpenLayers/Geometry/Rectangle.js","OpenLayers/Geometry/Collection.js","OpenLayers/Geometry/Point.js","OpenLayers/Geometry/MultiPoint.js","OpenLayers/Geometry/Curve.js","OpenLayers/Geometry/LineString.js","OpenLayers/Geometry/LinearRing.js","OpenLayers/Geometry/Polygon.js","OpenLayers/Geometry/MultiLineString.js","OpenLayers/Geometry/MultiPolygon.js","OpenLayers/Geometry/Surface.js","OpenLayers/Renderer.js","OpenLayers/Renderer/Elements.js","OpenLayers/Renderer/SVG.js","OpenLayers/Renderer/Canvas.js","OpenLayers/Renderer/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/Vector/RootContainer.js","OpenLayers/Strategy.js","OpenLayers/Strategy/Filter.js","OpenLayers/Strategy/Fixed.js","OpenLayers/Strategy/Cluster.js","OpenLayers/Strategy/Paging.js","OpenLayers/Strategy/BBOX.js","OpenLayers/Strategy/Save.js","OpenLayers/Strategy/Refresh.js","OpenLayers/Filter.js","OpenLayers/Filter/FeatureId.js","OpenLayers/Filter/Logical.js","OpenLayers/Filter/Comparison.js","OpenLayers/Filter/Spatial.js","OpenLayers/Protocol.js","OpenLayers/Protocol/HTTP.js","OpenLayers/Protocol/SQL.js","OpenLayers/Protocol/SQL/Gears.js","OpenLayers/Protocol/WFS.js","OpenLayers/Protocol/WFS/v1.js","OpenLayers/Protocol/WFS/v1_0_0.js","OpenLayers/Protocol/WFS/v1_1_0.js","OpenLayers/Protocol/SOS.js","OpenLayers/Protocol/SOS/v1_0_0.js","OpenLayers/Layer/PointTrack.js","OpenLayers/Layer/GML.js","OpenLayers/Style.js","OpenLayers/Style2.js","OpenLayers/StyleMap.js","OpenLayers/Rule.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/Context.js","OpenLayers/Format/ArcXML.js","OpenLayers/Format/ArcXML/Features.js","OpenLayers/Format/GML.js","OpenLayers/Format/GML/Base.js","OpenLayers/Format/GML/v2.js","OpenLayers/Format/GML/v3.js","OpenLayers/Format/Atom.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WFSCapabilities.js","OpenLayers/Format/WFSCapabilities/v1.js","OpenLayers/Format/WFSCapabilities/v1_0_0.js","OpenLayers/Format/WFSCapabilities/v1_1_0.js","OpenLayers/Format/WFSDescribeFeatureType.js","OpenLayers/Format/WMSDescribeLayer.js","OpenLayers/Format/WMSDescribeLayer/v1_1.js","OpenLayers/Format/WKT.js","OpenLayers/Format/OSM.js","OpenLayers/Format/GPX.js","OpenLayers/Format/Filter.js","OpenLayers/Format/Filter/v1.js","OpenLayers/Format/Filter/v1_0_0.js","OpenLayers/Format/Filter/v1_1_0.js","OpenLayers/Format/SLD.js","OpenLayers/Format/SLD/v1.js","OpenLayers/Format/SLD/v1_0_0.js","OpenLayers/Format/OWSCommon/v1.js","OpenLayers/Format/OWSCommon/v1_0_0.js","OpenLayers/Format/OWSCommon/v1_1_0.js","OpenLayers/Format/CSWGetDomain.js","OpenLayers/Format/CSWGetDomain/v2_0_2.js","OpenLayers/Format/CSWGetRecords.js","OpenLayers/Format/CSWGetRecords/v2_0_2.js","OpenLayers/Format/WFST.js","OpenLayers/Format/WFST/v1.js","OpenLayers/Format/WFST/v1_0_0.js","OpenLayers/Format/WFST/v1_1_0.js","OpenLayers/Format/Text.js","OpenLayers/Format/JSON.js","OpenLayers/Format/GeoJSON.js","OpenLayers/Format/WMC.js","OpenLayers/Format/WMC/v1.js","OpenLayers/Format/WMC/v1_0_0.js","OpenLayers/Format/WMC/v1_1_0.js","OpenLayers/Format/WMSCapabilities.js","OpenLayers/Format/WMSCapabilities/v1.js","OpenLayers/Format/WMSCapabilities/v1_1.js","OpenLayers/Format/WMSCapabilities/v1_1_0.js","OpenLayers/Format/WMSCapabilities/v1_1_1.js","OpenLayers/Format/WMSCapabilities/v1_3.js","OpenLayers/Format/WMSCapabilities/v1_3_0.js","OpenLayers/Format/WMSGetFeatureInfo.js","OpenLayers/Format/SOSCapabilities.js","OpenLayers/Format/SOSCapabilities/v1_0_0.js","OpenLayers/Format/SOSGetObservation.js","OpenLayers/Format/SOSGetFeatureOfInterest.js","OpenLayers/Format/OWSContext.js","OpenLayers/Format/OWSContext/v0_3_1.js","OpenLayers/Format/WMTSCapabilities.js","OpenLayers/Format/WMTSCapabilities/v1_0_0.js","OpenLayers/Layer/WFS.js","OpenLayers/Control/GetFeature.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/PanPanel.js","OpenLayers/Control/Pan.js","OpenLayers/Control/ZoomIn.js","OpenLayers/Control/ZoomOut.js","OpenLayers/Control/ZoomPanel.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Symbolizer.js","OpenLayers/Symbolizer/Point.js","OpenLayers/Symbolizer/Line.js","OpenLayers/Symbolizer/Polygon.js","OpenLayers/Symbolizer/Text.js","OpenLayers/Symbolizer/Raster.js","OpenLayers/Lang.js","OpenLayers/Lang/en.js");var agent=navigator.userAgent;var docWrite=(agent.match("MSIE")||agent.match("Safari"));if(docWrite){var allScriptTags=new Array(jsfiles.length);}
var host=OpenLayers._getScriptLocation()+"lib/";for(var i=0,len=jsfiles.length;i<len;i++){if(docWrite){allScriptTags[i]="<script src='"+host+jsfiles[i]+"'></script>";}else{var s=document.createElement("script");s.src=host+jsfiles[i];var h=document.getElementsByTagName("head").length?document.getElementsByTagName("head")[0]:document.body;h.appendChild(s);}}
if(docWrite){document.write(allScriptTags.join(""));}}})();OpenLayers.VERSION_NUMBER="OpenLayers 2.10 -- $Revision: 10721 $";OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s\s*/,'').replace(/\s\s*$/,'');},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1,len=oStringList.length;i<len;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
return camelizedString;},format:function(template,context,args){if(!context){context=window;}
var replacer=function(str,match){var replacement;var subs=match.split(/\.+/);for(var i=0;i<subs.length;i++){if(i==0){replacement=context;}
replacement=replacement[subs[i]];}
if(typeof replacement=="function"){replacement=args?replacement.apply(null,args):replacement();}
if(typeof replacement=='undefined'){return'undefined';}else{return replacement;}};return template.replace(OpenLayers.String.tokenRegEx,replacer);},tokenRegEx:/\$\{([\w.]+?)\}/g,numberRegEx:/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,isNumeric:function(value){return OpenLayers.String.numberRegEx.test(value);},numericIf:function(value){return OpenLayers.String.isNumeric(value)?parseFloat(value):value;}};if(!String.prototype.startsWith){String.prototype.startsWith=function(sStart){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.startsWith'}));return OpenLayers.String.startsWith(this,sStart);};}
if(!String.prototype.contains){String.prototype.contains=function(str){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.contains'}));return OpenLayers.String.contains(this,str);};}
if(!String.prototype.trim){String.prototype.trim=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.trim'}));return OpenLayers.String.trim(this);};}
if(!String.prototype.camelize){String.prototype.camelize=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.camelize'}));return OpenLayers.String.camelize(this);};}
OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(num,sig){var fig=0;if(sig>0){fig=parseFloat(num.toPrecision(sig));}
return fig;},format:function(num,dec,tsep,dsep){dec=(typeof dec!="undefined")?dec:0;tsep=(typeof tsep!="undefined")?tsep:OpenLayers.Number.thousandsSeparator;dsep=(typeof dsep!="undefined")?dsep:OpenLayers.Number.decimalSeparator;if(dec!=null){num=parseFloat(num.toFixed(dec));}
var parts=num.toString().split(".");if(parts.length==1&&dec==null){dec=0;}
var integer=parts[0];if(tsep){var thousands=/(-?[0-9]+)([0-9]{3})/;while(thousands.test(integer)){integer=integer.replace(thousands,"$1"+tsep+"$2");}}
var str;if(dec==0){str=integer;}else{var rem=parts.length>1?parts[1]:"0";if(dec!=null){rem=rem+new Array(dec-rem.length+1).join("0");}
str=integer+dsep+rem;}
return str;}};if(!Number.prototype.limitSigDigs){Number.prototype.limitSigDigs=function(sig){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.Number.limitSigDigs'}));return OpenLayers.Number.limitSigDigs(this,sig);};}
OpenLayers.Function={bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},bindAsEventListener:function(func,object){return function(event){return func.call(object,event||window.event);};},False:function(){return false;},True:function(){return true;}};if(!Function.prototype.bind){Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.Function.bind'}));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments);};}
if(!Function.prototype.bindAsEventListener){Function.prototype.bindAsEventListener=function(object){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.Function.bindAsEventListener'}));return OpenLayers.Function.bindAsEventListener(this,object);};}
OpenLayers.Array={filter:function(array,callback,caller){var selected=[];if(Array.prototype.filter){selected=array.filter(callback,caller);}else{var len=array.length;if(typeof callback!="function"){throw new TypeError();}
for(var i=0;i<len;i++){if(i in array){var val=array[i];if(callback.call(caller,val,i,array)){selected.push(val);}}}}
return selected;}};OpenLayers.Date={toISOString:(function(){if("toISOString"in Date.prototype){return function(date){return date.toISOString();}}else{function pad(num,len){var str=num+"";while(str.length<len){str="0"+str;}
return str;}
return function(date){var str;if(isNaN(date.getTime())){str="Invalid Date";}else{str=date.getUTCFullYear()+"-"+
pad(date.getUTCMonth()+1,2)+"-"+
pad(date.getUTCDate(),2)+"T"+
pad(date.getUTCHours(),2)+":"+
pad(date.getUTCMinutes(),2)+":"+
pad(date.getUTCSeconds(),2)+"."+
pad(date.getUTCMilliseconds(),3)+"Z";}
return str;}}})(),parse:function(str){var date;var elapsed=Date.parse(str);if(!isNaN(elapsed)){date=new Date(elapsed);}else{var match=str.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))?$/);var date;if(match&&(match[1]||match[7])){var year=parseInt(match[1],10)||0;var month=(parseInt(match[2],10)-1)||0;var day=parseInt(match[3],10)||1;date=new Date(Date.UTC(year,month,day));var type=match[7];if(type){var hours=parseInt(match[4],10);var minutes=parseInt(match[5],10);var secFrac=parseFloat(match[6]);var seconds=secFrac|0;var milliseconds=Math.round(1000*(secFrac-seconds));date.setUTCHours(hours,minutes,seconds,milliseconds);if(type!=="Z"){var hoursOffset=parseInt(type,10);var minutesOffset=parseInt(match[8])||0;var offset=-1000*(60*(hoursOffset*60)+minutesOffset*60);date=new Date(date.getTime()+offset);}}}else{date=new Date("invalid");}}
return date;}};OpenLayers.Class=function(){var Class=function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}};var extended={};var parent,initialize,Type;for(var i=0,len=arguments.length;i<len;++i){Type=arguments[i];if(typeof Type=="function"){if(i==0&&len>1){initialize=Type.prototype.initialize;Type.prototype.initialize=function(){};extended=new Type();if(initialize===undefined){delete Type.prototype.initialize;}else{Type.prototype.initialize=initialize;}}
parent=Type.prototype;}else{parent=Type;}
OpenLayers.Util.extend(extended,parent);}
Class.prototype=extended;return Class;};OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}};};OpenLayers.Class.inherit=function(){var superClass=arguments[0];var proto=new superClass(OpenLayers.Class.isPrototype);for(var i=1,len=arguments.length;i<len;i++){if(typeof arguments[i]=="function"){var mixin=arguments[i];arguments[i]=new mixin(OpenLayers.Class.isPrototype);}
OpenLayers.Util.extend(proto,arguments[i]);}
return proto;};OpenLayers.Util={};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0,len=arguments.length;i<len;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
if(arguments.length==1){return element;}
elements.push(element);}
return elements;};OpenLayers.Util.isElement=function(o){return!!(o&&o.nodeType===1);};if(typeof window.$==="undefined"){window.$=OpenLayers.Util.getElement;}
OpenLayers.Util.extend=function(destination,source){destination=destination||{};if(source){for(var property in source){var value=source[property];if(value!==undefined){destination[property]=value;}}
var sourceIsEvt=typeof window.Event=="function"&&source instanceof window.Event;if(!sourceIsEvt&&source.hasOwnProperty&&source.hasOwnProperty('toString')){destination.toString=source.toString;}}
return destination;};OpenLayers.Util.removeItem=function(array,item){for(var i=array.length-1;i>=0;i--){if(array[i]==item){array.splice(i,1);}}
return array;};OpenLayers.Util.clearArray=function(array){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'array = []'}));array.length=0;};OpenLayers.Util.indexOf=function(array,obj){if(typeof array.indexOf=="function"){return array.indexOf(obj);}else{for(var i=0,len=array.length;i<len;i++){if(array[i]==obj){return i;}}
return-1;}};OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id;}
if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
if(position){element.style.position=position;}
if(border){element.style.border=border;}
if(overflow){element.style.overflow=overflow;}
if(parseFloat(opacity)>=0.0&&parseFloat(opacity)<1.0){element.style.filter='alpha(opacity='+(opacity*100)+')';element.style.opacity=opacity;}else if(parseFloat(opacity)==1.0){element.style.filter='';element.style.opacity='';}};OpenLayers.Util.createDiv=function(id,px,sz,imgURL,position,border,overflow,opacity){var dom=document.createElement('div');if(imgURL){dom.style.backgroundImage='url('+imgURL+')';}
if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
if(!position){position="absolute";}
OpenLayers.Util.modifyDOMElement(dom,id,px,sz,position,border,overflow,opacity);return dom;};OpenLayers.Util.createImage=function(id,px,sz,imgURL,position,border,opacity,delayDisplay){var image=document.createElement("img");if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
if(!position){position="relative";}
OpenLayers.Util.modifyDOMElement(image,id,px,sz,position,border,null,opacity);if(delayDisplay){image.style.display="none";OpenLayers.Event.observe(image,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,image));OpenLayers.Event.observe(image,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,image));}
image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
return image;};OpenLayers.Util.setOpacity=function(element,opacity){OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);};OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||(this.map&&this.viewRequestID==this.map.viewRequestID)){this.style.display="";}
OpenLayers.Element.removeClass(this,"olImageLoadError");};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.onImageLoadError=function(){this._attempts=(this._attempts)?(this._attempts+1):1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){var urls=this.urls;if(urls&&urls instanceof Array&&urls.length>1){var src=this.src.toString();var current_url,k;for(k=0;current_url=urls[k];k++){if(src.indexOf(current_url)!=-1){break;}}
var guess=Math.floor(urls.length*Math.random());var new_url=urls[guess];k=0;while(new_url==current_url&&k++<4){guess=Math.floor(urls.length*Math.random());new_url=urls[guess];}
this.src=src.replace(current_url,new_url);}else{this.src=this.src;}}else{OpenLayers.Element.addClass(this,"olImageLoadError");}
this.style.display="";};OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=!!(document.body.filters);}catch(e){}
OpenLayers.Util.alphaHackNeeded=(filter&&(version>=5.5)&&(version<7));}
return OpenLayers.Util.alphaHackNeeded;};OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz,position,null,null,opacity);var img=div.childNodes[0];if(imgURL){img.src=imgURL;}
OpenLayers.Util.modifyDOMElement(img,div.id+"_innerImage",null,sz,"relative",border);if(OpenLayers.Util.alphaHack()){if(div.style.display!="none"){div.style.display="inline-block";}
if(sizing==null){sizing="scale";}
div.style.filter="progid:DXImageTransform.Microsoft"+".AlphaImageLoader(src='"+img.src+"', "+"sizingMethod='"+sizing+"')";if(parseFloat(div.style.opacity)>=0.0&&parseFloat(div.style.opacity)<1.0){div.style.filter+=" alpha(opacity="+div.style.opacity*100+")";}
img.style.filter="alpha(opacity=0)";}};OpenLayers.Util.createAlphaImageDiv=function(id,px,sz,imgURL,position,border,sizing,opacity,delayDisplay){var div=OpenLayers.Util.createDiv();var img=OpenLayers.Util.createImage(null,null,null,null,null,null,null,false);div.appendChild(img);if(delayDisplay){img.style.display="none";OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,div));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,div));}
OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};OpenLayers.Util.upperCaseObject=function(object){var uObject={};for(var key in object){uObject[key.toUpperCase()]=object[key];}
return uObject;};OpenLayers.Util.applyDefaults=function(to,from){to=to||{};var fromIsEvt=typeof window.Event=="function"&&from instanceof window.Event;for(var key in from){if(to[key]===undefined||(!fromIsEvt&&from.hasOwnProperty&&from.hasOwnProperty(key)&&!to.hasOwnProperty(key))){to[key]=from[key];}}
if(!fromIsEvt&&from&&from.hasOwnProperty&&from.hasOwnProperty('toString')&&!to.hasOwnProperty('toString')){to.toString=from.toString;}
return to;};OpenLayers.Util.getParameterString=function(params){var paramsArray=[];for(var key in params){var value=params[key];if((value!=null)&&(typeof value!='function')){var encodedValue;if(typeof value=='object'&&value.constructor==Array){var encodedItemArray=[];var item;for(var itemIndex=0,len=value.length;itemIndex<len;itemIndex++){item=value[itemIndex];encodedItemArray.push(encodeURIComponent((item===null||item===undefined)?"":item));}
encodedValue=encodedItemArray.join(",");}
else{encodedValue=encodeURIComponent(value);}
paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
return paramsArray.join("&");};OpenLayers.Util.urlAppend=function(url,paramStr){var newUrl=url;if(paramStr){var parts=(url+" ").split(/[?&]/);newUrl+=(parts.pop()===" "?paramStr:parts.length?"&"+paramStr:"?"+paramStr);}
return newUrl;};OpenLayers.ImgPath='';OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0,len=arguments.length;i<len;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
return returnValue;};OpenLayers.Util.getNodes=function(p,tagName){var nodes=OpenLayers.Util.Try(function(){return OpenLayers.Util._getNodes(p.documentElement.childNodes,tagName);},function(){return OpenLayers.Util._getNodes(p.childNodes,tagName);});return nodes;};OpenLayers.Util._getNodes=function(nodes,tagName){var retArray=[];for(var i=0,len=nodes.length;i<len;i++){if(nodes[i].nodeName==tagName){retArray.push(nodes[i]);}}
return retArray;};OpenLayers.Util.getTagText=function(parent,item,index){var result=OpenLayers.Util.getNodes(parent,item);if(result&&(result.length>0))
{if(!index){index=0;}
if(result[index].childNodes.length>1){return result.childNodes[1].nodeValue;}
else if(result[index].childNodes.length==1){return result[index].firstChild.nodeValue;}}else{return"";}};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val){val=node.textContent;}
if(!val){val=node.firstChild.nodeValue;}},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
return(target!=div);};OpenLayers.Util.DEFAULT_PRECISION=14;OpenLayers.Util.toFloat=function(number,precision){if(precision==null){precision=OpenLayers.Util.DEFAULT_PRECISION;}
var number;if(precision==0){number=parseFloat(number);}else{number=parseFloat(parseFloat(number).toPrecision(precision));}
return number;};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.deg=function(x){return x*180/Math.PI;};OpenLayers.Util.VincentyConstants={a:6378137,b:6356752.3142,f:1/298.257223563};OpenLayers.Util.distVincenty=function(p1,p2){var ct=OpenLayers.Util.VincentyConstants;var a=ct.a,b=ct.b,f=ct.f;var L=OpenLayers.Util.rad(p2.lon-p1.lon);var U1=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p1.lat)));var U2=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p2.lat)));var sinU1=Math.sin(U1),cosU1=Math.cos(U1);var sinU2=Math.sin(U2),cosU2=Math.cos(U2);var lambda=L,lambdaP=2*Math.PI;var iterLimit=20;while(Math.abs(lambda-lambdaP)>1e-12&&--iterLimit>0){var sinLambda=Math.sin(lambda),cosLambda=Math.cos(lambda);var sinSigma=Math.sqrt((cosU2*sinLambda)*(cosU2*sinLambda)+
(cosU1*sinU2-sinU1*cosU2*cosLambda)*(cosU1*sinU2-sinU1*cosU2*cosLambda));if(sinSigma==0){return 0;}
var cosSigma=sinU1*sinU2+cosU1*cosU2*cosLambda;var sigma=Math.atan2(sinSigma,cosSigma);var alpha=Math.asin(cosU1*cosU2*sinLambda/sinSigma);var cosSqAlpha=Math.cos(alpha)*Math.cos(alpha);var cos2SigmaM=cosSigma-2*sinU1*sinU2/cosSqAlpha;var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));lambdaP=lambda;lambda=L+(1-C)*f*Math.sin(alpha)*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));}
if(iterLimit==0){return NaN;}
var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));var s=b*A*(sigma-deltaSigma);var d=s.toFixed(3)/1000;return d;};OpenLayers.Util.destinationVincenty=function(lonlat,brng,dist){var u=OpenLayers.Util;var ct=u.VincentyConstants;var a=ct.a,b=ct.b,f=ct.f;var lon1=lonlat.lon;var lat1=lonlat.lat;var s=dist;var alpha1=u.rad(brng);var sinAlpha1=Math.sin(alpha1);var cosAlpha1=Math.cos(alpha1);var tanU1=(1-f)*Math.tan(u.rad(lat1));var cosU1=1/Math.sqrt((1+tanU1*tanU1)),sinU1=tanU1*cosU1;var sigma1=Math.atan2(tanU1,cosAlpha1);var sinAlpha=cosU1*sinAlpha1;var cosSqAlpha=1-sinAlpha*sinAlpha;var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var sigma=s/(b*A),sigmaP=2*Math.PI;while(Math.abs(sigma-sigmaP)>1e-12){var cos2SigmaM=Math.cos(2*sigma1+sigma);var sinSigma=Math.sin(sigma);var cosSigma=Math.cos(sigma);var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));sigmaP=sigma;sigma=s/(b*A)+deltaSigma;}
var tmp=sinU1*sinSigma-cosU1*cosSigma*cosAlpha1;var lat2=Math.atan2(sinU1*cosSigma+cosU1*sinSigma*cosAlpha1,(1-f)*Math.sqrt(sinAlpha*sinAlpha+tmp*tmp));var lambda=Math.atan2(sinSigma*sinAlpha1,cosU1*cosSigma-sinU1*sinSigma*cosAlpha1);var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));var L=lambda-(1-C)*f*sinAlpha*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));var revAz=Math.atan2(sinAlpha,-tmp);return new OpenLayers.LonLat(lon1+u.deg(L),u.deg(lat2));};OpenLayers.Util.getParameters=function(url){url=url||window.location.href;var paramsString="";if(OpenLayers.String.contains(url,'?')){var start=url.indexOf('?')+1;var end=OpenLayers.String.contains(url,"#")?url.indexOf('#'):url.length;paramsString=url.substring(start,end);}
var parameters={};var pairs=paramsString.split(/[&;]/);for(var i=0,len=pairs.length;i<len;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=decodeURIComponent(keyValue[0]);var value=keyValue[1]||'';value=decodeURIComponent(value.replace(/\+/g," ")).split(",");if(value.length==1){value=value[0];}
parameters[key]=value;}}
return parameters;};OpenLayers.Util.getArgs=function(url){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.Util.getParameters'}));return OpenLayers.Util.getParameters(url);};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}
OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.3701,'km':39370.1,'dd':4374754,'yd':36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT["nmi"]=1852*OpenLayers.INCHES_PER_UNIT.m;OpenLayers.METERS_PER_INCH=0.02540005080010160020;OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{"Inch":OpenLayers.INCHES_PER_UNIT.inches,"Meter":1.0/OpenLayers.METERS_PER_INCH,"Foot":0.30480060960121920243/OpenLayers.METERS_PER_INCH,"IFoot":0.30480000000000000000/OpenLayers.METERS_PER_INCH,"ClarkeFoot":0.3047972651151/OpenLayers.METERS_PER_INCH,"SearsFoot":0.30479947153867624624/OpenLayers.METERS_PER_INCH,"GoldCoastFoot":0.30479971018150881758/OpenLayers.METERS_PER_INCH,"IInch":0.02540000000000000000/OpenLayers.METERS_PER_INCH,"MicroInch":0.00002540000000000000/OpenLayers.METERS_PER_INCH,"Mil":0.00000002540000000000/OpenLayers.METERS_PER_INCH,"Centimeter":0.01000000000000000000/OpenLayers.METERS_PER_INCH,"Kilometer":1000.00000000000000000000/OpenLayers.METERS_PER_INCH,"Yard":0.91440182880365760731/OpenLayers.METERS_PER_INCH,"SearsYard":0.914398414616029/OpenLayers.METERS_PER_INCH,"IndianYard":0.91439853074444079983/OpenLayers.METERS_PER_INCH,"IndianYd37":0.91439523/OpenLayers.METERS_PER_INCH,"IndianYd62":0.9143988/OpenLayers.METERS_PER_INCH,"IndianYd75":0.9143985/OpenLayers.METERS_PER_INCH,"IndianFoot":0.30479951/OpenLayers.METERS_PER_INCH,"IndianFt37":0.30479841/OpenLayers.METERS_PER_INCH,"IndianFt62":0.3047996/OpenLayers.METERS_PER_INCH,"IndianFt75":0.3047995/OpenLayers.METERS_PER_INCH,"Mile":1609.34721869443738887477/OpenLayers.METERS_PER_INCH,"IYard":0.91440000000000000000/OpenLayers.METERS_PER_INCH,"IMile":1609.34400000000000000000/OpenLayers.METERS_PER_INCH,"NautM":1852.00000000000000000000/OpenLayers.METERS_PER_INCH,"Lat-66":110943.316488932731/OpenLayers.METERS_PER_INCH,"Lat-83":110946.25736872234125/OpenLayers.METERS_PER_INCH,"Decimeter":0.10000000000000000000/OpenLayers.METERS_PER_INCH,"Millimeter":0.00100000000000000000/OpenLayers.METERS_PER_INCH,"Dekameter":10.00000000000000000000/OpenLayers.METERS_PER_INCH,"Decameter":10.00000000000000000000/OpenLayers.METERS_PER_INCH,"Hectometer":100.00000000000000000000/OpenLayers.METERS_PER_INCH,"GermanMeter":1.0000135965/OpenLayers.METERS_PER_INCH,"CaGrid":0.999738/OpenLayers.METERS_PER_INCH,"ClarkeChain":20.1166194976/OpenLayers.METERS_PER_INCH,"GunterChain":20.11684023368047/OpenLayers.METERS_PER_INCH,"BenoitChain":20.116782494375872/OpenLayers.METERS_PER_INCH,"SearsChain":20.11676512155/OpenLayers.METERS_PER_INCH,"ClarkeLink":0.201166194976/OpenLayers.METERS_PER_INCH,"GunterLink":0.2011684023368047/OpenLayers.METERS_PER_INCH,"BenoitLink":0.20116782494375872/OpenLayers.METERS_PER_INCH,"SearsLink":0.2011676512155/OpenLayers.METERS_PER_INCH,"Rod":5.02921005842012/OpenLayers.METERS_PER_INCH,"IntnlChain":20.1168/OpenLayers.METERS_PER_INCH,"IntnlLink":0.201168/OpenLayers.METERS_PER_INCH,"Perch":5.02921005842012/OpenLayers.METERS_PER_INCH,"Pole":5.02921005842012/OpenLayers.METERS_PER_INCH,"Furlong":201.1684023368046/OpenLayers.METERS_PER_INCH,"Rood":3.778266898/OpenLayers.METERS_PER_INCH,"CapeFoot":0.3047972615/OpenLayers.METERS_PER_INCH,"Brealey":375.00000000000000000000/OpenLayers.METERS_PER_INCH,"ModAmFt":0.304812252984505969011938/OpenLayers.METERS_PER_INCH,"Fathom":1.8288/OpenLayers.METERS_PER_INCH,"NautM-UK":1853.184/OpenLayers.METERS_PER_INCH,"50kilometers":50000.0/OpenLayers.METERS_PER_INCH,"150kilometers":150000.0/OpenLayers.METERS_PER_INCH});OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{"mm":OpenLayers.INCHES_PER_UNIT["Meter"]/1000.0,"cm":OpenLayers.INCHES_PER_UNIT["Meter"]/100.0,"dm":OpenLayers.INCHES_PER_UNIT["Meter"]*100.0,"km":OpenLayers.INCHES_PER_UNIT["Meter"]*1000.0,"kmi":OpenLayers.INCHES_PER_UNIT["nmi"],"fath":OpenLayers.INCHES_PER_UNIT["Fathom"],"ch":OpenLayers.INCHES_PER_UNIT["IntnlChain"],"link":OpenLayers.INCHES_PER_UNIT["IntnlLink"],"us-in":OpenLayers.INCHES_PER_UNIT["inches"],"us-ft":OpenLayers.INCHES_PER_UNIT["Foot"],"us-yd":OpenLayers.INCHES_PER_UNIT["Yard"],"us-ch":OpenLayers.INCHES_PER_UNIT["GunterChain"],"us-mi":OpenLayers.INCHES_PER_UNIT["Mile"],"ind-yd":OpenLayers.INCHES_PER_UNIT["IndianYd37"],"ind-ft":OpenLayers.INCHES_PER_UNIT["IndianFt37"],"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){var resolution;if(scale){if(units==null){units="degrees";}
var normScale=OpenLayers.Util.normalizeScale(scale);resolution=1/(normScale*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH);}
return resolution;};OpenLayers.Util.getScaleFromResolution=function(resolution,units){if(units==null){units="degrees";}
var scale=resolution*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH;return scale;};OpenLayers.Util.safeStopPropagation=function(evt){OpenLayers.Event.stop(evt,true);};OpenLayers.Util.pagePosition=function(forElement){var valueT=0,valueL=0;var element=forElement;var child=forElement;while(element){if(element==document.body){if(OpenLayers.Element.getStyle(child,'position')=='absolute'){break;}}
valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;child=element;try{element=element.offsetParent;}catch(e){OpenLayers.Console.error(OpenLayers.i18n("pagePositionFailed",{'elemId':element.id}));break;}}
element=forElement;while(element){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;element=element.parentNode;}
return[valueL,valueT];};OpenLayers.Util.isEquivalentUrl=function(url1,url2,options){options=options||{};OpenLayers.Util.applyDefaults(options,{ignoreCase:true,ignorePort80:true,ignoreHash:true});var urlObj1=OpenLayers.Util.createUrlObject(url1,options);var urlObj2=OpenLayers.Util.createUrlObject(url2,options);for(var key in urlObj1){if(key!=="args"){if(urlObj1[key]!=urlObj2[key]){return false;}}}
for(var key in urlObj1.args){if(urlObj1.args[key]!=urlObj2.args[key]){return false;}
delete urlObj2.args[key];}
for(var key in urlObj2.args){return false;}
return true;};OpenLayers.Util.createUrlObject=function(url,options){options=options||{};if(!(/^\w+:\/\//).test(url)){var loc=window.location;var port=loc.port?":"+loc.port:"";var fullUrl=loc.protocol+"//"+loc.host.split(":").shift()+port;if(url.indexOf("/")===0){url=fullUrl+url;}else{var parts=loc.pathname.split("/");parts.pop();url=fullUrl+parts.join("/")+"/"+url;}}
if(options.ignoreCase){url=url.toLowerCase();}
var a=document.createElement('a');a.href=url;var urlObject={};urlObject.host=a.host.split(":").shift();urlObject.protocol=a.protocol;if(options.ignorePort80){urlObject.port=(a.port=="80"||a.port=="0")?"":a.port;}else{urlObject.port=(a.port==""||a.port=="0")?"80":a.port;}
urlObject.hash=(options.ignoreHash||a.hash==="#")?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
urlObject.args=OpenLayers.Util.getParameters(queryString);urlObject.pathname=(a.pathname.charAt(0)=="/")?a.pathname:"/"+a.pathname;return urlObject;};OpenLayers.Util.removeTail=function(url){var head=null;var qMark=url.indexOf("?");var hashMark=url.indexOf("#");if(qMark==-1){head=(hashMark!=-1)?url.substr(0,hashMark):url;}else{head=(hashMark!=-1)?url.substr(0,Math.min(qMark,hashMark)):url.substr(0,qMark);}
return head;};OpenLayers.Util.getBrowserName=function(){var browserName="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){browserName="opera";}else if(ua.indexOf("msie")!=-1){browserName="msie";}else if(ua.indexOf("safari")!=-1){browserName="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){browserName="firefox";}else{browserName="mozilla";}}
return browserName;};OpenLayers.Util.getRenderedDimensions=function(contentHTML,size,options){var w,h;var container=document.createElement("div");container.style.visibility="hidden";var containerElement=(options&&options.containerElement)?options.containerElement:document.body;if(size){if(size.w){w=size.w;container.style.width=w+"px";}else if(size.h){h=size.h;container.style.height=h+"px";}}
if(options&&options.displayClass){container.className=options.displayClass;}
var content=document.createElement("div");content.innerHTML=contentHTML;content.style.overflow="visible";if(content.childNodes){for(var i=0,l=content.childNodes.length;i<l;i++){if(!content.childNodes[i].style)continue;content.childNodes[i].style.overflow="visible";}}
container.appendChild(content);containerElement.appendChild(container);var parentHasPositionAbsolute=false;var parent=container.parentNode;while(parent&&parent.tagName.toLowerCase()!="body"){var parentPosition=OpenLayers.Element.getStyle(parent,"position");if(parentPosition=="absolute"){parentHasPositionAbsolute=true;break;}else if(parentPosition&&parentPosition!="static"){break;}
parent=parent.parentNode;}
if(!parentHasPositionAbsolute){container.style.position="absolute";}
if(!w){w=parseInt(content.scrollWidth);container.style.width=w+"px";}
if(!h){h=parseInt(content.scrollHeight);}
container.removeChild(content);containerElement.removeChild(container);return new OpenLayers.Size(w,h);};OpenLayers.Util.getScrollbarWidth=function(){var scrollbarWidth=OpenLayers.Util._scrollbarWidth;if(scrollbarWidth==null){var scr=null;var inn=null;var wNoScroll=0;var wScroll=0;scr=document.createElement('div');scr.style.position='absolute';scr.style.top='-1000px';scr.style.left='-1000px';scr.style.width='100px';scr.style.height='50px';scr.style.overflow='hidden';inn=document.createElement('div');inn.style.width='100%';inn.style.height='200px';scr.appendChild(inn);document.body.appendChild(scr);wNoScroll=inn.offsetWidth;scr.style.overflow='scroll';wScroll=inn.offsetWidth;document.body.removeChild(document.body.lastChild);OpenLayers.Util._scrollbarWidth=(wNoScroll-wScroll);scrollbarWidth=OpenLayers.Util._scrollbarWidth;}
return scrollbarWidth;};OpenLayers.Util.getFormattedLonLat=function(coordinate,axis,dmsOption){if(!dmsOption){dmsOption='dms';}
var abscoordinate=Math.abs(coordinate)
var coordinatedegrees=Math.floor(abscoordinate);var coordinateminutes=(abscoordinate-coordinatedegrees)/(1/60);var tempcoordinateminutes=coordinateminutes;coordinateminutes=Math.floor(coordinateminutes);var coordinateseconds=(tempcoordinateminutes-coordinateminutes)/(1/60);coordinateseconds=Math.round(coordinateseconds*10);coordinateseconds/=10;if(coordinatedegrees<10){coordinatedegrees="0"+coordinatedegrees;}
var str=coordinatedegrees+"\u00B0";if(dmsOption.indexOf('dm')>=0){if(coordinateminutes<10){coordinateminutes="0"+coordinateminutes;}
str+=coordinateminutes+"'";if(dmsOption.indexOf('dms')>=0){if(coordinateseconds<10){coordinateseconds="0"+coordinateseconds;}
str+=coordinateseconds+'"';}}
if(axis=="lon"){str+=coordinate<0?OpenLayers.i18n("W"):OpenLayers.i18n("E");}else{str+=coordinate<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");}
return str;};OpenLayers.Rico=new Object();OpenLayers.Rico.Corner={round:function(e,options){e=OpenLayers.Util.getElement(e);this._setOptions(options);var color=this.options.color;if(this.options.color=="fromElement"){color=this._background(e);}
var bgColor=this.options.bgColor;if(this.options.bgColor=="fromParent"){bgColor=this._background(e.offsetParent);}
this._roundCornersImpl(e,color,bgColor);},changeColor:function(theDiv,newColor){theDiv.style.backgroundColor=newColor;var spanElements=theDiv.parentNode.getElementsByTagName("span");for(var currIdx=0;currIdx<spanElements.length;currIdx++){spanElements[currIdx].style.backgroundColor=newColor;}},changeOpacity:function(theDiv,newOpacity){var mozillaOpacity=newOpacity;var ieOpacity='alpha(opacity='+newOpacity*100+')';theDiv.style.opacity=mozillaOpacity;theDiv.style.filter=ieOpacity;var spanElements=theDiv.parentNode.getElementsByTagName("span");for(var currIdx=0;currIdx<spanElements.length;currIdx++){spanElements[currIdx].style.opacity=mozillaOpacity;spanElements[currIdx].style.filter=ieOpacity;}},reRound:function(theDiv,options){var topRico=theDiv.parentNode.childNodes[0];var bottomRico=theDiv.parentNode.childNodes[2];theDiv.parentNode.removeChild(topRico);theDiv.parentNode.removeChild(bottomRico);this.round(theDiv.parentNode,options);},_roundCornersImpl:function(e,color,bgColor){if(this.options.border){this._renderBorder(e,bgColor);}
if(this._isTopRounded()){this._roundTopCorners(e,color,bgColor);}
if(this._isBottomRounded()){this._roundBottomCorners(e,color,bgColor);}},_renderBorder:function(el,bgColor){var borderValue="1px solid "+this._borderColor(bgColor);var borderL="border-left: "+borderValue;var borderR="border-right: "+borderValue;var style="style='"+borderL+";"+borderR+"'";el.innerHTML="<div "+style+">"+el.innerHTML+"</div>";},_roundTopCorners:function(el,color,bgColor){var corner=this._createCorner(bgColor);for(var i=0;i<this.options.numSlices;i++){corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));}
el.style.paddingTop=0;el.insertBefore(corner,el.firstChild);},_roundBottomCorners:function(el,color,bgColor){var corner=this._createCorner(bgColor);for(var i=(this.options.numSlices-1);i>=0;i--){corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));}
el.style.paddingBottom=0;el.appendChild(corner);},_createCorner:function(bgColor){var corner=document.createElement("div");corner.style.backgroundColor=(this._isTransparent()?"transparent":bgColor);return corner;},_createCornerSlice:function(color,bgColor,n,position){var slice=document.createElement("span");var inStyle=slice.style;inStyle.backgroundColor=color;inStyle.display="block";inStyle.height="1px";inStyle.overflow="hidden";inStyle.fontSize="1px";var borderColor=this._borderColor(color,bgColor);if(this.options.border&&n==0){inStyle.borderTopStyle="solid";inStyle.borderTopWidth="1px";inStyle.borderLeftWidth="0px";inStyle.borderRightWidth="0px";inStyle.borderBottomWidth="0px";inStyle.height="0px";inStyle.borderColor=borderColor;}
else if(borderColor){inStyle.borderColor=borderColor;inStyle.borderStyle="solid";inStyle.borderWidth="0px 1px";}
if(!this.options.compact&&(n==(this.options.numSlices-1))){inStyle.height="2px";}
this._setMargin(slice,n,position);this._setBorder(slice,n,position);return slice;},_setOptions:function(options){this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:true,border:false,compact:false};OpenLayers.Util.extend(this.options,options||{});this.options.numSlices=this.options.compact?2:4;if(this._isTransparent()){this.options.blend=false;}},_whichSideTop:function(){if(this._hasString(this.options.corners,"all","top")){return"";}
if(this.options.corners.indexOf("tl")>=0&&this.options.corners.indexOf("tr")>=0){return"";}
if(this.options.corners.indexOf("tl")>=0){return"left";}else if(this.options.corners.indexOf("tr")>=0){return"right";}
return"";},_whichSideBottom:function(){if(this._hasString(this.options.corners,"all","bottom")){return"";}
if(this.options.corners.indexOf("bl")>=0&&this.options.corners.indexOf("br")>=0){return"";}
if(this.options.corners.indexOf("bl")>=0){return"left";}else if(this.options.corners.indexOf("br")>=0){return"right";}
return"";},_borderColor:function(color,bgColor){if(color=="transparent"){return bgColor;}else if(this.options.border){return this.options.border;}else if(this.options.blend){return this._blend(bgColor,color);}else{return"";}},_setMargin:function(el,n,corners){var marginSize=this._marginSize(n);var whichSide=corners=="top"?this._whichSideTop():this._whichSideBottom();if(whichSide=="left"){el.style.marginLeft=marginSize+"px";el.style.marginRight="0px";}
else if(whichSide=="right"){el.style.marginRight=marginSize+"px";el.style.marginLeft="0px";}
else{el.style.marginLeft=marginSize+"px";el.style.marginRight=marginSize+"px";}},_setBorder:function(el,n,corners){var borderSize=this._borderSize(n);var whichSide=corners=="top"?this._whichSideTop():this._whichSideBottom();if(whichSide=="left"){el.style.borderLeftWidth=borderSize+"px";el.style.borderRightWidth="0px";}
else if(whichSide=="right"){el.style.borderRightWidth=borderSize+"px";el.style.borderLeftWidth="0px";}
else{el.style.borderLeftWidth=borderSize+"px";el.style.borderRightWidth=borderSize+"px";}
if(this.options.border!=false){el.style.borderLeftWidth=borderSize+"px";el.style.borderRightWidth=borderSize+"px";}},_marginSize:function(n){if(this._isTransparent()){return 0;}
var marginSizes=[5,3,2,1];var blendedMarginSizes=[3,2,1,0];var compactMarginSizes=[2,1];var smBlendedMarginSizes=[1,0];if(this.options.compact&&this.options.blend){return smBlendedMarginSizes[n];}else if(this.options.compact){return compactMarginSizes[n];}else if(this.options.blend){return blendedMarginSizes[n];}else{return marginSizes[n];}},_borderSize:function(n){var transparentBorderSizes=[5,3,2,1];var blendedBorderSizes=[2,1,1,1];var compactBorderSizes=[1,0];var actualBorderSizes=[0,2,0,0];if(this.options.compact&&(this.options.blend||this._isTransparent())){return 1;}else if(this.options.compact){return compactBorderSizes[n];}else if(this.options.blend){return blendedBorderSizes[n];}else if(this.options.border){return actualBorderSizes[n];}else if(this._isTransparent()){return transparentBorderSizes[n];}
return 0;},_hasString:function(str){for(var i=1;i<arguments.length;i++)if(str.indexOf(arguments[i])>=0){return true;}return false;},_blend:function(c1,c2){var cc1=OpenLayers.Rico.Color.createFromHex(c1);cc1.blend(OpenLayers.Rico.Color.createFromHex(c2));return cc1;},_background:function(el){try{return OpenLayers.Rico.Color.createColorFromBackground(el).asHex();}catch(err){return"#ffffff";}},_isTransparent:function(){return this.options.color=="transparent";},_isTopRounded:function(){return this._hasString(this.options.corners,"all","top","tl","tr");},_isBottomRounded:function(){return this._hasString(this.options.corners,"all","bottom","bl","br");},_hasSingleTextChild:function(el){return el.childNodes.length==1&&el.childNodes[0].nodeType==3;}};(function(){if(window.google&&google.gears){return;}
var factory=null;if(typeof GearsFactory!='undefined'){factory=new GearsFactory();}else{try{factory=new ActiveXObject('Gears.Factory');if(factory.getBuildInfo().indexOf('ie_mobile')!=-1){factory.privateSetGlobalObject(this);}}catch(e){if((typeof navigator.mimeTypes!='undefined')&&navigator.mimeTypes["application/x-googlegears"]){factory=document.createElement("object");factory.style.display="none";factory.width=0;factory.height=0;factory.type="application/x-googlegears";document.documentElement.appendChild(factory);}}}
if(!factory){return;}
if(!window.google){google={};}
if(!google.gears){google.gears={factory:factory};}})();OpenLayers.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0,len=arguments.length;i<len;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'hide':'show';OpenLayers.Element[display](element);}},hide:function(){for(var i=0,len=arguments.length;i<len;i++){var element=OpenLayers.Util.getElement(arguments[i]);if(element){element.style.display='none';}}},show:function(){for(var i=0,len=arguments.length;i<len;i++){var element=OpenLayers.Util.getElement(arguments[i]);if(element){element.style.display='';}}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},getDimensions:function(element){element=OpenLayers.Util.getElement(element);if(OpenLayers.Element.getStyle(element,'display')!='none'){return{width:element.offsetWidth,height:element.offsetHeight};}
var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;var originalDisplay=els.display;els.visibility='hidden';els.position='absolute';els.display='';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display=originalDisplay;els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},hasClass:function(element,name){var names=element.className;return(!!names&&new RegExp("(^|\\s)"+name+"(\\s|$)").test(names));},addClass:function(element,name){if(!OpenLayers.Element.hasClass(element,name)){element.className+=(element.className?" ":"")+name;}
return element;},removeClass:function(element,name){var names=element.className;if(names){element.className=OpenLayers.String.trim(names.replace(new RegExp("(^|\\s+)"+name+"(\\s+|$)")," "));}
return element;},toggleClass:function(element,name){if(OpenLayers.Element.hasClass(element,name)){OpenLayers.Element.removeClass(element,name);}else{OpenLayers.Element.addClass(element,name);}
return element;},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=null;if(element&&element.style){value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}}
return value=='auto'?null:value;}};OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},equals:function(sz){var equals=false;if(sz!=null){equals=((this.w==sz.w&&this.h==sz.h)||(isNaN(this.w)&&isNaN(this.h)&&isNaN(sz.w)&&isNaN(sz.h)));}
return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(error){alert(error);},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){if(console){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=(size)?size:new OpenLayers.Size(20,20);this.offset=offset?offset:new OpenLayers.Pixel(-(this.size.w/2),-(this.size.h/2));this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
this.draw();},setUrl:function(url){if(url!=null){this.url=url;}
this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},erase:function(){if(this.imageDiv!=null&&this.imageDiv.parentNode!=null){OpenLayers.Element.remove(this.imageDiv);}},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
var offsetPx=this.px.offset(this.offset);OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,offsetPx);}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},isDrawn:function(){var isDrawn=(this.imageDiv&&this.imageDiv.parentNode&&(this.imageDiv.parentNode.nodeType!=11));return isDrawn;},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:false,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:false,fixPadding:function(){if(typeof this.padding=="number"){this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding);}},panMapIfOutOfView:false,keepInMap:false,closeOnMove:false,map:null,initialize:function(id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
this.id=id;this.lonlat=lonlat;this.contentSize=(contentSize!=null)?contentSize:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);if(contentHTML!=null){this.contentHTML=contentHTML;}
this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;var groupDivId=this.id+"_GroupDiv";this.groupDiv=OpenLayers.Util.createDiv(groupDivId,null,null,null,"relative",null,"hidden");var id=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(id,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);if(closeBox){this.addCloseBox(closeBoxCallback);}
this.registerEvents();},destroy:function(){this.id=null;this.lonlat=null;this.size=null;this.contentHTML=null;this.backgroundColor=null;this.opacity=null;this.border=null;if(this.closeOnMove&&this.map){this.map.events.unregister("movestart",this,this.hide);}
this.events.destroy();this.events=null;if(this.closeDiv){OpenLayers.Event.stopObservingElement(this.closeDiv);this.groupDiv.removeChild(this.closeDiv);}
this.closeDiv=null;this.div.removeChild(this.groupDiv);this.groupDiv=null;if(this.map!=null){this.map.removePopup(this);}
this.map=null;this.div=null;this.autoSize=null;this.minSize=null;this.maxSize=null;this.padding=null;this.panMapIfOutOfView=null;},draw:function(px){if(px==null){if((this.lonlat!=null)&&(this.map!=null)){px=this.map.getLayerPxFromLonLat(this.lonlat);}}
if(this.closeOnMove){this.map.events.register("movestart",this,this.hide);}
if(!this.disableFirefoxOverflowHack&&OpenLayers.Util.getBrowserName()=='firefox'){this.map.events.register("movestart",this,function(){var style=document.defaultView.getComputedStyle(this.contentDiv,null);var currentOverflow=style.getPropertyValue("overflow");if(currentOverflow!="hidden"){this.contentDiv._oldOverflow=currentOverflow;this.contentDiv.style.overflow="hidden";}});this.map.events.register("moveend",this,function(){var oldOverflow=this.contentDiv._oldOverflow;if(oldOverflow){this.contentDiv.style.overflow=oldOverflow;this.contentDiv._oldOverflow=null;}});}
this.moveTo(px);if(!this.autoSize&&!this.size){this.setSize(this.contentSize);}
this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();if(this.panMapIfOutOfView){this.panIntoView();}
return this.div;},updatePosition:function(){if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);if(px){this.moveTo(px);}}},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},visible:function(){return OpenLayers.Element.visible(this.div);},toggle:function(){if(this.visible()){this.hide();}else{this.show();}},show:function(){OpenLayers.Element.show(this.div);if(this.panMapIfOutOfView){this.panIntoView();}},hide:function(){OpenLayers.Element.hide(this.div);},setSize:function(contentSize){this.size=contentSize.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;this.fixPadding();wPadding+=this.padding.left+this.padding.right;hPadding+=this.padding.top+this.padding.bottom;if(this.closeDiv){var closeDivWidth=parseInt(this.closeDiv.style.width);wPadding+=closeDivWidth+contentDivPadding.right;}
this.size.w+=wPadding;this.size.h+=hPadding;if(OpenLayers.Util.getBrowserName()=="msie"){this.contentSize.w+=contentDivPadding.left+contentDivPadding.right;this.contentSize.h+=contentDivPadding.bottom+contentDivPadding.top;}
if(this.div!=null){this.div.style.width=this.size.w+"px";this.div.style.height=this.size.h+"px";}
if(this.contentDiv!=null){this.contentDiv.style.width=contentSize.w+"px";this.contentDiv.style.height=contentSize.h+"px";}},updateSize:function(){var preparedHTML="<div class='"+this.contentDisplayClass+"'>"+
this.contentDiv.innerHTML+"</div>";var containerElement=(this.map)?this.map.layerContainerDiv:document.body;var realSize=OpenLayers.Util.getRenderedDimensions(preparedHTML,null,{displayClass:this.displayClass,containerElement:containerElement});var safeSize=this.getSafeContentSize(realSize);var newSize=null;if(safeSize.equals(realSize)){newSize=realSize;}else{var fixedSize=new OpenLayers.Size();fixedSize.w=(safeSize.w<realSize.w)?safeSize.w:null;fixedSize.h=(safeSize.h<realSize.h)?safeSize.h:null;if(fixedSize.w&&fixedSize.h){newSize=safeSize;}else{var clippedSize=OpenLayers.Util.getRenderedDimensions(preparedHTML,fixedSize,{displayClass:this.contentDisplayClass,containerElement:containerElement});var currentOverflow=OpenLayers.Element.getStyle(this.contentDiv,"overflow");if((currentOverflow!="hidden")&&(clippedSize.equals(safeSize))){var scrollBar=OpenLayers.Util.getScrollbarWidth();if(fixedSize.w){clippedSize.h+=scrollBar;}else{clippedSize.w+=scrollBar;}}
newSize=this.getSafeContentSize(clippedSize);}}
this.setSize(newSize);},setBackgroundColor:function(color){if(color!=undefined){this.backgroundColor=color;}
if(this.div!=null){this.div.style.backgroundColor=this.backgroundColor;}},setOpacity:function(opacity){if(opacity!=undefined){this.opacity=opacity;}
if(this.div!=null){this.div.style.opacity=this.opacity;this.div.style.filter='alpha(opacity='+this.opacity*100+')';}},setBorder:function(border){if(border!=undefined){this.border=border;}
if(this.div!=null){this.div.style.border=this.border;}},setContentHTML:function(contentHTML){if(contentHTML!=null){this.contentHTML=contentHTML;}
if((this.contentDiv!=null)&&(this.contentHTML!=null)&&(this.contentHTML!=this.contentDiv.innerHTML)){this.contentDiv.innerHTML=this.contentHTML;if(this.autoSize){this.registerImageListeners();this.updateSize();}}},registerImageListeners:function(){var onImgLoad=function(){this.popup.updateSize();if(this.popup.visible()&&this.popup.panMapIfOutOfView){this.popup.panIntoView();}
OpenLayers.Event.stopObserving(this.img,"load",this.img._onImageLoad);};var images=this.contentDiv.getElementsByTagName("img");for(var i=0,len=images.length;i<len;i++){var img=images[i];if(img.width==0||img.height==0){var context={'popup':this,'img':img};img._onImgLoad=OpenLayers.Function.bind(onImgLoad,context);OpenLayers.Event.observe(img,'load',img._onImgLoad);}}},getSafeContentSize:function(size){var safeContentSize=size.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;this.fixPadding();wPadding+=this.padding.left+this.padding.right;hPadding+=this.padding.top+this.padding.bottom;if(this.closeDiv){var closeDivWidth=parseInt(this.closeDiv.style.width);wPadding+=closeDivWidth+contentDivPadding.right;}
if(this.minSize){safeContentSize.w=Math.max(safeContentSize.w,(this.minSize.w-wPadding));safeContentSize.h=Math.max(safeContentSize.h,(this.minSize.h-hPadding));}
if(this.maxSize){safeContentSize.w=Math.min(safeContentSize.w,(this.maxSize.w-wPadding));safeContentSize.h=Math.min(safeContentSize.h,(this.maxSize.h-hPadding));}
if(this.map&&this.map.size){var extraX=0,extraY=0;if(this.keepInMap&&!this.panMapIfOutOfView){var px=this.map.getPixelFromLonLat(this.lonlat);switch(this.relativePosition){case"tr":extraX=px.x;extraY=this.map.size.h-px.y;break;case"tl":extraX=this.map.size.w-px.x;extraY=this.map.size.h-px.y;break;case"bl":extraX=this.map.size.w-px.x;extraY=px.y;break;case"br":extraX=px.x;extraY=px.y;break;default:extraX=px.x;extraY=this.map.size.h-px.y;break;}}
var maxY=this.map.size.h-
this.map.paddingForPopups.top-
this.map.paddingForPopups.bottom-
hPadding-extraY;var maxX=this.map.size.w-
this.map.paddingForPopups.left-
this.map.paddingForPopups.right-
wPadding-extraX;safeContentSize.w=Math.min(safeContentSize.w,maxX);safeContentSize.h=Math.min(safeContentSize.h,maxY);}
return safeContentSize;},getContentDivPadding:function(){var contentDivPadding=this._contentDivPadding;if(!contentDivPadding){if(this.div.parentNode==null){this.div.style.display="none";document.body.appendChild(this.div);}
contentDivPadding=new OpenLayers.Bounds(OpenLayers.Element.getStyle(this.contentDiv,"padding-left"),OpenLayers.Element.getStyle(this.contentDiv,"padding-bottom"),OpenLayers.Element.getStyle(this.contentDiv,"padding-right"),OpenLayers.Element.getStyle(this.contentDiv,"padding-top"));this._contentDivPadding=contentDivPadding;if(this.div.parentNode==document.body){document.body.removeChild(this.div);this.div.style.display="";}}
return contentDivPadding;},addCloseBox:function(callback){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,new OpenLayers.Size(17,17));this.closeDiv.className="olPopupCloseBox";var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+"px";this.closeDiv.style.top=contentDivPadding.top+"px";this.groupDiv.appendChild(this.closeDiv);var closePopup=callback||function(e){this.hide();OpenLayers.Event.stop(e);};OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(closePopup,this));},panIntoView:function(){var mapSize=this.map.getSize();var origTL=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top)));var newTL=origTL.clone();if(origTL.x<this.map.paddingForPopups.left){newTL.x=this.map.paddingForPopups.left;}else
if((origTL.x+this.size.w)>(mapSize.w-this.map.paddingForPopups.right)){newTL.x=mapSize.w-this.map.paddingForPopups.right-this.size.w;}
if(origTL.y<this.map.paddingForPopups.top){newTL.y=this.map.paddingForPopups.top;}else
if((origTL.y+this.size.h)>(mapSize.h-this.map.paddingForPopups.bottom)){newTL.y=mapSize.h-this.map.paddingForPopups.bottom-this.size.h;}
var dx=origTL.x-newTL.x;var dy=origTL.y-newTL.y;this.map.pan(dx,dy);},registerEvents:function(){this.events=new OpenLayers.Events(this,this.div,null,true);this.events.on({"mousedown":this.onmousedown,"mousemove":this.onmousemove,"mouseup":this.onmouseup,"click":this.onclick,"mouseout":this.onmouseout,"dblclick":this.ondblclick,scope:this});},onmousedown:function(evt){this.mousedown=true;OpenLayers.Event.stop(evt,true);},onmousemove:function(evt){if(this.mousedown){OpenLayers.Event.stop(evt,true);}},onmouseup:function(evt){if(this.mousedown){this.mousedown=false;OpenLayers.Event.stop(evt,true);}},onclick:function(evt){OpenLayers.Event.stop(evt,true);},onmouseout:function(evt){this.mousedown=false;},ondblclick:function(evt){OpenLayers.Event.stop(evt,true);},CLASS_NAME:"OpenLayers.Popup"});OpenLayers.Popup.WIDTH=200;OpenLayers.Popup.HEIGHT=200;OpenLayers.Popup.COLOR="white";OpenLayers.Popup.OPACITY=1;OpenLayers.Popup.BORDER="0px";OpenLayers.Protocol=OpenLayers.Class({format:null,options:null,autoDestroy:true,defaultFilter:null,initialize:function(options){options=options||{};OpenLayers.Util.extend(this,options);this.options=options;},mergeWithDefaultFilter:function(filter){var merged;if(filter&&this.defaultFilter){merged=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.defaultFilter,filter]});}else{merged=filter||this.defaultFilter||undefined;}
return merged;},destroy:function(){this.options=null;this.format=null;},read:function(options){options=options||{};options.filter=this.mergeWithDefaultFilter(options.filter);},create:function(){},update:function(){},"delete":function(){},commit:function(){},abort:function(response){},createCallback:function(method,response,options){return OpenLayers.Function.bind(function(){method.apply(this,[response,options]);},this);},CLASS_NAME:"OpenLayers.Protocol"});OpenLayers.Protocol.Response=OpenLayers.Class({code:null,requestType:null,last:true,features:null,reqFeatures:null,priv:null,initialize:function(options){OpenLayers.Util.extend(this,options);},success:function(){return this.code>0;},CLASS_NAME:"OpenLayers.Protocol.Response"});OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:false,size:null,resolution:null,map:null,initialize:function(containerID,options){this.container=OpenLayers.Util.getElement(containerID);},destroy:function(){this.container=null;this.extent=null;this.size=null;this.resolution=null;this.map=null;},supported:function(){return false;},setExtent:function(extent,resolutionChanged){this.extent=extent.clone();if(resolutionChanged){this.resolution=null;}},setSize:function(size){this.size=size.clone();this.resolution=null;},getResolution:function(){this.resolution=this.resolution||this.map.getResolution();return this.resolution;},drawFeature:function(feature,style){if(style==null){style=feature.style;}
if(feature.geometry){var bounds=feature.geometry.getBounds();if(bounds){if(!bounds.intersectsBounds(this.extent)){style={display:"none"};}
var rendered=this.drawGeometry(feature.geometry,style,feature.id);if(style.display!="none"&&style.label&&rendered!==false){var location=feature.geometry.getCentroid();if(style.labelXOffset||style.labelYOffset){xOffset=isNaN(style.labelXOffset)?0:style.labelXOffset;yOffset=isNaN(style.labelYOffset)?0:style.labelYOffset;var res=this.getResolution();location.move(xOffset*res,yOffset*res);}
this.drawText(feature.id,style,location);}else{this.removeText(feature.id);}
return rendered;}}},drawGeometry:function(geometry,style,featureId){},drawText:function(featureId,style,location){},removeText:function(featureId){},clear:function(){},getFeatureIdFromEvent:function(evt){},eraseFeatures:function(features){if(!(features instanceof Array)){features=[features];}
for(var i=0,len=features.length;i<len;++i){var feature=features[i];this.eraseGeometry(feature.geometry,feature.id);this.removeText(feature.id);}},eraseGeometry:function(geometry,featureId){},moveRoot:function(renderer){},getRenderLayerId:function(){return this.container.id;},applyDefaultSymbolizer:function(symbolizer){var result=OpenLayers.Util.extend({},OpenLayers.Renderer.defaultSymbolizer);if(symbolizer.stroke===false){delete result.strokeWidth;delete result.strokeColor;}
if(symbolizer.fill===false){delete result.fillColor;}
OpenLayers.Util.extend(result,symbolizer);return result;},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Renderer.defaultSymbolizer={fillColor:"#000000",strokeColor:"#000000",strokeWidth:2,fillOpacity:1,strokeOpacity:1,pointRadius:0};OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:true,autoDestroy:true,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;this.active=false;},destroy:function(){this.deactivate();this.layer=null;this.options=null;},setLayer:function(layer){this.layer=layer;},activate:function(){if(!this.active){this.active=true;return true;}
return false;},deactivate:function(){if(this.active){this.active=false;return true;}
return false;},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Symbolizer=OpenLayers.Class({zIndex:0,initialize:function(config){OpenLayers.Util.extend(this,config);},clone:function(){var Type=eval(this.CLASS_NAME);return new Type(OpenLayers.Util.extend({},this));},CLASS_NAME:"OpenLayers.Symbolizer"});OpenLayers.Rico.Color=OpenLayers.Class({initialize:function(red,green,blue){this.rgb={r:red,g:green,b:blue};},setRed:function(r){this.rgb.r=r;},setGreen:function(g){this.rgb.g=g;},setBlue:function(b){this.rgb.b=b;},setHue:function(h){var hsb=this.asHSB();hsb.h=h;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(hsb.h,hsb.s,hsb.b);},setSaturation:function(s){var hsb=this.asHSB();hsb.s=s;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(hsb.h,hsb.s,hsb.b);},setBrightness:function(b){var hsb=this.asHSB();hsb.b=b;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(hsb.h,hsb.s,hsb.b);},darken:function(percent){var hsb=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(hsb.h,hsb.s,Math.max(hsb.b-percent,0));},brighten:function(percent){var hsb=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(hsb.h,hsb.s,Math.min(hsb.b+percent,1));},blend:function(other){this.rgb.r=Math.floor((this.rgb.r+other.rgb.r)/2);this.rgb.g=Math.floor((this.rgb.g+other.rgb.g)/2);this.rgb.b=Math.floor((this.rgb.b+other.rgb.b)/2);},isBright:function(){var hsb=this.asHSB();return this.asHSB().b>0.5;},isDark:function(){return!this.isBright();},asRGB:function(){return"rgb("+this.rgb.r+","+this.rgb.g+","+this.rgb.b+")";},asHex:function(){return"#"+this.rgb.r.toColorPart()+this.rgb.g.toColorPart()+this.rgb.b.toColorPart();},asHSB:function(){return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r,this.rgb.g,this.rgb.b);},toString:function(){return this.asHex();}});OpenLayers.Rico.Color.createFromHex=function(hexCode){if(hexCode.length==4){var shortHexCode=hexCode;var hexCode='#';for(var i=1;i<4;i++){hexCode+=(shortHexCode.charAt(i)+
shortHexCode.charAt(i));}}
if(hexCode.indexOf('#')==0){hexCode=hexCode.substring(1);}
var red=hexCode.substring(0,2);var green=hexCode.substring(2,4);var blue=hexCode.substring(4,6);return new OpenLayers.Rico.Color(parseInt(red,16),parseInt(green,16),parseInt(blue,16));};OpenLayers.Rico.Color.createColorFromBackground=function(elem){var actualColor=RicoUtil.getElementsComputedStyle(OpenLayers.Util.getElement(elem),"backgroundColor","background-color");if(actualColor=="transparent"&&elem.parentNode){return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode);}
if(actualColor==null){return new OpenLayers.Rico.Color(255,255,255);}
if(actualColor.indexOf("rgb(")==0){var colors=actualColor.substring(4,actualColor.length-1);var colorArray=colors.split(",");return new OpenLayers.Rico.Color(parseInt(colorArray[0]),parseInt(colorArray[1]),parseInt(colorArray[2]));}
else if(actualColor.indexOf("#")==0){return OpenLayers.Rico.Color.createFromHex(actualColor);}
else{return new OpenLayers.Rico.Color(255,255,255);}};OpenLayers.Rico.Color.HSBtoRGB=function(hue,saturation,brightness){var red=0;var green=0;var blue=0;if(saturation==0){red=parseInt(brightness*255.0+0.5);green=red;blue=red;}
else{var h=(hue-Math.floor(hue))*6.0;var f=h-Math.floor(h);var p=brightness*(1.0-saturation);var q=brightness*(1.0-saturation*f);var t=brightness*(1.0-(saturation*(1.0-f)));switch(parseInt(h)){case 0:red=(brightness*255.0+0.5);green=(t*255.0+0.5);blue=(p*255.0+0.5);break;case 1:red=(q*255.0+0.5);green=(brightness*255.0+0.5);blue=(p*255.0+0.5);break;case 2:red=(p*255.0+0.5);green=(brightness*255.0+0.5);blue=(t*255.0+0.5);break;case 3:red=(p*255.0+0.5);green=(q*255.0+0.5);blue=(brightness*255.0+0.5);break;case 4:red=(t*255.0+0.5);green=(p*255.0+0.5);blue=(brightness*255.0+0.5);break;case 5:red=(brightness*255.0+0.5);green=(p*255.0+0.5);blue=(q*255.0+0.5);break;}}
return{r:parseInt(red),g:parseInt(green),b:parseInt(blue)};};OpenLayers.Rico.Color.RGBtoHSB=function(r,g,b){var hue;var saturation;var brightness;var cmax=(r>g)?r:g;if(b>cmax){cmax=b;}
var cmin=(r<g)?r:g;if(b<cmin){cmin=b;}
brightness=cmax/255.0;if(cmax!=0){saturation=(cmax-cmin)/cmax;}else{saturation=0;}
if(saturation==0){hue=0;}else{var redc=(cmax-r)/(cmax-cmin);var greenc=(cmax-g)/(cmax-cmin);var bluec=(cmax-b)/(cmax-cmin);if(r==cmax){hue=bluec-greenc;}else if(g==cmax){hue=2.0+redc-bluec;}else{hue=4.0+greenc-redc;}
hue=hue/6.0;if(hue<0){hue=hue+1.0;}}
return{h:hue,s:saturation,b:brightness};};OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,centerLonLat:null,initialize:function(left,bottom,right,top){if(left!=null){this.left=OpenLayers.Util.toFloat(left);}
if(bottom!=null){this.bottom=OpenLayers.Util.toFloat(bottom);}
if(right!=null){this.right=OpenLayers.Util.toFloat(right);}
if(top!=null){this.top=OpenLayers.Util.toFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},equals:function(bounds){var equals=false;if(bounds!=null){equals=((this.left==bounds.left)&&(this.right==bounds.right)&&(this.top==bounds.top)&&(this.bottom==bounds.bottom));}
return equals;},toString:function(){return("left-bottom=("+this.left+","+this.bottom+")"
+" right-top=("+this.right+","+this.top+")");},toArray:function(reverseAxisOrder){if(reverseAxisOrder===true){return[this.bottom,this.left,this.top,this.right];}else{return[this.left,this.bottom,this.right,this.top];}},toBBOX:function(decimal,reverseAxisOrder){if(decimal==null){decimal=6;}
var mult=Math.pow(10,decimal);var xmin=Math.round(this.left*mult)/mult;var ymin=Math.round(this.bottom*mult)/mult;var xmax=Math.round(this.right*mult)/mult;var ymax=Math.round(this.top*mult)/mult;if(reverseAxisOrder===true){return ymin+","+xmin+","+ymax+","+xmax;}else{return xmin+","+ymin+","+xmax+","+ymax;}},toGeometry:function(){return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(this.left,this.bottom),new OpenLayers.Geometry.Point(this.right,this.bottom),new OpenLayers.Geometry.Point(this.right,this.top),new OpenLayers.Geometry.Point(this.left,this.top)])]);},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){if(!this.centerLonLat){this.centerLonLat=new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);}
return this.centerLonLat;},scale:function(ratio,origin){if(origin==null){origin=this.getCenterLonLat();}
var origx,origy;if(origin.CLASS_NAME=="OpenLayers.LonLat"){origx=origin.lon;origy=origin.lat;}else{origx=origin.x;origy=origin.y;}
var left=(this.left-origx)*ratio+origx;var bottom=(this.bottom-origy)*ratio+origy;var right=(this.right-origx)*ratio+origx;var top=(this.top-origy)*ratio+origy;return new OpenLayers.Bounds(left,bottom,right,top);},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.i18n("boundsAddError");OpenLayers.Console.error(msg);return null;}
return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){var bounds=null;if(object){switch(object.CLASS_NAME){case"OpenLayers.LonLat":bounds=new OpenLayers.Bounds(object.lon,object.lat,object.lon,object.lat);break;case"OpenLayers.Geometry.Point":bounds=new OpenLayers.Bounds(object.x,object.y,object.x,object.y);break;case"OpenLayers.Bounds":bounds=object;break;}
if(bounds){this.centerLonLat=null;if((this.left==null)||(bounds.left<this.left)){this.left=bounds.left;}
if((this.bottom==null)||(bounds.bottom<this.bottom)){this.bottom=bounds.bottom;}
if((this.right==null)||(bounds.right>this.right)){this.right=bounds.right;}
if((this.top==null)||(bounds.top>this.top)){this.top=bounds.top;}}}},containsLonLat:function(ll,inclusive){return this.contains(ll.lon,ll.lat,inclusive);},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
if(x==null||y==null){return false;}
x=OpenLayers.Util.toFloat(x);y=OpenLayers.Util.toFloat(y);var contains=false;if(inclusive){contains=((x>=this.left)&&(x<=this.right)&&(y>=this.bottom)&&(y<=this.top));}else{contains=((x>this.left)&&(x<this.right)&&(y>this.bottom)&&(y<this.top));}
return contains;},intersectsBounds:function(bounds,inclusive){if(inclusive==null){inclusive=true;}
var intersects=false;var mightTouch=(this.left==bounds.right||this.right==bounds.left||this.top==bounds.bottom||this.bottom==bounds.top);if(inclusive||!mightTouch){var inBottom=(((bounds.bottom>=this.bottom)&&(bounds.bottom<=this.top))||((this.bottom>=bounds.bottom)&&(this.bottom<=bounds.top)));var inTop=(((bounds.top>=this.bottom)&&(bounds.top<=this.top))||((this.top>bounds.bottom)&&(this.top<bounds.top)));var inLeft=(((bounds.left>=this.left)&&(bounds.left<=this.right))||((this.left>=bounds.left)&&(this.left<=bounds.right)));var inRight=(((bounds.right>=this.left)&&(bounds.right<=this.right))||((this.right>=bounds.left)&&(this.right<=bounds.right)));intersects=((inBottom||inTop)&&(inLeft||inRight));}
return intersects;},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
if(inclusive==null){inclusive=true;}
var bottomLeft=this.contains(bounds.left,bounds.bottom,inclusive);var bottomRight=this.contains(bounds.right,bounds.bottom,inclusive);var topLeft=this.contains(bounds.left,bounds.top,inclusive);var topRight=this.contains(bounds.right,bounds.top,inclusive);return(partial)?(bottomLeft||bottomRight||topLeft||topRight):(bottomLeft&&bottomRight&&topLeft&&topRight);},determineQuadrant:function(lonlat){var quadrant="";var center=this.getCenterLonLat();quadrant+=(lonlat.lat<center.lat)?"b":"t";quadrant+=(lonlat.lon<center.lon)?"l":"r";return quadrant;},transform:function(source,dest){this.centerLonLat=null;var ll=OpenLayers.Projection.transform({'x':this.left,'y':this.bottom},source,dest);var lr=OpenLayers.Projection.transform({'x':this.right,'y':this.bottom},source,dest);var ul=OpenLayers.Projection.transform({'x':this.left,'y':this.top},source,dest);var ur=OpenLayers.Projection.transform({'x':this.right,'y':this.top},source,dest);this.left=Math.min(ll.x,ul.x);this.bottom=Math.min(ll.y,lr.y);this.right=Math.max(lr.x,ur.x);this.top=Math.max(ul.y,ur.y);return this;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){while(newBounds.left<maxExtent.left&&(newBounds.right-rightTolerance)<=maxExtent.left){newBounds=newBounds.add(maxExtent.getWidth(),0);}
while((newBounds.left+leftTolerance)>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-maxExtent.getWidth(),0);}}
return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds);};OpenLayers.Bounds.fromArray=function(bbox){return new OpenLayers.Bounds(parseFloat(bbox[0]),parseFloat(bbox[1]),parseFloat(bbox[2]),parseFloat(bbox[3]));};OpenLayers.Bounds.fromSize=function(size){return new OpenLayers.Bounds(0,size.h,size.w,0);};OpenLayers.Bounds.oppositeQuadrant=function(quadrant){var opp="";opp+=(quadrant.charAt(0)=='t')?'b':'t';opp+=(quadrant.charAt(1)=='l')?'r':'l';return opp;};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){this.lon=OpenLayers.Util.toFloat(lon);this.lat=OpenLayers.Util.toFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){var msg=OpenLayers.i18n("lonlatAddError");OpenLayers.Console.error(msg);return null;}
return new OpenLayers.LonLat(this.lon+OpenLayers.Util.toFloat(lon),this.lat+OpenLayers.Util.toFloat(lat));},equals:function(ll){var equals=false;if(ll!=null){equals=((this.lon==ll.lon&&this.lat==ll.lat)||(isNaN(this.lon)&&isNaN(this.lat)&&isNaN(ll.lon)&&isNaN(ll.lat)));}
return equals;},transform:function(source,dest){var point=OpenLayers.Projection.transform({'x':this.lon,'y':this.lat},source,dest);this.lon=point.x;this.lat=point.y;return this;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
while(newLonLat.lon>maxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(pair[0],pair[1]);};OpenLayers.Pixel=OpenLayers.Class({x:0.0,y:0.0,initialize:function(x,y){this.x=parseFloat(x);this.y=parseFloat(y);},toString:function(){return("x="+this.x+",y="+this.y);},clone:function(){return new OpenLayers.Pixel(this.x,this.y);},equals:function(px){var equals=false;if(px!=null){equals=((this.x==px.x&&this.y==px.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(px.x)&&isNaN(px.y)));}
return equals;},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.i18n("pixelAddError");OpenLayers.Console.error(msg);return null;}
return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);}
return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:false,displayClass:"",title:"",autoActivate:false,active:null,handler:null,eventListeners:null,events:null,EVENT_TYPES:["activate","deactivate"],initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}},destroy:function(){if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
this.events.destroy();this.events=null;}
this.eventListeners=null;if(this.handler){this.handler.destroy();this.handler=null;}
if(this.handlers){for(var key in this.handlers){if(this.handlers.hasOwnProperty(key)&&typeof this.handlers[key].destroy=="function"){this.handlers[key].destroy();}}
this.handlers=null;}
if(this.map){this.map.removeControl(this);this.map=null;}},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv(this.id);this.div.className=this.displayClass;if(!this.allowSelection){this.div.className+=" olControlNoSelect";this.div.setAttribute("unselectable","on",0);this.div.onselectstart=OpenLayers.Function.False;}
if(this.title!=""){this.div.title=this.title;}}
if(px!=null){this.position=px.clone();}
this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
if(this.handler){this.handler.activate();}
this.active=true;if(this.map){OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");}
this.events.triggerEvent("activate");return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
this.active=false;if(this.map){OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");}
this.events.triggerEvent("deactivate");return true;}
return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){if(!OpenLayers.Lang.code){OpenLayers.Lang.setCode();}
return OpenLayers.Lang.code;},setCode:function(code){var lang;if(!code){code=(OpenLayers.Util.getBrowserName()=="msie")?navigator.userLanguage:navigator.language;}
var parts=code.split('-');parts[0]=parts[0].toLowerCase();if(typeof OpenLayers.Lang[parts[0]]=="object"){lang=parts[0];}
if(parts[1]){var testLang=parts[0]+'-'+parts[1].toUpperCase();if(typeof OpenLayers.Lang[testLang]=="object"){lang=testLang;}}
if(!lang){OpenLayers.Console.warn('Failed to find OpenLayers.Lang.'+parts.join("-")+' dictionary, falling back to default language');lang=OpenLayers.Lang.defaultCode;}
OpenLayers.Lang.code=lang;},translate:function(key,context){var dictionary=OpenLayers.Lang[OpenLayers.Lang.getCode()];var message=dictionary[key];if(!message){message=key;}
if(context){message=OpenLayers.String.format(message,context);}
return message;}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,keepInMap:true,anchor:null,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){var newArguments=[id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback];OpenLayers.Popup.prototype.initialize.apply(this,newArguments);this.anchor=(anchor!=null)?anchor:{size:new OpenLayers.Size(0,0),offset:new OpenLayers.Pixel(0,0)};},destroy:function(){this.anchor=null;this.relativePosition=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments);},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments);},moveTo:function(px){var oldRelativePosition=this.relativePosition;this.relativePosition=this.calculateRelativePosition(px);var newPx=this.calculateNewPx(px);var newArguments=new Array(newPx);OpenLayers.Popup.prototype.moveTo.apply(this,newArguments);if(this.relativePosition!=oldRelativePosition){this.updateRelativePosition();}},setSize:function(contentSize){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(px);}},calculateRelativePosition:function(px){var lonlat=this.map.getLonLatFromLayerPx(px);var extent=this.map.getExtent();var quadrant=extent.determineQuadrant(lonlat);return OpenLayers.Bounds.oppositeQuadrant(quadrant);},updateRelativePosition:function(){},calculateNewPx:function(px){var newPx=px.offset(this.anchor.offset);var size=this.size||this.contentSize;var top=(this.relativePosition.charAt(0)=='t');newPx.y+=(top)?-(size.h+this.anchor.size.h):this.anchor.size.h;var left=(this.relativePosition.charAt(1)=='l');newPx.x+=(left)?-(size.w+this.anchor.size.w):this.anchor.size.w;return newPx;},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Protocol.SOS=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Protocol.SOS.DEFAULTS);var cls=OpenLayers.Protocol.SOS["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported SOS version: "+options.version;}
return new cls(options);};OpenLayers.Protocol.SOS.DEFAULTS={"version":"1.0.0"};OpenLayers.Protocol.SQL=OpenLayers.Class(OpenLayers.Protocol,{databaseName:'ol',tableName:"ol_vector_features",postReadFiltering:true,initialize:function(options){OpenLayers.Protocol.prototype.initialize.apply(this,[options]);},destroy:function(){OpenLayers.Protocol.prototype.destroy.apply(this);},supported:function(){return false;},evaluateFilter:function(feature,filter){return filter&&this.postReadFiltering?filter.evaluate(feature):true;},CLASS_NAME:"OpenLayers.Protocol.SQL"});OpenLayers.Protocol.WFS=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Protocol.WFS.DEFAULTS);var cls=OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported WFS version: "+options.version;}
return new cls(options);};OpenLayers.Protocol.WFS.fromWMSLayer=function(layer,options){var typeName,featurePrefix;var param=layer.params["LAYERS"];var parts=(param instanceof Array?param[0]:param).split(":");if(parts.length>1){featurePrefix=parts[0];}
typeName=parts.pop();var protocolOptions={url:layer.url,featureType:typeName,featurePrefix:featurePrefix,srsName:layer.projection&&layer.projection.getCode()||layer.map&&layer.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(options,protocolOptions));};OpenLayers.Protocol.WFS.DEFAULTS={"version":"1.0.0"};OpenLayers.Renderer.Canvas=OpenLayers.Class(OpenLayers.Renderer,{canvas:null,features:null,initialize:function(containerID){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.root=document.createElement("canvas");this.container.appendChild(this.root);this.canvas=this.root.getContext("2d");this.features={};},eraseGeometry:function(geometry,featureId){this.eraseFeatures(this.features[featureId][0]);},supported:function(){var canvas=document.createElement("canvas");return!!canvas.getContext;},setExtent:function(extent){this.extent=extent.clone();this.resolution=null;this.redraw();},setSize:function(size){this.size=size.clone();this.root.style.width=size.w+"px";this.root.style.height=size.h+"px";this.root.width=size.w;this.root.height=size.h;this.resolution=null;},drawFeature:function(feature,style){style=style||feature.style;style=this.applyDefaultSymbolizer(style);this.features[feature.id]=[feature,style];this.redraw();},drawGeometry:function(geometry,style){var className=geometry.CLASS_NAME;if((className=="OpenLayers.Geometry.Collection")||(className=="OpenLayers.Geometry.MultiPoint")||(className=="OpenLayers.Geometry.MultiLineString")||(className=="OpenLayers.Geometry.MultiPolygon")){for(var i=0;i<geometry.components.length;i++){this.drawGeometry(geometry.components[i],style);}
return;}
switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":this.drawPoint(geometry,style);break;case"OpenLayers.Geometry.LineString":this.drawLineString(geometry,style);break;case"OpenLayers.Geometry.LinearRing":this.drawLinearRing(geometry,style);break;case"OpenLayers.Geometry.Polygon":this.drawPolygon(geometry,style);break;default:break;}},drawExternalGraphic:function(pt,style){var img=new Image();if(style.graphicTitle){img.title=style.graphicTitle;}
var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);var context={img:img,x:(pt[0]+xOffset),y:(pt[1]+yOffset),width:width,height:height,opacity:style.graphicOpacity||style.fillOpacity,canvas:this.canvas};img.onload=OpenLayers.Function.bind(function(){this.canvas.globalAlpha=this.opacity;this.canvas.drawImage(this.img,this.x,this.y,this.width,this.height);},context);img.src=style.externalGraphic;},setCanvasStyle:function(type,style){if(type=="fill"){this.canvas.globalAlpha=style['fillOpacity'];this.canvas.fillStyle=style['fillColor'];}else if(type=="stroke"){this.canvas.globalAlpha=style['strokeOpacity'];this.canvas.strokeStyle=style['strokeColor'];this.canvas.lineWidth=style['strokeWidth'];}else{this.canvas.globalAlpha=0;this.canvas.lineWidth=1;}},drawPoint:function(geometry,style){if(style.graphic!==false){var pt=this.getLocalXY(geometry);if(style.externalGraphic){this.drawExternalGraphic(pt,style);}else{if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();this.canvas.arc(pt[0],pt[1],style.pointRadius,0,Math.PI*2,true);this.canvas.fill();}
if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();this.canvas.arc(pt[0],pt[1],style.pointRadius,0,Math.PI*2,true);this.canvas.stroke();this.setCanvasStyle("reset");}}}},drawLineString:function(geometry,style){if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();var start=this.getLocalXY(geometry.components[0]);this.canvas.moveTo(start[0],start[1]);for(var i=1;i<geometry.components.length;i++){var pt=this.getLocalXY(geometry.components[i]);this.canvas.lineTo(pt[0],pt[1]);}
this.canvas.stroke();}
this.setCanvasStyle("reset");},drawLinearRing:function(geometry,style){if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();var start=this.getLocalXY(geometry.components[0]);this.canvas.moveTo(start[0],start[1]);for(var i=1;i<geometry.components.length-1;i++){var pt=this.getLocalXY(geometry.components[i]);this.canvas.lineTo(pt[0],pt[1]);}
this.canvas.fill();}
if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();var start=this.getLocalXY(geometry.components[0]);this.canvas.moveTo(start[0],start[1]);for(var i=1;i<geometry.components.length;i++){var pt=this.getLocalXY(geometry.components[i]);this.canvas.lineTo(pt[0],pt[1]);}
this.canvas.stroke();}
this.setCanvasStyle("reset");},drawPolygon:function(geometry,style){this.drawLinearRing(geometry.components[0],style);for(var i=1;i<geometry.components.length;i++){this.drawLinearRing(geometry.components[i],{fillOpacity:0,strokeWidth:0,strokeOpacity:0,strokeColor:'#000000',fillColor:'#000000'});}},drawText:function(location,style){style=OpenLayers.Util.extend({fontColor:"#000000",labelAlign:"cm"},style);var pt=this.getLocalXY(location);this.setCanvasStyle("reset");this.canvas.fillStyle=style.fontColor;this.canvas.globalAlpha=style.fontOpacity||1.0;var fontStyle=style.fontWeight+" "+style.fontSize+" "+style.fontFamily;if(this.canvas.fillText){var labelAlign=OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]]||"center";this.canvas.font=fontStyle;this.canvas.textAlign=labelAlign;this.canvas.fillText(style.label,pt[0],pt[1]);}else if(this.canvas.mozDrawText){this.canvas.mozTextStyle=fontStyle;var len=this.canvas.mozMeasureText(style.label);switch(style.labelAlign[0]){case"l":break;case"r":pt[0]-=len;break;case"c":default:pt[0]-=len/2;}
this.canvas.translate(pt[0],pt[1]);this.canvas.mozDrawText(style.label);this.canvas.translate(-1*pt[0],-1*pt[1]);}
this.setCanvasStyle("reset");},getLocalXY:function(point){var resolution=this.getResolution();var extent=this.extent;var x=(point.x/resolution+(-extent.left/resolution));var y=((extent.top/resolution)-point.y/resolution);return[x,y];},clear:function(){this.canvas.clearRect(0,0,this.root.width,this.root.height);this.features={};},getFeatureIdFromEvent:function(evt){var loc=this.map.getLonLatFromPixel(evt.xy);var resolution=this.getResolution();var bounds=new OpenLayers.Bounds(loc.lon-resolution*5,loc.lat-resolution*5,loc.lon+resolution*5,loc.lat+resolution*5);var geom=bounds.toGeometry();for(var feat in this.features){if(!this.features.hasOwnProperty(feat)){continue;}
if(this.features[feat][0].geometry.intersects(geom)){return feat;}}
return null;},eraseFeatures:function(features){if(!(features instanceof Array)){features=[features];}
for(var i=0;i<features.length;++i){delete this.features[features[i].id];}
this.redraw();},redraw:function(){if(!this.locked){this.canvas.clearRect(0,0,this.root.width,this.root.height);var labelMap=[];var feature,style;for(var id in this.features){if(!this.features.hasOwnProperty(id)){continue;}
feature=this.features[id][0];style=this.features[id][1];if(!feature.geometry){continue;}
this.drawGeometry(feature.geometry,style);if(style.label){labelMap.push([feature,style]);}}
var item;for(var i=0,len=labelMap.length;i<len;++i){item=labelMap[i];this.drawText(item[0].geometry.getCentroid(),item[1]);}}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={"l":"left","r":"right"};OpenLayers.ElementsIndexer=OpenLayers.Class({maxZIndex:null,order:null,indices:null,compare:null,initialize:function(yOrdering){this.compare=yOrdering?OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER:OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;this.order=[];this.indices={};this.maxZIndex=0;},insert:function(newNode){if(this.exists(newNode)){this.remove(newNode);}
var nodeId=newNode.id;this.determineZIndex(newNode);var leftIndex=-1;var rightIndex=this.order.length;var middle;while(rightIndex-leftIndex>1){middle=parseInt((leftIndex+rightIndex)/2);var placement=this.compare(this,newNode,OpenLayers.Util.getElement(this.order[middle]));if(placement>0){leftIndex=middle;}else{rightIndex=middle;}}
this.order.splice(rightIndex,0,nodeId);this.indices[nodeId]=this.getZIndex(newNode);return this.getNextElement(rightIndex);},remove:function(node){var nodeId=node.id;var arrayIndex=OpenLayers.Util.indexOf(this.order,nodeId);if(arrayIndex>=0){this.order.splice(arrayIndex,1);delete this.indices[nodeId];if(this.order.length>0){var lastId=this.order[this.order.length-1];this.maxZIndex=this.indices[lastId];}else{this.maxZIndex=0;}}},clear:function(){this.order=[];this.indices={};this.maxZIndex=0;},exists:function(node){return(this.indices[node.id]!=null);},getZIndex:function(node){return node._style.graphicZIndex;},determineZIndex:function(node){var zIndex=node._style.graphicZIndex;if(zIndex==null){zIndex=this.maxZIndex;node._style.graphicZIndex=zIndex;}else if(zIndex>this.maxZIndex){this.maxZIndex=zIndex;}},getNextElement:function(index){var nextIndex=index+1;if(nextIndex<this.order.length){var nextElement=OpenLayers.Util.getElement(this.order[nextIndex]);if(nextElement==undefined){nextElement=this.getNextElement(nextIndex);}
return nextElement;}else{return null;}},CLASS_NAME:"OpenLayers.ElementsIndexer"});OpenLayers.ElementsIndexer.IndexingMethods={Z_ORDER:function(indexer,newNode,nextNode){var newZIndex=indexer.getZIndex(newNode);var returnVal=0;if(nextNode){var nextZIndex=indexer.getZIndex(nextNode);returnVal=newZIndex-nextZIndex;}
return returnVal;},Z_ORDER_DRAWING_ORDER:function(indexer,newNode,nextNode){var returnVal=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer,newNode,nextNode);if(nextNode&&returnVal==0){returnVal=1;}
return returnVal;},Z_ORDER_Y_ORDER:function(indexer,newNode,nextNode){var returnVal=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer,newNode,nextNode);if(nextNode&&returnVal===0){var result=nextNode._boundsBottom-newNode._boundsBottom;returnVal=(result===0)?1:result;}
return returnVal;}};OpenLayers.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,vectorRoot:null,textRoot:null,xmlns:null,indexer:null,BACKGROUND_ID_SUFFIX:"_background",LABEL_ID_SUFFIX:"_label",initialize:function(containerID,options){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot("_root");this.vectorRoot=this.createRoot("_vroot");this.textRoot=this.createRoot("_troot");this.root.appendChild(this.vectorRoot);this.root.appendChild(this.textRoot);this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);if(options&&(options.zIndexing||options.yOrdering)){this.indexer=new OpenLayers.ElementsIndexer(options.yOrdering);}},destroy:function(){this.clear();this.rendererRoot=null;this.root=null;this.xmlns=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments);},clear:function(){var child;var root=this.vectorRoot;if(root){while(child=root.firstChild){root.removeChild(child);}}
root=this.textRoot;if(root){while(child=root.firstChild){root.removeChild(child);}}
if(this.indexer){this.indexer.clear();}},getNodeType:function(geometry,style){},drawGeometry:function(geometry,style,featureId){var className=geometry.CLASS_NAME;var rendered=true;if((className=="OpenLayers.Geometry.Collection")||(className=="OpenLayers.Geometry.MultiPoint")||(className=="OpenLayers.Geometry.MultiLineString")||(className=="OpenLayers.Geometry.MultiPolygon")){for(var i=0,len=geometry.components.length;i<len;i++){rendered=this.drawGeometry(geometry.components[i],style,featureId)&&rendered;}
return rendered;};rendered=false;if(style.display!="none"){if(style.backgroundGraphic){this.redrawBackgroundNode(geometry.id,geometry,style,featureId);}
rendered=this.redrawNode(geometry.id,geometry,style,featureId);}
if(rendered==false){var node=document.getElementById(geometry.id);if(node){if(node._style.backgroundGraphic){node.parentNode.removeChild(document.getElementById(geometry.id+this.BACKGROUND_ID_SUFFIX));}
node.parentNode.removeChild(node);}}
return rendered;},redrawNode:function(id,geometry,style,featureId){style=this.applyDefaultSymbolizer(style);var node=this.nodeFactory(id,this.getNodeType(geometry,style));node._featureId=featureId;node._boundsBottom=geometry.getBounds().bottom;node._geometryClass=geometry.CLASS_NAME;node._style=style;var drawResult=this.drawGeometryNode(node,geometry,style);if(drawResult===false){return false;}
node=drawResult.node;if(this.indexer){var insert=this.indexer.insert(node);if(insert){this.vectorRoot.insertBefore(node,insert);}else{this.vectorRoot.appendChild(node);}}else{if(node.parentNode!==this.vectorRoot){this.vectorRoot.appendChild(node);}}
this.postDraw(node);return drawResult.complete;},redrawBackgroundNode:function(id,geometry,style,featureId){var backgroundStyle=OpenLayers.Util.extend({},style);backgroundStyle.externalGraphic=backgroundStyle.backgroundGraphic;backgroundStyle.graphicXOffset=backgroundStyle.backgroundXOffset;backgroundStyle.graphicYOffset=backgroundStyle.backgroundYOffset;backgroundStyle.graphicZIndex=backgroundStyle.backgroundGraphicZIndex;backgroundStyle.graphicWidth=backgroundStyle.backgroundWidth||backgroundStyle.graphicWidth;backgroundStyle.graphicHeight=backgroundStyle.backgroundHeight||backgroundStyle.graphicHeight;backgroundStyle.backgroundGraphic=null;backgroundStyle.backgroundXOffset=null;backgroundStyle.backgroundYOffset=null;backgroundStyle.backgroundGraphicZIndex=null;return this.redrawNode(id+this.BACKGROUND_ID_SUFFIX,geometry,backgroundStyle,null);},drawGeometryNode:function(node,geometry,style){style=style||node._style;var options={'isFilled':style.fill===undefined?true:style.fill,'isStroked':style.stroke===undefined?!!style.strokeWidth:style.stroke};var drawn;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.graphic===false){options.isFilled=false;options.isStroked=false;}
drawn=this.drawPoint(node,geometry);break;case"OpenLayers.Geometry.LineString":options.isFilled=false;drawn=this.drawLineString(node,geometry);break;case"OpenLayers.Geometry.LinearRing":drawn=this.drawLinearRing(node,geometry);break;case"OpenLayers.Geometry.Polygon":drawn=this.drawPolygon(node,geometry);break;case"OpenLayers.Geometry.Surface":drawn=this.drawSurface(node,geometry);break;case"OpenLayers.Geometry.Rectangle":drawn=this.drawRectangle(node,geometry);break;default:break;}
node._options=options;if(drawn!=false){return{node:this.setStyle(node,style,options,geometry),complete:drawn};}else{return false;}},postDraw:function(node){},drawPoint:function(node,geometry){},drawLineString:function(node,geometry){},drawLinearRing:function(node,geometry){},drawPolygon:function(node,geometry){},drawRectangle:function(node,geometry){},drawCircle:function(node,geometry){},drawSurface:function(node,geometry){},removeText:function(featureId){var label=document.getElementById(featureId+this.LABEL_ID_SUFFIX);if(label){this.textRoot.removeChild(label);}},getFeatureIdFromEvent:function(evt){var target=evt.target;var useElement=target&&target.correspondingUseElement;var node=useElement?useElement:(target||evt.srcElement);var featureId=node._featureId;return featureId;},eraseGeometry:function(geometry,featureId){if((geometry.CLASS_NAME=="OpenLayers.Geometry.MultiPoint")||(geometry.CLASS_NAME=="OpenLayers.Geometry.MultiLineString")||(geometry.CLASS_NAME=="OpenLayers.Geometry.MultiPolygon")||(geometry.CLASS_NAME=="OpenLayers.Geometry.Collection")){for(var i=0,len=geometry.components.length;i<len;i++){this.eraseGeometry(geometry.components[i],featureId);}}else{var element=OpenLayers.Util.getElement(geometry.id);if(element&&element.parentNode){if(element.geometry){element.geometry.destroy();element.geometry=null;}
element.parentNode.removeChild(element);if(this.indexer){this.indexer.remove(element);}
if(element._style.backgroundGraphic){var backgroundId=geometry.id+this.BACKGROUND_ID_SUFFIX;var bElem=OpenLayers.Util.getElement(backgroundId);if(bElem&&bElem.parentNode){bElem.parentNode.removeChild(bElem);}}}}},nodeFactory:function(id,type){var node=OpenLayers.Util.getElement(id);if(node){if(!this.nodeTypeCompare(node,type)){node.parentNode.removeChild(node);node=this.nodeFactory(id,type);}}else{node=this.createNode(type,id);}
return node;},nodeTypeCompare:function(node,type){},createNode:function(type,id){},moveRoot:function(renderer){var root=this.root;if(renderer.root.parentNode==this.rendererRoot){root=renderer.root;}
root.parentNode.removeChild(root);renderer.rendererRoot.appendChild(root);},getRenderLayerId:function(){return this.root.parentNode.parentNode.id;},isComplexSymbol:function(graphicName){return(graphicName!="circle")&&!!graphicName;},CLASS_NAME:"OpenLayers.Renderer.Elements"});OpenLayers.Renderer.symbol={"star":[350,75,379,161,469,161,397,215,423,301,350,250,277,301,303,215,231,161,321,161,350,75],"cross":[4,0,6,0,6,4,10,4,10,6,6,6,6,10,4,10,4,6,0,6,0,4,4,4,4,0],"x":[0,0,25,0,50,35,75,0,100,0,65,50,100,100,75,100,50,65,25,100,0,100,35,50,0,0],"square":[0,0,0,1,1,1,1,0,0,0],"triangle":[0,10,10,10,5,0,0,10]};OpenLayers.Strategy.Cluster=OpenLayers.Class(OpenLayers.Strategy,{distance:20,threshold:null,features:null,clusters:null,clustering:false,resolution:null,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);},activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"beforefeaturesadded":this.cacheFeatures,"moveend":this.cluster,scope:this});}
return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.clearCache();this.layer.events.un({"beforefeaturesadded":this.cacheFeatures,"moveend":this.cluster,scope:this});}
return deactivated;},cacheFeatures:function(event){var propagate=true;if(!this.clustering){this.clearCache();this.features=event.features;this.cluster();propagate=false;}
return propagate;},clearCache:function(){this.features=null;},cluster:function(event){if((!event||event.zoomChanged)&&this.features){var resolution=this.layer.map.getResolution();if(resolution!=this.resolution||!this.clustersExist()){this.resolution=resolution;var clusters=[];var feature,clustered,cluster;for(var i=0;i<this.features.length;++i){feature=this.features[i];if(feature.geometry){clustered=false;for(var j=clusters.length-1;j>=0;--j){cluster=clusters[j];if(this.shouldCluster(cluster,feature)){this.addToCluster(cluster,feature);clustered=true;break;}}
if(!clustered){clusters.push(this.createCluster(this.features[i]));}}}
this.layer.removeAllFeatures();if(clusters.length>0){if(this.threshold>1){var clone=clusters.slice();clusters=[];var candidate;for(var i=0,len=clone.length;i<len;++i){candidate=clone[i];if(candidate.attributes.count<this.threshold){Array.prototype.push.apply(clusters,candidate.cluster);}else{clusters.push(candidate);}}}
this.clustering=true;this.layer.addFeatures(clusters);this.clustering=false;}
this.clusters=clusters;}}},clustersExist:function(){var exist=false;if(this.clusters&&this.clusters.length>0&&this.clusters.length==this.layer.features.length){exist=true;for(var i=0;i<this.clusters.length;++i){if(this.clusters[i]!=this.layer.features[i]){exist=false;break;}}}
return exist;},shouldCluster:function(cluster,feature){var cc=cluster.geometry.getBounds().getCenterLonLat();var fc=feature.geometry.getBounds().getCenterLonLat();var distance=(Math.sqrt(Math.pow((cc.lon-fc.lon),2)+Math.pow((cc.lat-fc.lat),2))/this.resolution);return(distance<=this.distance);},addToCluster:function(cluster,feature){cluster.cluster.push(feature);cluster.attributes.count+=1;},createCluster:function(feature){var center=feature.geometry.getBounds().getCenterLonLat();var cluster=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(center.lon,center.lat),{count:1});cluster.cluster=[feature];return cluster;},CLASS_NAME:"OpenLayers.Strategy.Cluster"});OpenLayers.Strategy.Fixed=OpenLayers.Class(OpenLayers.Strategy,{preload:false,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);},destroy:function(){OpenLayers.Strategy.prototype.destroy.apply(this,arguments);},activate:function(){if(OpenLayers.Strategy.prototype.activate.apply(this,arguments)){this.layer.events.on({"refresh":this.load,scope:this});if(this.layer.visibility==true||this.preload){this.load();}else{this.layer.events.on({"visibilitychanged":this.load,scope:this});}
return true;}
return false;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"refresh":this.load,"visibilitychanged":this.load,scope:this});}
return deactivated;},load:function(options){this.layer.events.triggerEvent("loadstart");this.layer.protocol.read(OpenLayers.Util.applyDefaults({callback:this.merge,filter:this.layer.filter,scope:this},options));this.layer.events.un({"visibilitychanged":this.load,scope:this});},merge:function(resp){this.layer.destroyFeatures();var features=resp.features;if(features&&features.length>0){var remote=this.layer.projection;var local=this.layer.map.getProjectionObject();if(!local.equals(remote)){var geom;for(var i=0,len=features.length;i<len;++i){geom=features[i].geometry;if(geom){geom.transform(remote,local);}}}
this.layer.addFeatures(features);}
this.layer.events.triggerEvent("loadend");},CLASS_NAME:"OpenLayers.Strategy.Fixed"});OpenLayers.Strategy.Paging=OpenLayers.Class(OpenLayers.Strategy,{features:null,length:10,num:null,paging:false,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);},activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"beforefeaturesadded":this.cacheFeatures,scope:this});}
return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.clearCache();this.layer.events.un({"beforefeaturesadded":this.cacheFeatures,scope:this});}
return deactivated;},cacheFeatures:function(event){if(!this.paging){this.clearCache();this.features=event.features;this.pageNext(event);}},clearCache:function(){if(this.features){for(var i=0;i<this.features.length;++i){this.features[i].destroy();}}
this.features=null;this.num=null;},pageCount:function(){var numFeatures=this.features?this.features.length:0;return Math.ceil(numFeatures/this.length);},pageNum:function(){return this.num;},pageLength:function(newLength){if(newLength&&newLength>0){this.length=newLength;}
return this.length;},pageNext:function(event){var changed=false;if(this.features){if(this.num===null){this.num=-1;}
var start=(this.num+1)*this.length;changed=this.page(start,event);}
return changed;},pagePrevious:function(){var changed=false;if(this.features){if(this.num===null){this.num=this.pageCount();}
var start=(this.num-1)*this.length;changed=this.page(start);}
return changed;},page:function(start,event){var changed=false;if(this.features){if(start>=0&&start<this.features.length){var num=Math.floor(start/this.length);if(num!=this.num){this.paging=true;var features=this.features.slice(start,start+this.length);this.layer.removeFeatures(this.layer.features);this.num=num;if(event&&event.features){event.features=features;}else{this.layer.addFeatures(features);}
this.paging=false;changed=true;}}}
return changed;},CLASS_NAME:"OpenLayers.Strategy.Paging"});OpenLayers.Strategy.Refresh=OpenLayers.Class(OpenLayers.Strategy,{force:false,interval:0,timer:null,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);},activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){if(this.layer.visibility===true){this.start();}
this.layer.events.on({"visibilitychanged":this.reset,scope:this});}
return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.stop();}
return deactivated;},reset:function(){if(this.layer.visibility===true){this.start();}else{this.stop();}},start:function(){if(this.interval&&typeof this.interval==="number"&&this.interval>0){this.timer=window.setInterval(OpenLayers.Function.bind(this.refresh,this),this.interval);}},refresh:function(){if(this.layer&&this.layer.refresh&&typeof this.layer.refresh=="function"){this.layer.refresh({force:this.force});}},stop:function(){if(this.timer!==null){window.clearInterval(this.timer);this.timer=null;}},CLASS_NAME:"OpenLayers.Strategy.Refresh"});OpenLayers.Strategy.Save=OpenLayers.Class(OpenLayers.Strategy,{EVENT_TYPES:["start","success","fail"],events:null,auto:false,timer:null,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){if(this.auto){if(typeof this.auto==="number"){this.timer=window.setInterval(OpenLayers.Function.bind(this.save,this),this.auto*1000);}else{this.layer.events.on({"featureadded":this.triggerSave,"afterfeaturemodified":this.triggerSave,scope:this});}}}
return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){if(this.auto){if(typeof this.auto==="number"){window.clearInterval(this.timer);}else{this.layer.events.un({"featureadded":this.triggerSave,"afterfeaturemodified":this.triggerSave,scope:this});}}}
return deactivated;},triggerSave:function(event){var feature=event.feature;if(feature.state===OpenLayers.State.INSERT||feature.state===OpenLayers.State.UPDATE||feature.state===OpenLayers.State.DELETE){this.save([event.feature]);}},save:function(features){if(!features){features=this.layer.features;}
this.events.triggerEvent("start",{features:features});var remote=this.layer.projection;var local=this.layer.map.getProjectionObject();if(!local.equals(remote)){var len=features.length;var clones=new Array(len);var orig,clone;for(var i=0;i<len;++i){orig=features[i];clone=orig.clone();clone.fid=orig.fid;clone.state=orig.state;if(orig.url){clone.url=orig.url;}
clone._original=orig;clone.geometry.transform(local,remote);clones[i]=clone;}
features=clones;}
this.layer.protocol.commit(features,{callback:this.onCommit,scope:this});},onCommit:function(response){var evt={"response":response};if(response.success()){var features=response.reqFeatures;var state,feature;var destroys=[];var insertIds=response.insertIds||[];var j=0;for(var i=0,len=features.length;i<len;++i){feature=features[i];feature=feature._original||feature;state=feature.state;if(state){if(state==OpenLayers.State.DELETE){destroys.push(feature);}else if(state==OpenLayers.State.INSERT){feature.fid=insertIds[j];++j;}
feature.state=null;}}
if(destroys.length>0){this.layer.destroyFeatures(destroys);}
this.events.triggerEvent("success",evt);}else{this.events.triggerEvent("fail",evt);}},CLASS_NAME:"OpenLayers.Strategy.Save"});OpenLayers.Symbolizer.Line=OpenLayers.Class(OpenLayers.Symbolizer,{strokeColor:null,strokeOpacity:null,strokeWidth:null,strokeLinecap:null,strokeDashstyle:null,initialize:function(config){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Symbolizer.Line"});OpenLayers.Symbolizer.Point=OpenLayers.Class(OpenLayers.Symbolizer,{strokeColor:null,strokeOpacity:null,strokeWidth:null,strokeLinecap:null,strokeDashstyle:null,fillColor:null,fillOpacity:null,pointRadius:null,externalGraphic:null,graphicWidth:null,graphicHeight:null,graphicOpacity:null,graphicXOffset:null,graphicYOffset:null,rotation:null,graphicName:null,initialize:function(config){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Symbolizer.Point"});OpenLayers.Symbolizer.Polygon=OpenLayers.Class(OpenLayers.Symbolizer,{strokeColor:null,strokeOpacity:null,strokeWidth:null,strokeLinecap:null,strokeDashstyle:null,fillColor:null,fillOpacity:null,initialize:function(config){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Symbolizer.Polygon"});OpenLayers.Symbolizer.Raster=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(config){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Symbolizer.Raster"});OpenLayers.Symbolizer.Text=OpenLayers.Class(OpenLayers.Symbolizer,{label:null,fontFamily:null,fontSize:null,fontWeight:null,fontStyle:null,initialize:function(config){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Symbolizer.Text"});OpenLayers.Tween=OpenLayers.Class({INTERVAL:10,easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,interval:null,playing:false,initialize:function(easing){this.easing=(easing)?easing:OpenLayers.Easing.Expo.easeOut;},start:function(begin,finish,duration,options){this.playing=true;this.begin=begin;this.finish=finish;this.duration=duration;this.callbacks=options.callbacks;this.time=0;if(this.interval){window.clearInterval(this.interval);this.interval=null;}
if(this.callbacks&&this.callbacks.start){this.callbacks.start.call(this,this.begin);}
this.interval=window.setInterval(OpenLayers.Function.bind(this.play,this),this.INTERVAL);},stop:function(){if(!this.playing){return;}
if(this.callbacks&&this.callbacks.done){this.callbacks.done.call(this,this.finish);}
window.clearInterval(this.interval);this.interval=null;this.playing=false;},play:function(){var value={};for(var i in this.begin){var b=this.begin[i];var f=this.finish[i];if(b==null||f==null||isNaN(b)||isNaN(f)){OpenLayers.Console.error('invalid value for Tween');}
var c=f-b;value[i]=this.easing.apply(this,[this.time,b,c,this.duration]);}
this.time++;if(this.callbacks&&this.callbacks.eachStep){this.callbacks.eachStep.call(this,value);}
if(this.time>this.duration){this.stop();}},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(t,b,c,d){return c*t/d+b;},easeOut:function(t,b,c,d){return c*t/d+b;},easeInOut:function(t,b,c,d){return c*t/d+b;},CLASS_NAME:"OpenLayers.Easing.Linear"};OpenLayers.Easing.Expo={easeIn:function(t,b,c,d){return(t==0)?b:c*Math.pow(2,10*(t/d-1))+b;},easeOut:function(t,b,c,d){return(t==d)?b+c:c*(-Math.pow(2,-10*t/d)+1)+b;},easeInOut:function(t,b,c,d){if(t==0)return b;if(t==d)return b+c;if((t/=d/2)<1)return c/2*Math.pow(2,10*(t-1))+b;return c/2*(-Math.pow(2,-10*--t)+2)+b;},CLASS_NAME:"OpenLayers.Easing.Expo"};OpenLayers.Easing.Quad={easeIn:function(t,b,c,d){return c*(t/=d)*t+b;},easeOut:function(t,b,c,d){return-c*(t/=d)*(t-2)+b;},easeInOut:function(t,b,c,d){if((t/=d/2)<1)return c/2*t*t+b;return-c/2*((--t)*(t-2)-1)+b;},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0,len=this.map.controls.length;i<len;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
break;}}
if(i==this.map.controls.length){var args=OpenLayers.Util.getParameters();if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}
if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseInt(args.zoom);}
this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);if(this.displayProjection){this.center.transform(this.displayProjection,this.map.getProjectionObject());}
this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0,len=this.layers.length;i<len;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.map.events.un({"removelayer":this.updateAttribution,"addlayer":this.updateAttribution,"changelayer":this.updateAttribution,"changebaselayer":this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({'changebaselayer':this.updateAttribution,'changelayer':this.updateAttribution,'addlayer':this.updateAttribution,'removelayer':this.updateAttribution,scope:this});this.updateAttribution();return this.div;},updateAttribution:function(){var attributions=[];if(this.map&&this.map.layers){for(var i=0,len=this.map.layers.length;i<len;i++){var layer=this.map.layers[i];if(layer.attribution&&layer.getVisibility()){if(OpenLayers.Util.indexOf(attributions,layer.attribution)===-1){attributions.push(layer.attribution);}}}
this.div.innerHTML=attributions.join(this.separator);}},CLASS_NAME:"OpenLayers.Control.Attribution"});OpenLayers.Control.Button=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){},CLASS_NAME:"OpenLayers.Control.Button"});OpenLayers.Control.Graticule=OpenLayers.Class(OpenLayers.Control,{autoActivate:true,intervals:[45,30,20,10,5,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.002,0.001],displayInLayerSwitcher:true,visible:true,numPoints:50,targetSize:200,layerName:null,labelled:true,labelFormat:'dm',lineSymbolizer:{strokeColor:"#333",strokeWidth:1,strokeOpacity:0.5},labelSymbolizer:{},gratLayer:null,initialize:function(options){options=options||{};options.layerName=options.layerName||OpenLayers.i18n("graticule");OpenLayers.Control.prototype.initialize.apply(this,[options]);this.labelSymbolizer.stroke=false;this.labelSymbolizer.fill=false;this.labelSymbolizer.label="${label}";this.labelSymbolizer.labelAlign="${labelAlign}";this.labelSymbolizer.labelXOffset="${xOffset}";this.labelSymbolizer.labelYOffset="${yOffset}";},destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);if(this.gratLayer){this.gratLayer.destroy();this.gratLayer=null;}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.gratLayer){var gratStyle=new OpenLayers.Style({},{rules:[new OpenLayers.Rule({'symbolizer':{"Point":this.labelSymbolizer,"Line":this.lineSymbolizer}})]});this.gratLayer=new OpenLayers.Layer.Vector(this.layerName,{styleMap:new OpenLayers.StyleMap({'default':gratStyle}),visibility:this.visible,displayInLayerSwitcher:this.displayInLayerSwitcher});}
return this.div;},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){this.map.addLayer(this.gratLayer);this.map.events.register('moveend',this,this.update);this.update();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.map.events.unregister('moveend',this,this.update);this.map.removeLayer(this.gratLayer);return true;}else{return false;}},update:function(){var mapBounds=this.map.getExtent();if(!mapBounds){return;}
this.gratLayer.destroyFeatures();var llProj=new OpenLayers.Projection("EPSG:4326");var mapProj=this.map.getProjectionObject();var mapRes=this.map.getResolution();if(mapProj.proj&&mapProj.proj.projName=="longlat"){this.numPoints=1;}
var mapCenter=this.map.getCenter();var mapCenterLL=new OpenLayers.Pixel(mapCenter.lon,mapCenter.lat);OpenLayers.Projection.transform(mapCenterLL,mapProj,llProj);var testSq=this.targetSize*mapRes;testSq*=testSq;var llInterval;for(var i=0;i<this.intervals.length;++i){llInterval=this.intervals[i];var delta=llInterval/2;var p1=mapCenterLL.offset(new OpenLayers.Pixel(-delta,-delta));var p2=mapCenterLL.offset(new OpenLayers.Pixel(delta,delta));OpenLayers.Projection.transform(p1,llProj,mapProj);OpenLayers.Projection.transform(p2,llProj,mapProj);var distSq=(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);if(distSq<=testSq){break;}}
mapCenterLL.x=Math.floor(mapCenterLL.x/llInterval)*llInterval;mapCenterLL.y=Math.floor(mapCenterLL.y/llInterval)*llInterval;var iter=0;var centerLonPoints=[mapCenterLL.clone()];var newPoint=mapCenterLL.clone();var mapXY;do{newPoint=newPoint.offset(new OpenLayers.Pixel(0,llInterval));mapXY=OpenLayers.Projection.transform(newPoint.clone(),llProj,mapProj);centerLonPoints.unshift(newPoint);}while(mapBounds.containsPixel(mapXY)&&++iter<1000);newPoint=mapCenterLL.clone();do{newPoint=newPoint.offset(new OpenLayers.Pixel(0,-llInterval));mapXY=OpenLayers.Projection.transform(newPoint.clone(),llProj,mapProj);centerLonPoints.push(newPoint);}while(mapBounds.containsPixel(mapXY)&&++iter<1000);iter=0;var centerLatPoints=[mapCenterLL.clone()];newPoint=mapCenterLL.clone();do{newPoint=newPoint.offset(new OpenLayers.Pixel(-llInterval,0));mapXY=OpenLayers.Projection.transform(newPoint.clone(),llProj,mapProj);centerLatPoints.unshift(newPoint);}while(mapBounds.containsPixel(mapXY)&&++iter<1000);newPoint=mapCenterLL.clone();do{newPoint=newPoint.offset(new OpenLayers.Pixel(llInterval,0));mapXY=OpenLayers.Projection.transform(newPoint.clone(),llProj,mapProj);centerLatPoints.push(newPoint);}while(mapBounds.containsPixel(mapXY)&&++iter<1000);var lines=[];for(var i=0;i<centerLatPoints.length;++i){var lon=centerLatPoints[i].x;var pointList=[];var labelPoint=null;var latEnd=Math.min(centerLonPoints[0].y,90);var latStart=Math.max(centerLonPoints[centerLonPoints.length-1].y,-90);var latDelta=(latEnd-latStart)/this.numPoints;var lat=latStart;for(var j=0;j<=this.numPoints;++j){var gridPoint=new OpenLayers.Geometry.Point(lon,lat);gridPoint.transform(llProj,mapProj);pointList.push(gridPoint);lat+=latDelta;if(gridPoint.y>=mapBounds.bottom&&!labelPoint){labelPoint=gridPoint;}}
if(this.labelled){var labelPos=new OpenLayers.Geometry.Point(labelPoint.x,mapBounds.bottom);var labelAttrs={value:lon,label:this.labelled?OpenLayers.Util.getFormattedLonLat(lon,"lon",this.labelFormat):"",labelAlign:"cb",xOffset:0,yOffset:2};this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos,labelAttrs));}
var geom=new OpenLayers.Geometry.LineString(pointList);lines.push(new OpenLayers.Feature.Vector(geom));}
for(var j=0;j<centerLonPoints.length;++j){lat=centerLonPoints[j].y;if(lat<-90||lat>90){continue;}
var pointList=[];var lonStart=centerLatPoints[0].x;var lonEnd=centerLatPoints[centerLatPoints.length-1].x;var lonDelta=(lonEnd-lonStart)/this.numPoints;var lon=lonStart;var labelPoint=null;for(var i=0;i<=this.numPoints;++i){var gridPoint=new OpenLayers.Geometry.Point(lon,lat);gridPoint.transform(llProj,mapProj);pointList.push(gridPoint);lon+=lonDelta;if(gridPoint.x<mapBounds.right){labelPoint=gridPoint;}}
if(this.labelled){var labelPos=new OpenLayers.Geometry.Point(mapBounds.right,labelPoint.y);var labelAttrs={value:lat,label:this.labelled?OpenLayers.Util.getFormattedLonLat(lat,"lat",this.labelFormat):"",labelAlign:"rb",xOffset:-2,yOffset:2};this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos,labelAttrs));}
var geom=new OpenLayers.Geometry.LineString(pointList);lines.push(new OpenLayers.Feature.Vector(geom));}
this.gratLayer.addFeatures(lines);},CLASS_NAME:"OpenLayers.Control.Graticule"});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{roundedCorner:true,roundedCornerColor:"darkblue",layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[];},destroy:function(){OpenLayers.Event.stopObservingElement(this.div);OpenLayers.Event.stopObservingElement(this.minimizeDiv);OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({"addlayer":this.redraw,"changelayer":this.redraw,"removelayer":this.redraw,"changebaselayer":this.redraw,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({"addlayer":this.redraw,"changelayer":this.redraw,"removelayer":this.redraw,"changebaselayer":this.redraw,scope:this});},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();if(!this.outsideViewport){this.minimizeControl();}
this.redraw();return this.div;},clearLayersArray:function(layersType){var layers=this[layersType+"Layers"];if(layers){for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];OpenLayers.Event.stopObservingElement(layer.inputElem);OpenLayers.Event.stopObservingElement(layer.labelSpan);}}
this[layersType+"LayersDiv"].innerHTML="";this[layersType+"Layers"]=[];},checkRedraw:function(){var redraw=false;if(!this.layerStates.length||(this.map.layers.length!=this.layerStates.length)){redraw=true;}else{for(var i=0,len=this.layerStates.length;i<len;i++){var layerState=this.layerStates[i];var layer=this.map.layers[i];if((layerState.name!=layer.name)||(layerState.inRange!=layer.inRange)||(layerState.id!=layer.id)||(layerState.visibility!=layer.visibility)){redraw=true;break;}}}
return redraw;},redraw:function(){if(!this.checkRedraw()){return this.div;}
this.clearLayersArray("base");this.clearLayersArray("data");var containsOverlays=false;var containsBaseLayers=false;var len=this.map.layers.length;this.layerStates=new Array(len);for(var i=0;i<len;i++){var layer=this.map.layers[i];this.layerStates[i]={'name':layer.name,'visibility':layer.visibility,'inRange':layer.inRange,'id':layer.id};}
var layers=this.map.layers.slice();if(!this.ascending){layers.reverse();}
for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];var baseLayer=layer.isBaseLayer;if(layer.displayInLayerSwitcher){if(baseLayer){containsBaseLayers=true;}else{containsOverlays=true;}
var checked=(baseLayer)?(layer==this.map.baseLayer):layer.getVisibility();var inputElem=document.createElement("input");inputElem.id=this.id+"_input_"+layer.name;inputElem.name=(baseLayer)?this.id+"_baseLayers":layer.name;inputElem.type=(baseLayer)?"radio":"checkbox";inputElem.value=layer.name;inputElem.checked=checked;inputElem.defaultChecked=checked;if(!baseLayer&&!layer.inRange){inputElem.disabled=true;}
var context={'inputElem':inputElem,'layer':layer,'layerSwitcher':this};OpenLayers.Event.observe(inputElem,"mouseup",OpenLayers.Function.bindAsEventListener(this.onInputClick,context));var labelSpan=document.createElement("span");OpenLayers.Element.addClass(labelSpan,"labelSpan")
if(!baseLayer&&!layer.inRange){labelSpan.style.color="gray";}
labelSpan.innerHTML=layer.name;labelSpan.style.verticalAlign=(baseLayer)?"bottom":"baseline";OpenLayers.Event.observe(labelSpan,"click",OpenLayers.Function.bindAsEventListener(this.onInputClick,context));var br=document.createElement("br");var groupArray=(baseLayer)?this.baseLayers:this.dataLayers;groupArray.push({'layer':layer,'inputElem':inputElem,'labelSpan':labelSpan});var groupDiv=(baseLayer)?this.baseLayersDiv:this.dataLayersDiv;groupDiv.appendChild(inputElem);groupDiv.appendChild(labelSpan);groupDiv.appendChild(br);}}
this.dataLbl.style.display=(containsOverlays)?"":"none";this.baseLbl.style.display=(containsBaseLayers)?"":"none";return this.div;},onInputClick:function(e){if(!this.inputElem.disabled){if(this.inputElem.type=="radio"){this.inputElem.checked=true;this.layer.map.setBaseLayer(this.layer);}else{this.inputElem.checked=!this.inputElem.checked;this.layerSwitcher.updateMap();}}
OpenLayers.Event.stop(e);},onLayerClick:function(e){this.updateMap();},updateMap:function(){for(var i=0,len=this.baseLayers.length;i<len;i++){var layerEntry=this.baseLayers[i];if(layerEntry.inputElem.checked){this.map.setBaseLayer(layerEntry.layer,false);}}
for(var i=0,len=this.dataLayers.length;i<len;i++){var layerEntry=this.dataLayers[i];layerEntry.layer.setVisibility(layerEntry.inputElem.checked);}},maximizeControl:function(e){this.div.style.width="";this.div.style.height="";this.showControls(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.div.style.width="0px";this.div.style.height="0px";this.showControls(true);if(e!=null){OpenLayers.Event.stop(e);}},showControls:function(minimize){this.maximizeDiv.style.display=minimize?"":"none";this.minimizeDiv.style.display=minimize?"none":"";this.layersDiv.style.display=minimize?"none":"";},loadContents:function(){OpenLayers.Event.observe(this.div,"mouseup",OpenLayers.Function.bindAsEventListener(this.mouseUp,this));OpenLayers.Event.observe(this.div,"click",this.ignoreEvent);OpenLayers.Event.observe(this.div,"mousedown",OpenLayers.Function.bindAsEventListener(this.mouseDown,this));OpenLayers.Event.observe(this.div,"dblclick",this.ignoreEvent);this.layersDiv=document.createElement("div");this.layersDiv.id=this.id+"_layersDiv";OpenLayers.Element.addClass(this.layersDiv,"layersDiv");this.baseLbl=document.createElement("div");this.baseLbl.innerHTML=OpenLayers.i18n("baseLayer");OpenLayers.Element.addClass(this.baseLbl,"baseLbl");this.baseLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.baseLayersDiv,"baseLayersDiv");this.dataLbl=document.createElement("div");this.dataLbl.innerHTML=OpenLayers.i18n("overlays");OpenLayers.Element.addClass(this.dataLbl,"dataLbl");this.dataLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.dataLayersDiv,"dataLayersDiv");if(this.ascending){this.layersDiv.appendChild(this.baseLbl);this.layersDiv.appendChild(this.baseLayersDiv);this.layersDiv.appendChild(this.dataLbl);this.layersDiv.appendChild(this.dataLayersDiv);}else{this.layersDiv.appendChild(this.dataLbl);this.layersDiv.appendChild(this.dataLayersDiv);this.layersDiv.appendChild(this.baseLbl);this.layersDiv.appendChild(this.baseLayersDiv);}
this.div.appendChild(this.layersDiv);if(this.roundedCorner){OpenLayers.Rico.Corner.round(this.div,{corners:"tl bl",bgColor:"transparent",color:this.roundedCornerColor,blend:false});OpenLayers.Rico.Corner.changeOpacity(this.layersDiv,0.75);}
var imgLocation=OpenLayers.Util.getImagesLocation();var sz=new OpenLayers.Size(18,18);var img=imgLocation+'layer-switcher-maximize.png';this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv",null,sz,img,"absolute");OpenLayers.Element.addClass(this.maximizeDiv,"maximizeDiv");this.maximizeDiv.style.display="none";OpenLayers.Event.observe(this.maximizeDiv,"click",OpenLayers.Function.bindAsEventListener(this.maximizeControl,this));this.div.appendChild(this.maximizeDiv);var img=imgLocation+'layer-switcher-minimize.png';var sz=new OpenLayers.Size(18,18);this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv",null,sz,img,"absolute");OpenLayers.Element.addClass(this.minimizeDiv,"minimizeDiv");this.minimizeDiv.style.display="none";OpenLayers.Event.observe(this.minimizeDiv,"click",OpenLayers.Function.bindAsEventListener(this.minimizeControl,this));this.div.appendChild(this.minimizeDiv);},ignoreEvent:function(evt){OpenLayers.Event.stop(evt);},mouseDown:function(evt){this.isMouseDown=true;this.ignoreEvent(evt);},mouseUp:function(evt){if(this.isMouseDown){this.isMouseDown=false;this.ignoreEvent(evt);}},CLASS_NAME:"OpenLayers.Control.LayerSwitcher"});OpenLayers.Control.MouseDefaults=OpenLayers.Class(OpenLayers.Control,{performedDrag:false,wheelObserver:null,initialize:function(){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.handler){this.handler.destroy();}
this.handler=null;this.map.events.un({"click":this.defaultClick,"dblclick":this.defaultDblClick,"mousedown":this.defaultMouseDown,"mouseup":this.defaultMouseUp,"mousemove":this.defaultMouseMove,"mouseout":this.defaultMouseOut,scope:this});OpenLayers.Event.stopObserving(window,"DOMMouseScroll",this.wheelObserver);OpenLayers.Event.stopObserving(window,"mousewheel",this.wheelObserver);OpenLayers.Event.stopObserving(document,"mousewheel",this.wheelObserver);this.wheelObserver=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){this.map.events.on({"click":this.defaultClick,"dblclick":this.defaultDblClick,"mousedown":this.defaultMouseDown,"mouseup":this.defaultMouseUp,"mousemove":this.defaultMouseMove,"mouseout":this.defaultMouseOut,scope:this});this.registerWheelEvents();},registerWheelEvents:function(){this.wheelObserver=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this);OpenLayers.Event.observe(window,"DOMMouseScroll",this.wheelObserver);OpenLayers.Event.observe(window,"mousewheel",this.wheelObserver);OpenLayers.Event.observe(document,"mousewheel",this.wheelObserver);},defaultClick:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
var notAfterDrag=!this.performedDrag;this.performedDrag=false;return notAfterDrag;},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);OpenLayers.Event.stop(evt);return false;},defaultMouseDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
this.mouseDragStart=evt.xy.clone();this.performedDrag=false;if(evt.shiftKey){this.map.div.style.cursor="crosshair";this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.mouseDragStart,null,null,"absolute","2px solid red");this.zoomBox.style.backgroundColor="white";this.zoomBox.style.filter="alpha(opacity=50)";this.zoomBox.style.opacity="0.50";this.zoomBox.style.fontSize="1px";this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);}
document.onselectstart=OpenLayers.Function.False;OpenLayers.Event.stop(evt);},defaultMouseMove:function(evt){this.mousePosition=evt.xy.clone();if(this.mouseDragStart!=null){if(this.zoomBox){var deltaX=Math.abs(this.mouseDragStart.x-evt.xy.x);var deltaY=Math.abs(this.mouseDragStart.y-evt.xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";if(evt.xy.x<this.mouseDragStart.x){this.zoomBox.style.left=evt.xy.x+"px";}
if(evt.xy.y<this.mouseDragStart.y){this.zoomBox.style.top=evt.xy.y+"px";}}else{var deltaX=this.mouseDragStart.x-evt.xy.x;var deltaY=this.mouseDragStart.y-evt.xy.y;var size=this.map.getSize();var newXY=new OpenLayers.Pixel(size.w/2+deltaX,size.h/2+deltaY);var newCenter=this.map.getLonLatFromViewPortPx(newXY);this.map.setCenter(newCenter,null,true);this.mouseDragStart=evt.xy.clone();this.map.div.style.cursor="move";}
this.performedDrag=true;}},defaultMouseUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
if(this.zoomBox){this.zoomBoxEnd(evt);}else{if(this.performedDrag){this.map.setCenter(this.map.center);}}
document.onselectstart=null;this.mouseDragStart=null;this.map.div.style.cursor="";},defaultMouseOut:function(evt){if(this.mouseDragStart!=null&&OpenLayers.Util.mouseLeft(evt,this.map.div)){if(this.zoomBox){this.removeZoomBox();}
this.mouseDragStart=null;}},defaultWheelUp:function(evt){if(this.map.getZoom()<=this.map.getNumZoomLevels()){this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),this.map.getZoom()+1);}},defaultWheelDown:function(evt){if(this.map.getZoom()>0){this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),this.map.getZoom()-1);}},zoomBoxEnd:function(evt){if(this.mouseDragStart!=null){if(Math.abs(this.mouseDragStart.x-evt.xy.x)>5||Math.abs(this.mouseDragStart.y-evt.xy.y)>5){var start=this.map.getLonLatFromViewPortPx(this.mouseDragStart);var end=this.map.getLonLatFromViewPortPx(evt.xy);var top=Math.max(start.lat,end.lat);var bottom=Math.min(start.lat,end.lat);var left=Math.min(start.lon,end.lon);var right=Math.max(start.lon,end.lon);var bounds=new OpenLayers.Bounds(left,bottom,right,top);this.map.zoomToExtent(bounds);}else{var end=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(new OpenLayers.LonLat((end.lon),(end.lat)),this.map.getZoom()+1);}
this.removeZoomBox();}},removeZoomBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;},onWheelEvent:function(e){var inMap=false;var elem=OpenLayers.Event.element(e);while(elem!=null){if(this.map&&elem==this.map.div){inMap=true;break;}
elem=elem.parentNode;}
if(inMap){var delta=0;if(!e){e=window.event;}
if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera&&window.opera.version()<9.2){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
if(delta){e.xy=this.mousePosition;if(delta<0){this.defaultWheelDown(e);}else{this.defaultWheelUp(e);}}
OpenLayers.Event.stop(e);}},CLASS_NAME:"OpenLayers.Control.MouseDefaults"});OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{autoActivate:true,element:null,prefix:'',separator:', ',suffix:'',numDigits:5,granularity:10,emptyString:null,lastXy:null,displayProjection:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){this.map.events.register('mousemove',this,this.redraw);this.map.events.register('mouseout',this,this.reset);this.redraw();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.map.events.unregister('mousemove',this,this.redraw);this.map.events.unregister('mouseout',this,this.reset);this.element.innerHTML="";return true;}else{return false;}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.left="";this.div.top="";this.element=this.div;}
return this.div;},redraw:function(evt){var lonLat;if(evt==null){this.reset();return;}else{if(this.lastXy==null||Math.abs(evt.xy.x-this.lastXy.x)>this.granularity||Math.abs(evt.xy.y-this.lastXy.y)>this.granularity)
{this.lastXy=evt.xy;return;}
lonLat=this.map.getLonLatFromPixel(evt.xy);if(!lonLat){return;}
if(this.displayProjection){lonLat.transform(this.map.getProjectionObject(),this.displayProjection);}
this.lastXy=evt.xy;}
var newHtml=this.formatOutput(lonLat);if(newHtml!=this.element.innerHTML){this.element.innerHTML=newHtml;}},reset:function(evt){if(this.emptyString!=null){this.element.innerHTML=this.emptyString;}},formatOutput:function(lonLat){var digits=parseInt(this.numDigits);var newHtml=this.prefix+
lonLat.lon.toFixed(digits)+
this.separator+
lonLat.lat.toFixed(digits)+
this.suffix;return newHtml;},CLASS_NAME:"OpenLayers.Control.MousePosition"});OpenLayers.Control.Pan=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,direction:null,type:OpenLayers.Control.TYPE_BUTTON,initialize:function(direction,options){this.direction=direction;this.CLASS_NAME+=this.direction;OpenLayers.Control.prototype.initialize.apply(this,[options]);},trigger:function(){switch(this.direction){case OpenLayers.Control.Pan.NORTH:this.map.pan(0,-this.slideFactor);break;case OpenLayers.Control.Pan.SOUTH:this.map.pan(0,this.slideFactor);break;case OpenLayers.Control.Pan.WEST:this.map.pan(-this.slideFactor,0);break;case OpenLayers.Control.Pan.EAST:this.map.pan(this.slideFactor,0);break;}},CLASS_NAME:"OpenLayers.Control.Pan"});OpenLayers.Control.Pan.NORTH="North";OpenLayers.Control.Pan.SOUTH="South";OpenLayers.Control.Pan.EAST="East";OpenLayers.Control.Pan.WEST="West";OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,slideRatio:null,buttons:null,position:null,initialize:function(options){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this,arguments);this.removeButtons();this.buttons=null;this.position=null;},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position;this.buttons=[];var sz=new OpenLayers.Size(18,18);var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);this._addButton("panright","east-mini.png",px.add(sz.w,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);this._addButton("zoomworld","zoom-world-mini.png",centered.add(0,sz.h*4+5),sz);this._addButton("zoomout","zoom-minus-mini.png",centered.add(0,sz.h*5+5),sz);return this.div;},_addButton:function(id,img,xy,sz){var imgLocation=OpenLayers.Util.getImagesLocation()+img;var btn=OpenLayers.Util.createAlphaImageDiv(this.id+"_"+id,xy,sz,imgLocation,"absolute");this.div.appendChild(btn);OpenLayers.Event.observe(btn,"mousedown",OpenLayers.Function.bindAsEventListener(this.buttonDown,btn));OpenLayers.Event.observe(btn,"dblclick",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));OpenLayers.Event.observe(btn,"click",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));btn.action=id;btn.map=this.map;if(!this.slideRatio){var slideFactorPixels=this.slideFactor;var getSlideFactor=function(){return slideFactorPixels;};}else{var slideRatio=this.slideRatio;var getSlideFactor=function(dim){return this.map.getSize()[dim]*slideRatio;};}
btn.getSlideFactor=getSlideFactor;this.buttons.push(btn);return btn;},_removeButton:function(btn){OpenLayers.Event.stopObservingElement(btn);btn.map=null;btn.getSlideFactor=null;this.div.removeChild(btn);OpenLayers.Util.removeItem(this.buttons,btn);},removeButtons:function(){for(var i=this.buttons.length-1;i>=0;--i){this._removeButton(this.buttons[i]);}},doubleClick:function(evt){OpenLayers.Event.stop(evt);return false;},buttonDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
switch(this.action){case"panup":this.map.pan(0,-this.getSlideFactor("h"));break;case"pandown":this.map.pan(0,this.getSlideFactor("h"));break;case"panleft":this.map.pan(-this.getSlideFactor("w"),0);break;case"panright":this.map.pan(this.getSlideFactor("w"),0);break;case"zoomin":this.map.zoomIn();break;case"zoomout":this.map.zoomOut();break;case"zoomworld":this.map.zoomToMaxExtent();break;}
OpenLayers.Event.stop(evt);},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Control.Panel=OpenLayers.Class(OpenLayers.Control,{controls:null,autoActivate:true,defaultControl:null,saveState:false,activeState:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.controls=[];this.activeState={};},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this,arguments);for(var i=this.controls.length-1;i>=0;i--){if(this.controls[i].events){this.controls[i].events.un({"activate":this.redraw,"deactivate":this.redraw,scope:this});}
OpenLayers.Event.stopObservingElement(this.controls[i].panel_div);this.controls[i].panel_div=null;}
this.activeState=null;},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){var control;for(var i=0,len=this.controls.length;i<len;i++){control=this.controls[i];if(control===this.defaultControl||(this.saveState&&this.activeState[control.id])){control.activate();}}
if(this.saveState===true){this.defaultControl=null;}
this.redraw();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){var control;for(var i=0,len=this.controls.length;i<len;i++){control=this.controls[i];this.activeState[control.id]=control.deactivate();}
return true;}else{return false;}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.addControlsToMap(this.controls);return this.div;},redraw:function(){if(this.div.children.length>0){for(var l=this.div.children.length,i=l-1;i>=0;i--){this.div.removeChild(this.div.children[i]);}}
this.div.innerHTML="";if(this.active){for(var i=0,len=this.controls.length;i<len;i++){var element=this.controls[i].panel_div;if(this.controls[i].active){element.className=this.controls[i].displayClass+"ItemActive";}else{element.className=this.controls[i].displayClass+"ItemInactive";}
this.div.appendChild(element);}}},activateControl:function(control){if(!this.active){return false;}
if(control.type==OpenLayers.Control.TYPE_BUTTON){control.trigger();this.redraw();return;}
if(control.type==OpenLayers.Control.TYPE_TOGGLE){if(control.active){control.deactivate();}else{control.activate();}
this.redraw();return;}
var c;for(var i=0,len=this.controls.length;i<len;i++){c=this.controls[i];if(c!=control&&(c.type===OpenLayers.Control.TYPE_TOOL||c.type==null)){c.deactivate();}}
control.activate();},addControls:function(controls){if(!(controls instanceof Array)){controls=[controls];}
this.controls=this.controls.concat(controls);for(var i=0,len=controls.length;i<len;i++){var element=document.createElement("div");controls[i].panel_div=element;if(controls[i].title!=""){controls[i].panel_div.title=controls[i].title;}
OpenLayers.Event.observe(controls[i].panel_div,"click",OpenLayers.Function.bind(this.onClick,this,controls[i]));OpenLayers.Event.observe(controls[i].panel_div,"dblclick",OpenLayers.Function.bind(this.onDoubleClick,this,controls[i]));OpenLayers.Event.observe(controls[i].panel_div,"mousedown",OpenLayers.Function.bindAsEventListener(OpenLayers.Event.stop));}
if(this.map){this.addControlsToMap(controls);this.redraw();}},addControlsToMap:function(controls){var control;for(var i=0,len=controls.length;i<len;i++){control=controls[i];if(control.autoActivate===true){control.autoActivate=false;this.map.addControl(control);control.autoActivate=true;}else{this.map.addControl(control);control.deactivate();}
control.events.on({"activate":this.redraw,"deactivate":this.redraw,scope:this});}},onClick:function(ctrl,evt){OpenLayers.Event.stop(evt?evt:window.event);this.activateControl(ctrl);},onDoubleClick:function(ctrl,evt){OpenLayers.Event.stop(evt?evt:window.event);},getControlsBy:function(property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this.controls,function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getControlsByName:function(match){return this.getControlsBy("name",match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},CLASS_NAME:"OpenLayers.Control.Panel"});OpenLayers.Control.Scale=OpenLayers.Class(OpenLayers.Control,{element:null,geodesic:false,initialize:function(element,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.element=OpenLayers.Util.getElement(element);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.element=document.createElement("div");this.div.appendChild(this.element);}
this.map.events.register('moveend',this,this.updateScale);this.updateScale();return this.div;},updateScale:function(){var scale;if(this.geodesic===true){var units=this.map.getUnits();if(!units){return;}
var inches=OpenLayers.INCHES_PER_UNIT;scale=(this.map.getGeodesicPixelSize().w||0.000001)*inches["km"]*OpenLayers.DOTS_PER_INCH;}else{scale=this.map.getScale();}
if(!scale){return;}
if(scale>=9500&&scale<=950000){scale=Math.round(scale/1000)+"K";}else if(scale>=950000){scale=Math.round(scale/1000000)+"M";}else{scale=Math.round(scale);}
this.element.innerHTML=OpenLayers.i18n("scale",{'scaleDenom':scale});},CLASS_NAME:"OpenLayers.Control.Scale"});OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,geodesic:false,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.eTop){this.eTop=document.createElement("div");this.eTop.className=this.displayClass+"Top";var theLen=this.topInUnits.length;this.div.appendChild(this.eTop);if((this.topOutUnits=="")||(this.topInUnits=="")){this.eTop.style.visibility="hidden";}else{this.eTop.style.visibility="visible";}
this.eBottom=document.createElement("div");this.eBottom.className=this.displayClass+"Bottom";this.div.appendChild(this.eBottom);if((this.bottomOutUnits=="")||(this.bottomInUnits=="")){this.eBottom.style.visibility="hidden";}else{this.eBottom.style.visibility="visible";}}
this.map.events.register('moveend',this,this.update);this.update();return this.div;},getBarLen:function(maxLen){var digits=parseInt(Math.log(maxLen)/Math.log(10));var pow10=Math.pow(10,digits);var firstChar=parseInt(maxLen/pow10);var barLen;if(firstChar>5){barLen=5;}else if(firstChar>2){barLen=2;}else{barLen=1;}
return barLen*pow10;},update:function(){var res=this.map.getResolution();if(!res){return;}
var curMapUnits=this.map.getUnits();var inches=OpenLayers.INCHES_PER_UNIT;var maxSizeData=this.maxWidth*res*inches[curMapUnits];var geodesicRatio=1;if(this.geodesic===true){var maxSizeGeodesic=(this.map.getGeodesicPixelSize().w||0.000001)*this.maxWidth;var maxSizeKilometers=maxSizeData/inches["km"];geodesicRatio=maxSizeGeodesic/maxSizeKilometers;maxSizeData*=geodesicRatio;}
var topUnits;var bottomUnits;if(maxSizeData>100000){topUnits=this.topOutUnits;bottomUnits=this.bottomOutUnits;}else{topUnits=this.topInUnits;bottomUnits=this.bottomInUnits;}
var topMax=maxSizeData/inches[topUnits];var bottomMax=maxSizeData/inches[bottomUnits];var topRounded=this.getBarLen(topMax);var bottomRounded=this.getBarLen(bottomMax);topMax=topRounded/inches[curMapUnits]*inches[topUnits];bottomMax=bottomRounded/inches[curMapUnits]*inches[bottomUnits];var topPx=topMax/res/geodesicRatio;var bottomPx=bottomMax/res/geodesicRatio;if(this.eBottom.style.visibility=="visible"){this.eBottom.style.width=Math.round(bottomPx)+"px";this.eBottom.innerHTML=bottomRounded+" "+bottomUnits;}
if(this.eTop.style.visibility=="visible"){this.eTop.style.width=Math.round(topPx)+"px";this.eTop.innerHTML=topRounded+" "+topUnits;}},CLASS_NAME:"OpenLayers.Control.ScaleLine"});OpenLayers.Control.ZoomIn=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){this.map.zoomIn();},CLASS_NAME:"OpenLayers.Control.ZoomIn"});OpenLayers.Control.ZoomOut=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){this.map.zoomOut();},CLASS_NAME:"OpenLayers.Control.ZoomOut"});OpenLayers.Control.ZoomToMaxExtent=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){if(this.map){this.map.zoomToMaxExtent();}},CLASS_NAME:"OpenLayers.Control.ZoomToMaxExtent"});OpenLayers.Event={observers:false,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},isRightClick:function(event){return(((event.which)&&(event.which==3))||((event.button)&&(event.button==2)));},stop:function(event,allowDefault){if(!allowDefault){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}}
if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},findElement:function(event,tagName){var element=OpenLayers.Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase()))){element=element.parentNode;}
return element;},observe:function(elementParam,name,observer,useCapture){var element=OpenLayers.Util.getElement(elementParam);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent)){name='keydown';}
if(!this.observers){this.observers={};}
if(!element._eventCacheID){var idPrefix="eventCacheID_";if(element.id){idPrefix=element.id+"_"+idPrefix;}
element._eventCacheID=OpenLayers.Util.createUniqueID(idPrefix);}
var cacheID=element._eventCacheID;if(!this.observers[cacheID]){this.observers[cacheID]=[];}
this.observers[cacheID].push({'element':element,'name':name,'observer':observer,'useCapture':useCapture});if(element.addEventListener){element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){element.attachEvent('on'+name,observer);}},stopObservingElement:function(elementParam){var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[cacheID]);},_removeElementObservers:function(elementObservers){if(elementObservers){for(var i=elementObservers.length-1;i>=0;i--){var entry=elementObservers[i];var args=new Array(entry.element,entry.name,entry.observer,entry.useCapture);var removed=OpenLayers.Event.stopObserving.apply(this,args);}}},stopObserving:function(elementParam,name,observer,useCapture){useCapture=useCapture||false;var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;if(name=='keypress'){if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent){name='keydown';}}
var foundEntry=false;var elementObservers=OpenLayers.Event.observers[cacheID];if(elementObservers){var i=0;while(!foundEntry&&i<elementObservers.length){var cacheEntry=elementObservers[i];if((cacheEntry.name==name)&&(cacheEntry.observer==observer)&&(cacheEntry.useCapture==useCapture)){elementObservers.splice(i,1);if(elementObservers.length==0){delete OpenLayers.Event.observers[cacheID];}
foundEntry=true;break;}
i++;}}
if(foundEntry){if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}}
return foundEntry;},unloadCache:function(){if(OpenLayers.Event&&OpenLayers.Event.observers){for(var cacheID in OpenLayers.Event.observers){var elementObservers=OpenLayers.Event.observers[cacheID];OpenLayers.Event._removeElementObservers.apply(this,[elementObservers]);}
OpenLayers.Event.observers=false;}},CLASS_NAME:"OpenLayers.Event"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);if(window.Event){OpenLayers.Util.applyDefaults(window.Event,OpenLayers.Event);}else{var Event=OpenLayers.Event;}
OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","rightclick","dblrightclick","resize","focus","blur"],listeners:null,object:null,element:null,eventTypes:null,eventHandler:null,fallThrough:null,includeXY:false,clearMouseListener:null,initialize:function(object,element,eventTypes,fallThrough,options){OpenLayers.Util.extend(this,options);this.object=object;this.fallThrough=fallThrough;this.listeners={};this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);this.clearMouseListener=OpenLayers.Function.bind(this.clearMouseCache,this);this.eventTypes=[];if(eventTypes!=null){for(var i=0,len=eventTypes.length;i<len;i++){this.addEventType(eventTypes[i]);}}
if(element!=null){this.attachToElement(element);}},destroy:function(){if(this.element){OpenLayers.Event.stopObservingElement(this.element);if(this.element.hasScrollEvent){OpenLayers.Event.stopObserving(window,"scroll",this.clearMouseListener);}}
this.element=null;this.listeners=null;this.object=null;this.eventTypes=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){if(!this.listeners[eventName]){this.eventTypes.push(eventName);this.listeners[eventName]=[];}},attachToElement:function(element){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}
this.element=element;for(var i=0,len=this.BROWSER_EVENTS.length;i<len;i++){var eventType=this.BROWSER_EVENTS[i];this.addEventType(eventType);OpenLayers.Event.observe(element,eventType,this.eventHandler);}
OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},on:function(object){for(var type in object){if(type!="scope"){this.register(type,object.scope,object[type]);}}},register:function(type,obj,func){if((func!=null)&&(OpenLayers.Util.indexOf(this.eventTypes,type)!=-1)){if(obj==null){obj=this.object;}
var listeners=this.listeners[type];listeners.push({obj:obj,func:func});}},registerPriority:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
var listeners=this.listeners[type];if(listeners!=null){listeners.unshift({obj:obj,func:func});}}},un:function(object){for(var type in object){if(type!="scope"){this.unregister(type,object.scope,object[type]);}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
var listeners=this.listeners[type];if(listeners!=null){for(var i=0,len=listeners.length;i<len;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){var listeners=this.listeners[type];if(!listeners||listeners.length==0){return;}
if(evt==null){evt={};}
evt.object=this.object;evt.element=this.element;if(!evt.type){evt.type=type;}
var listeners=listeners.slice(),continueChain;for(var i=0,len=listeners.length;i<len;i++){var callback=listeners[i];continueChain=callback.func.apply(callback.obj,[evt]);if((continueChain!=undefined)&&(continueChain==false)){break;}}
if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}
return continueChain;},handleBrowserEvent:function(evt){if(this.includeXY){evt.xy=this.getMousePosition(evt);}
this.triggerEvent(evt.type,evt);},clearMouseCache:function(){this.element.scrolls=null;this.element.lefttop=null;this.element.offsets=null;},getMousePosition:function(evt){if(!this.includeXY){this.clearMouseCache();}else if(!this.element.hasScrollEvent){OpenLayers.Event.observe(window,"scroll",this.clearMouseListener);this.element.hasScrollEvent=true;}
if(!this.element.scrolls){this.element.scrolls=[(document.documentElement.scrollLeft||document.body.scrollLeft),(document.documentElement.scrollTop||document.body.scrollTop)];}
if(!this.element.lefttop){this.element.lefttop=[(document.documentElement.clientLeft||0),(document.documentElement.clientTop||0)];}
if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);this.element.offsets[0]+=this.element.scrolls[0];this.element.offsets[1]+=this.element.scrolls[1];}
return new OpenLayers.Pixel((evt.clientX+this.element.scrolls[0])-this.element.offsets[0]
-this.element.lefttop[0],(evt.clientY+this.element.scrolls[1])-this.element.offsets[1]
-this.element.lefttop[1]);},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:false,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;},destroy:function(){},read:function(data){OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));},write:function(object){OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Lang["ar"]=OpenLayers.Util.applyDefaults({'permalink':"وصلة دائمة",'baseLayer':"الطبقة الاساسية",'readNotImplemented':"القراءة غير محققة.",'writeNotImplemented':"الكتابة غير محققة",'errorLoadingGML':"خطأ عند تحميل الملف جي ام ال ${url}",'scale':"النسبة = 1 : ${scaleDenom}",'W':"غ",'E':"شر",'N':"شم",'S':"ج"});OpenLayers.Lang["be-tarask"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Неапрацаваны вынік запыту ${statusText}",'permalink':"Сталая спасылка",'overlays':"Слаі",'baseLayer':"Базавы слой",'sameProjection':"Аглядная мапа працуе толькі калі яна мае тую ж праекцыю, што і асноўная мапа",'readNotImplemented':"Функцыянальнасьць чытаньня ня створаная.",'writeNotImplemented':"Функцыянальнасьць запісу ня створаная.",'noFID':"Немагчыма абнавіць магчымасьць, для якога не існуе FID.",'errorLoadingGML':"Памылка загрузкі файла GML ${url}",'browserNotSupported':"Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}",'componentShouldBe':"addFeatures : кампанэнт павінен быць ${geomType}",'getFeatureError':"getFeatureFromEvent выкліканы для слоя бяз рэндэру. Звычайна гэта азначае, што Вы зьнішчылі слой, але пакінулі зьвязаны зь ім апрацоўшчык.",'minZoomLevelError':"Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што  гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-транзакцыя: ПОСЬПЕХ ${response}",'commitFailed':"WFS-транзакцыя: ПАМЫЛКА ${response}",'googleWarning':"Не атрымалася загрузіць слой Google. \x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3e Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'getLayerWarning':"Немагчыма загрузіць слой ${layerType}.\x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3eХутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'scale':"Маштаб = 1 : ${scaleDenom}",'W':"З",'E':"У",'N':"Пн",'S':"Пд",'layerAlreadyAdded':"Вы паспрабавалі дадаць слой ${layerName} на мапу, але ён ужо дададзены",'reprojectDeprecated':"Вы выкарыстоўваеце ўстаноўку \'reproject\' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}.",'boundsAddError':"Вам неабходна падаць абодва значэньні x і y для функцыі складаньня.",'lonlatAddError':"Вам неабходна падаць абодва значэньні lon і lat для функцыі складаньня.",'pixelAddError':"Вам неабходна падаць абодва значэньні x і y для функцыі складаньня.",'unsupportedGeometryType':"Тып геамэтрыі не падтрымліваецца: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: верагодна элемэнт з ідэнтыфікатарам ${elemId} займае няслушнае месца.",'filterEvaluateNotImplemented':"evaluate не рэалізаваны для гэтага тыпу фільтру."});OpenLayers.Lang["bg"]=OpenLayers.Util.applyDefaults({'permalink':"Постоянна препратка",'baseLayer':"Основен слой",'errorLoadingGML':"Грешка при зареждане на GML файл ${url}",'scale':"Мащаб = 1 : ${scaleDenom}",'layerAlreadyAdded':"Опитахте да добавите слой ${layerName} в картата, но той вече е добавен",'methodDeprecated':"Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}."});OpenLayers.Lang["br"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Distro evel reked anveret ${statusText}",'permalink':"Peurliamm",'overlays':"Gwiskadoù",'baseLayer':"Gwiskad diazez",'sameProjection':"Ne\'z ar gartenn lec\'hiañ en-dro nemet pa vez heñvel ar banndres anezhi ha hini ar gartenn bennañ",'readNotImplemented':"N\'eo ket emplementet al lenn.",'writeNotImplemented':"N\'eo ket emplementet ar skrivañ.",'noFID':"N\'haller ket hizivaat un elfenn ma n\'eus ket a niverenn-anaout (FID) eviti.",'errorLoadingGML':"Fazi e-ser kargañ ar restr GML ${url}",'browserNotSupported':"N\'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}",'componentShouldBe':"addFeatures : bez\' e tlefe ar parzh besañ eus ar seurt ${geomType}",'getFeatureError':"Galvet eo bet getFeatureFromEvent called war ur gwiskad hep daskorer. Kement-se a dalvez ez eus bet freuzet ur gwiskad hag hoc\'h eus miret un embreger bennak stag outañ.",'minZoomLevelError':"Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n\'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c\'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Treuzgread WFS : MAT EO ${response}",'commitFailed':"Treuzgread WFS Transaction: C\'HWITET ${response}",'googleWarning':"N\'eus ket bet gallet kargañ ar gwiskad Google ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het levraoueg Google Maps pe neuze ne glot ket an alc\'hwez API gant ho lec\'hienn.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'getLayerWarning':"N\'haller ket kargañ ar gwiskad ${layerType} ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het mat al levraoueg ${layerLib}.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit gouzout penaos reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'scale':"Skeul = 1 : ${scaleDenom}",'W':"K",'E':"R",'N':"N",'S':"S",'layerAlreadyAdded':"Klasket hoc\'h eus ouzhpennañ ar gwiskad : ${layerName} d\'ar gartenn, met ouzhpennet e oa bet c\'hoazh",'reprojectDeprecated':"Emaoc\'h oc\'h implijout an dibarzh \'reproject\' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c\'horre kartennoù diazez kenwerzhel, un dra hag a c\'haller ober bremañ gant an arc\'hwel dre skor banndres boullek Mercator. Muioc\'h a ditouroù a c\'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas.",'boundsAddError':"Rekis eo tremen an div dalvoudenn x ha y d\'an arc\'hwel add.",'lonlatAddError':"Rekis eo tremen an div dalvoudenn hedred ha ledred d\'an arc\'hwel add.",'pixelAddError':"Rekis eo tremen an div dalvoudenn x ha y d\'an arc\'hwel add.",'unsupportedGeometryType':"Seurt mentoniezh anskoret : ${geomType}",'pagePositionFailed':"C\'hwitet eo OpenLayers.Util.pagePosition : marteze emañ lec\'hiet fall an elfenn id ${elemId}.",'filterEvaluateNotImplemented':"N\'eo ket bet emplementet ar priziañ evit seurt siloù c\'hoazh."});OpenLayers.Lang["el"]=OpenLayers.Util.applyDefaults({'scale':"Κλίμακα ~ 1 : ${scaleDenom}"});OpenLayers.Lang.en={'unhandledRequest':"Unhandled request return ${statusText}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Base Layer",'sameProjection':"The overview map only works when it is in the same projection as the main map",'readNotImplemented':"Read not implemented.",'writeNotImplemented':"Write not implemented.",'noFID':"Can't update a feature for which there is no FID.",'errorLoadingGML':"Error in loading GML file ${url}",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",'componentShouldBe':"addFeatures : component should be an ${geomType}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. This usually means you "+"destroyed a layer, but not some handler which is associated with it.",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS ${response}",'commitFailed':"WFS Transaction: FAILED ${response}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the ${layerLib} library "+"script was not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>click here</a>",'scale':"Scale = 1 : ${scaleDenom}",'W':'W','E':'E','N':'N','S':'S','graticule':'Graticule','layerAlreadyAdded':"You tried to add the layer: ${layerName} to the map, but it has already been added",'reprojectDeprecated':"You are using the 'reproject' option "+"on the ${layerName} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",'filterEvaluateNotImplemented':"evaluate is not implemented for this filter type.",'end':''};OpenLayers.Lang["fi"]=OpenLayers.Util.applyDefaults({'permalink':"Ikilinkki",'overlays':"Kerrokset",'baseLayer':"Peruskerros",'sameProjection':"Yleiskuvakarttaa voi käyttää vain, kun sillä on sama projektio kuin pääkartalla.",'W':"L",'E':"I",'N':"P",'S':"E"});OpenLayers.Lang["fur"]=OpenLayers.Util.applyDefaults({'permalink':"Leam Permanent",'overlays':"Livei parsore",'baseLayer':"Livel di base",'browserNotSupported':"Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}",'scale':"Scjale = 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S"});OpenLayers.Lang["gl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Solicitude non xerada; a resposta foi: ${statusText}",'permalink':"Ligazón permanente",'overlays':"Capas superpostas",'baseLayer':"Capa base",'sameProjection':"A vista xeral do mapa só funciona cando está na mesma proxección có mapa principal",'readNotImplemented':"Lectura non implementada.",'writeNotImplemented':"Escritura non implementada.",'noFID':"Non se pode actualizar a funcionalidade para a que non hai FID.",'errorLoadingGML':"Erro ao cargar o ficheiro GML ${url}",'browserNotSupported':"O seu navegador non soporta a renderización de vectores. Os renderizadores soportados actualmente son:\n${renderers}",'componentShouldBe':"addFeatures: o compoñente debera ser de tipo ${geomType}",'getFeatureError':"getFeatureFromEvent ten sido chamado a unha capa sen renderizador. Isto normalmente significa que destruíu unha capa, mais non o executador que está asociado con ela.",'minZoomLevelError':"A propiedade minZoomLevel é só para uso conxuntamente coas capas FixedZoomLevels-descendent. O feito de que esa capa wfs verifique o minZoomLevel é unha reliquia do pasado. Non podemos, con todo, eliminala sen a posibilidade de non romper as aplicacións baseadas en OL que poidan depender dela. Por iso a estamos deixando obsoleta (a comprobación minZoomLevel de embaixo será eliminada na versión 3.0). Por favor, no canto diso use o axuste de resolución mín/máx tal e como está descrito aquí: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacción WFS: ÉXITO ${response}",'commitFailed':"Transacción WFS: FALLIDA ${response}",'googleWarning':"A capa do Google non puido cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría do Google Maps ou ben non foi incluída ou ben non contén a clave API correcta para o seu sitio.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e",'getLayerWarning':"A capa ${layerType} foi incapaz de cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría ${layerLib} non foi ben incluída.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e",'scale':"Escala = 1 : ${scaleDenom}",'W':"O",'E':"L",'N':"N",'S':"S",'layerAlreadyAdded':"Intentou engadir a capa: ${layerName} ao mapa, pero xa fora engadida",'reprojectDeprecated':"Está usando a opción \"reproject\" na capa ${layerName}. Esta opción está obsoleta: o seu uso foi deseñado para a visualización de datos sobre mapas base comerciais, pero esta funcionalidade debera agora ser obtida utilizando a proxección Spherical Mercator. Hai dispoñible máis información en http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método está obsoleto e será eliminado na versión 3.0. Por favor, no canto deste use ${newMethod}.",'boundsAddError':"Debe achegar os valores x e y á función add.",'lonlatAddError':"Debe achegar tanto o valor lon coma o lat á función add.",'pixelAddError':"Debe achegar os valores x e y á función add.",'unsupportedGeometryType':"Tipo xeométrico non soportado: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition fallou: o elemento con id ${elemId} pode non estar na súa posición.",'filterEvaluateNotImplemented':"avaliar non está implementado para este tipo de filtro."});OpenLayers.Lang["gsw"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nit behandleti Aafrogsruckmäldig ${statusText}",'permalink':"Permalink",'overlays':"Iberlagerige",'baseLayer':"Grundcharte",'sameProjection':"D Ibersichts-Charte funktioniert nume, wänn si di glych Projäktion brucht wie d Hauptcharte",'readNotImplemented':"Läse nit implementiert.",'writeNotImplemented':"Schrybe nit implementiert.",'noFID':"E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.",'errorLoadingGML':"Fähler bim Lade vu dr GML-Datei ${url}",'browserNotSupported':"Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}",'componentShouldBe':"addFeatures : Komponänt sott dr Typ ${geomType} syy",'getFeatureError':"getFeatureFromEvent isch uf eme Layer ohni Renderer ufgruefe wore. Des heisst normalerwys, ass Du e Layer kaputt gmacht hesch, aber nit dr Handler, wu derzue ghert.",'minZoomLevelError':"D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge.  Us däm Grund het die Funktion d Eigeschaft \'deprecated\' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transaktion: ERFOLGRYCH ${response}",'commitFailed':"WFS-Transaktion: FÄHLGSCHLAA ${response}",'googleWarning':"Dr Google-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'getLayerWarning':"Dr ${layerType}-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr \'${layerLib}\'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vu Layer \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'scale':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'layerAlreadyAdded':"Du hesch versuecht dää Layer in d Charte yyzfiege: ${layerName}, aber är isch schoi yygfiegt",'reprojectDeprecated':"Du bruchsch d \'reproject\'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go   Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}.",'boundsAddError':"Du muesch e x-Wärt un e y-Wärt yygee bi dr Zuefieg-Funktion",'lonlatAddError':"Du meusch e Lengi- un e Breiti-Grad yygee bi dr Zuefieg-Funktion.",'pixelAddError':"Du muesch x- un y-Wärt aagee bi dr Zuefieg-Funktion.",'unsupportedGeometryType':"Nit unterstitze Geometrii-Typ: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition fählgschlaa: Elemänt mit ID ${elemId} isch villicht falsch gsetzt.",'filterEvaluateNotImplemented':"evaluiere isch nit implemäntiert in däm Filtertyp."});OpenLayers.Lang["hr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nepodržani zahtjev ${statusText}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Osnovna karta",'sameProjection':"Pregledna karta radi jedino kao je u istoj projekciji kao i glava karta",'readNotImplemented':"Čitanje nije implementirano.",'writeNotImplemented':"Pisanje nije implementirano.",'noFID':"Ne mogu ažurirati značajku za koju ne postoji FID.",'errorLoadingGML':"Greška u učitavanju GML datoteke ${url}",'browserNotSupported':"Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}",'componentShouldBe':"addFeatures : komponenta bi trebala biti ${geomType}",'getFeatureError':"getFeatureFromEvent je pozvao Layer bez renderera. Ovo obično znači da ste uništiili Layer, a ne neki Handler koji je povezan s njim.",'commitSuccess':"WFS Transakcija: USPJEŠNA ${response}",'commitFailed':"WFS Transakcija: NEUSPJEŠNA ${response}",'scale':"Mjerilo = 1 : ${scaleDenom}",'layerAlreadyAdded':"Pokušali ste dodati layer:  ${layerName} na kartu, ali je već dodan",'methodDeprecated':"Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}.",'boundsAddError':"Morate dati obje vrijednosti ,  x i y  da bi dodali funkciju.",'lonlatAddError':"Morate dati obje vrijednosti , (lon i lat) da bi dodali funkciju.",'pixelAddError':"Morate dati obje vrijednosti ,  x i y  da bi dodali funkciju.",'unsupportedGeometryType':"Nepodržani tip geometrije: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition nije uspjelo: element sa id ${elemId} može biti krivo smješten."});OpenLayers.Lang["hsb"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Wotmołwa njewobdźěłaneho naprašowanja ${statusText}",'permalink':"Trajny wotkaz",'overlays':"Naworštowanja",'baseLayer':"Zakładna runina",'sameProjection':"Přehladowa karta jenož funguje, hdyž je w samsnej projekciji kaž hłowna karta",'readNotImplemented':"Čitanje njeimplementowane.",'writeNotImplemented':"Pisanje njeimplementowane.",'noFID':"Funkcija, za kotruž FID njeje, njeda so aktualizować.",'errorLoadingGML':"Zmylk při začitowanju dataje ${url}",'browserNotSupported':"Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}",'componentShouldBe':"addFeatures: komponenta měła ${geomType} być",'getFeatureError':"getFeatureFromEvent bu na woršće bjez rysowak zawołany. To zwjetša woznamjenja, zo sy worštu zničił, ale nic wobdźěłak, kotryž je z njej zwjazany.",'minZoomLevelError':"Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transakcija: WUSPĚŠNA ${response}",'commitFailed':"WFS-Transakcija: NJEPORADŹENA ${response}",'googleWarning':"Woršta Google njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'getLayerWarning':"Woršta ${layerType} njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'scale':"Měritko = 1 : ${scaleDenom}",'W':"Z",'E':"W",'N':"S",'S':"J",'layerAlreadyAdded':"Sy spytał runinu ${layerName} karće dodać, ale je so hižo dodała",'reprojectDeprecated':"Wužiwaš opciju \"reproject\" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.",'methodDeprecated':"Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho.",'boundsAddError':"Dyrbiš hódnotu x kaž tež y funkciji \"add\" přepodać.",'lonlatAddError':"Dyrbiš hódnotu lon kaž tež lat funkciji \"add\" přepodać.",'pixelAddError':"Dyrbiš hódnotu x kaž tež y funkciji \"add\" přepodać.",'unsupportedGeometryType':"Njepodpěrowany geometrijowy typ: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition je so njeporadźił: element z id ${elemId} bu snano wopak zaměstnjeny.",'filterEvaluateNotImplemented':"wuhódnoćenje njeje za tutón filtrowy typ implementowany."});OpenLayers.Lang["hu"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nem kezelt kérés visszatérése ${statusText}",'permalink':"Permalink",'overlays':"Rávetítések",'baseLayer':"Alapréteg",'sameProjection':"Az áttekintő térkép csak abban az esetben működik, ha ugyanazon a vetületen van, mint a fő térkép.",'readNotImplemented':"Olvasás nincs végrehajtva.",'writeNotImplemented':"Írás nincs végrehajtva.",'noFID':"Nem frissíthető olyan jellemző, amely nem rendelkezik FID-del.",'errorLoadingGML':"Hiba GML-fájl betöltésekor ${url}",'browserNotSupported':"A böngészője nem támogatja a vektoros renderelést. A jelenleg támogatott renderelők:\n${renderers}",'componentShouldBe':"addFeatures : az összetevőnek ilyen típusúnak kell lennie: ${geomType}",'getFeatureError':"getFeatureFromEvent réteget hívott meg renderelő nélkül. Ez rendszerint azt jelenti, hogy megsemmisített egy fóliát, de néhány ahhoz társított kezelőt nem.",'minZoomLevelError':"A minZoomLevel tulajdonságot csak a következővel való használatra szánták: FixedZoomLevels-leszármazott fóliák. Ez azt jelenti, hogy a minZoomLevel wfs fólia jelölőnégyzetei már a múlté. Mi azonban nem távolíthatjuk el annak a veszélye nélkül, hogy az esetlegesen ettől függő OL alapú alkalmazásokat tönkretennénk. Ezért ezt érvénytelenítjük -- a minZoomLevel az alul levő jelölőnégyzet a 3.0-s verzióból el lesz távolítva. Kérjük, helyette használja a  min/max felbontás beállítást, amelyről az alábbi helyen talál leírást: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS tranzakció: SIKERES ${response}",'commitFailed':"WFS tranzakció: SIKERTELEN ${response}",'googleWarning':"A Google fólia betöltése sikertelen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a Google Maps könyvtár parancsfájlja nem található, vagy nem tartalmazza az Ön oldalához tartozó megfelelő API-kulcsot.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e",'getLayerWarning':"A(z) ${layerType} fólia nem töltődött be helyesen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a(z) ${layerLib} könyvtár parancsfájlja helytelen.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e",'scale':"Lépték = 1 : ${scaleDenom}",'W':"Ny",'E':"K",'N':"É",'S':"D",'layerAlreadyAdded':"Megpróbálta hozzáadni a(z) ${layerName} fóliát a térképhez, de az már hozzá van adva",'reprojectDeprecated':"Ön a \'reproject\' beállítást használja a(z) ${layerName} fólián. Ez a beállítás érvénytelen: használata az üzleti alaptérképek fölötti adatok megjelenítésének támogatására szolgált, de ezt a funkció ezentúl a Gömbi Mercator használatával érhető el. További információ az alábbi helyen érhető el: http://trac.openlayers.org/wiki/SphericalMercator",'methodDeprecated':"Ez a módszer érvénytelenítve lett és a 3.0-s verzióból el lesz távolítva. Használja a(z) ${newMethod} módszert helyette.",'boundsAddError':"Az x és y értékeknek egyaránt meg kell felelnie, hogy a funkciót hozzáadhassa.",'lonlatAddError':"A hossz. és szél. értékeknek egyaránt meg kell felelnie, hogy a funkciót hozzáadhassa.",'pixelAddError':"Az x és y értékeknek egyaránt meg kell felelnie, hogy a funkciót hozzáadhassa.",'unsupportedGeometryType':"Nem támogatott geometriatípus: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition sikertelen: lehetséges, hogy a(z) ${elemId} azonosítójú elem téves helyre került.",'filterEvaluateNotImplemented':"ennél a szűrőtípusnál kiértékelés nem hajtódik végre."});OpenLayers.Lang["ia"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Le responsa a un requesta non esseva maneate: ${statusText}",'permalink':"Permaligamine",'overlays':"Superpositiones",'baseLayer':"Strato de base",'sameProjection':"Le mini-carta functiona solmente si illo es in le mesme projection que le carta principal",'readNotImplemented':"Lectura non implementate.",'writeNotImplemented':"Scriptura non implementate.",'noFID':"Non pote actualisar un elemento sin FID.",'errorLoadingGML':"Error al cargamento del file GML ${url}",'browserNotSupported':"Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}",'componentShouldBe':"addFeatures: le componente debe esser del typo ${geomType}",'getFeatureError':"getFeatureFromEvent ha essite appellate in un strato sin renditor. Isto significa generalmente que tu ha destruite un strato, ma lassava un gestor associate con illo.",'minZoomLevelError':"Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS: SUCCESSO ${response}",'commitFailed':"Transaction WFS: FALLEVA ${response}",'googleWarning':"Le strato Google non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicca hic\x3c/a",'getLayerWarning':"Le strato ${layerType} non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicca hic\x3c/a\x3e",'scale':"Scala = 1 : ${scaleDenom}",'W':"W",'E':"E",'N':"N",'S':"S",'layerAlreadyAdded':"Tu tentava adder le strato: ${layerName} al carta, ma illo es ja presente",'reprojectDeprecated':"Tu usa le option \'reproject\' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco.",'boundsAddError':"Tu debe passar le duo valores x e y al function add.",'lonlatAddError':"Tu debe passar le duo valores lon e lat al function add.",'pixelAddError':"Tu debe passar le duo valores x e y al function add.",'unsupportedGeometryType':"Typo de geometria non supportate: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition falleva: le elemento con id ${elemId} pote esser mal placiate.",'filterEvaluateNotImplemented':"\"evaluate\" non es implementate pro iste typo de filtro."});OpenLayers.Lang["id"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Permintaan yang tak tertangani menghasilkan ${statusText}",'permalink':"Pranala permanen",'overlays':"Hamparan",'baseLayer':"Lapisan Dasar",'sameProjection':"Peta tinjauan hanya bekerja bila dalam proyeksi yang sama dengan peta utama",'readNotImplemented':"Membaca tidak diterapkan.",'writeNotImplemented':"Menyimpan tidak diterapkan.",'noFID':"Tidak dapat memperbarui fitur yang tidak memiliki FID.",'errorLoadingGML':"Kesalahan dalam memuat berkas GML ${url}",'browserNotSupported':"Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}",'componentShouldBe':"addFeatures : komponen harus berupa ${geomType}",'getFeatureError':"getFeatureFromEvent diterapkan pada lapisan tanpa penggambar. Ini biasanya berarti Anda menghapus sebuah lapisan, tetapi tidak menghapus penangan yang terkait dengannya.",'minZoomLevelError':"Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaksi: BERHASIL ${respon}",'commitFailed':"WFS Transaksi: GAGAL ${respon}",'googleWarning':"Lapisan Google tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'getLayerWarning':"Lapisan ${layerType} tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'scale':"Sekala = 1 : ${scaleDenom}",'W':"B",'E':"T",'N':"U",'S':"S",'layerAlreadyAdded':"Anda mencoba menambahkan lapisan: ${layerName} ke dalam peta, tapi lapisan itu telah ditambahkan",'reprojectDeprecated':"Anda menggunakan opsi \'reproject\' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}.",'boundsAddError':"Anda harus memberikan kedua nilai x dan y ke fungsi penambah.",'lonlatAddError':"Anda harus memberikan kedua nilai lon dan lat ke fungsi penambah.",'pixelAddError':"Anda harus memberikan kedua nilai x dan y ke fungsi penambah.",'unsupportedGeometryType':"Tipe geometri tak didukung: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition gagal: elemen dengan id ${elemId} mungkin salah tempat.",'filterEvaluateNotImplemented':"evaluasi tidak tersedia untuk tipe filter ini."});OpenLayers.Lang["io"]=OpenLayers.Util.applyDefaults({'scale':"Skalo = 1 : ${scaleDenom}"});OpenLayers.Lang["is"]=OpenLayers.Util.applyDefaults({'permalink':"Varanlegur tengill",'overlays':"Þekjur",'baseLayer':"Grunnlag",'sameProjection':"Yfirlitskortið virkar aðeins ef það er í sömu vörpun og aðalkortið",'readNotImplemented':"Skrifun er óútfærð.",'writeNotImplemented':"Lestur er óútfærður.",'errorLoadingGML':"Villa kom upp við að hlaða inn GML skránni ${url}",'scale':"Skali = 1 : ${scaleDenom}",'layerAlreadyAdded':"Þú reyndir að bæta laginu ${layerName} á kortið en það er þegar búið að bæta því við",'methodDeprecated':"Þetta fall hefur verið úrelt og verður fjarlægt í 3.0. Notaðu ${newMethod} í staðin."});OpenLayers.Lang["ja"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"未処理の要求は ${statusText} を返します",'permalink':"パーマリンク",'overlays':"オーバーレイ",'baseLayer':"基底レイヤー",'sameProjection':"概観地図はメインの地図と同じ投影法をとる場合のみ機能します",'readNotImplemented':"読み込みは実装されていません。",'writeNotImplemented':"書き込みは実装されていません。",'noFID':"FID のない地物は更新できません。",'errorLoadingGML':"GML ファイル ${url} の読み込みエラー",'browserNotSupported':"あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}",'componentShouldBe':"addFeatures: 要素は ${geomType} であるべきです",'getFeatureError':"getFeatureFromEvent がレンダラーのないレイヤーから呼ばれました。通常、これはあなたがレイヤーを、それに関連づけられたいくつかのハンドラを除いて、破壊してしまったことを意味します。",'minZoomLevelError':"minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。",'commitSuccess':"WFS トランザクション: 成功 ${response}",'commitFailed':"WFS トランザクション: 失敗 ${response}",'googleWarning':"Google レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'getLayerWarning':"${layerType} レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'scale':"縮尺 = 1 : ${scaleDenom}",'W':"西",'E':"東",'N':"北",'S':"南",'layerAlreadyAdded':"あなたは「${layerName}」を地図に追加しようと試みましたが、そのレイヤーは既に追加されています",'reprojectDeprecated':"あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。",'methodDeprecated':"このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。",'boundsAddError':"x と y 両方の値を add 関数に渡さなければなりません。",'lonlatAddError':"lon と lat 両方の値を add 関数に渡さなければなりません。",'pixelAddError':"x と y の値両方を add 関数に渡さなければなりません。",'unsupportedGeometryType':"未対応の形状型: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition が失敗しました: id ${elemId} をもつ要素が誤った位置にある可能性があります。",'filterEvaluateNotImplemented':"このフィルター型について evaluate は実装されていません。"});OpenLayers.Lang["km"]=OpenLayers.Util.applyDefaults({'permalink':"តំណភ្ជាប់អចិន្ត្រៃយ៍",'baseLayer':"ស្រទាប់បាត​",'errorLoadingGML':"កំហុសកំឡុងពេលផ្ទុកឯកសារ GML ${url}",'scale':"មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}"});OpenLayers.Lang["ksh"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}",'permalink':"Lengk op Duuer",'overlays':"Drövver jelaat",'baseLayer':"Jrund-Nivoh",'sameProjection':"De Övverseeschs_Kaat deiht et bloß, wann se de sälve Projäxjuhn bruche deiht, wi de Houp_Kaat",'readNotImplemented':"„\x3ccode lang=\"en\"\x3eread\x3c/code\x3e“ is em Projramm nit fürjesinn.",'writeNotImplemented':"„\x3ccode lang=\"en\"\x3ewrite\x3c/code\x3e“ is em Projramm nit fürjesinn.",'noFID':"En Saach, woh kein \x3ci lang=\"en\"\x3eFID\x3c/i\x3e för doh es, löht sesch nit ändere.",'errorLoadingGML':"Fähler beim \x3ci lang=\"en\"\x3eGML\x3c/i\x3e-Datei-Laade vun \x3ccode\x3e${url}\x3c/code\x3e",'browserNotSupported':"Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}",'componentShouldBe':"\x3ccode lang=\"en\"\x3eaddFeatures\x3c/code\x3e: dä Aandeil sullt vun dä Zoot „\x3ccode lang=\"en\"\x3e${geomType}\x3c/code\x3e“ sin.",'getFeatureError':"\x3ccode lang=\"en\"\x3egetFeatureFromEvent\x3c/code\x3e es vun enem Nivoh opjeroofe woode, woh et kei Projramm zom Ußjävve jit. Dat bedügg för jewöhnlesch, dat De e Nivoh kapott jemaat häs, ävver nit e Projramm för domet ömzejonn, wat domet verbonge es.",'minZoomLevelError':"De Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun \x3ccode lang=\"en\"\x3eFixedZoomLevels\x3c/code\x3e affhange don. Dat dat \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Nivvoh övverhoup de Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.",'commitSuccess':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es joot jeloufe: ${response}",'commitFailed':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es scheif jejange: ${response}",'googleWarning':"Dat Nivvoh \x3ccode lang=\"en\"\x3eGoogle\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat wiel dat \x3ci lang=\"en\"\x3eGoogle-Maps\x3c/i\x3e-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje \x3ci lang=\"en\"\x3eAPI\x3c/i\x3e-Schlößel för Ding Web-ßait scheke deiht.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/Google\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'getLayerWarning':"Dat Nivvoh \x3ccode\x3e${layerType}\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat, wiel dat Skrepp \x3ccode\x3e${layerLib}\x3c/code\x3e nit reschtesch enjebonge wood.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_Et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/${layerLib}\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'scale':"Mohßshtaab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'layerAlreadyAdded':"Do häß versöhk, dat Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e en di Kaat eren ze bränge, et wohr ävver ald do dren.",'reprojectDeprecated':"Do bruchs de Ußwahl \x3ccode\x3ereproject\x3c/code\x3e op däm Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm \x3ccode\x3e${newMethod}\x3c/code\x3e doföör.",'boundsAddError':"Do moß beeds vun de \x3ccode\x3ex\x3c/code\x3e un \x3ccode\x3ey\x3c/code\x3e Wääte aan de Fungkßjohn \x3ccode\x3eadd\x3c/code\x3e jävve.",'lonlatAddError':"Do moß beeds \x3ccode\x3elon\x3c/code\x3e un \x3ccode\x3elat\x3c/code\x3e aan de Fungkßjohn \x3ccode\x3eadd\x3c/code\x3e jävve.",'pixelAddError':"Do moß beeds \x3ccode\x3ex\x3c/code\x3e un \x3ccode\x3ey\x3c/code\x3e aan de Fungkßjohn \x3ccode\x3eadd\x3c/code\x3e jävve.",'unsupportedGeometryType':"De Zoot Jommetrii dom_mer nit ongershtöze: \x3ccode\x3e${geomType}\x3c/code\x3e",'pagePositionFailed':"\x3ccode lang=\"en\"\x3eOpenLayers.Util.pagePosition\x3c/code\x3e es donevve jejange: dat Denge met dä Kännong \x3ccode\x3e${elemId}\x3c/code\x3e künnt am verkeehte Plaz sin.",'filterEvaluateNotImplemented':"„\x3ccode lang=\"en\"\x3eevaluate\x3c/code\x3e“ es för di Zoot Fellter nit enjereschdt."});OpenLayers.Lang["nds"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehannelt Trüchmellels för de Anfraag ${statusText}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Achtergrundkoort",'sameProjection':"De Översichtskoort geiht blot, wenn de sülve Projekschoon as bi de Hööftkoort bruukt warrt",'readNotImplemented':"Lesen is nich inricht.",'writeNotImplemented':"Schrieven is nich inricht.",'noFID':"En Feature, dat keen FID hett, kann nich aktuell maakt warrn.",'errorLoadingGML':"Fehler bi’t Laden vun de GML-Datei ${url}",'browserNotSupported':"Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}",'componentShouldBe':"addFeatures : Kumponent schull man den Typ ${geomType} hebben",'getFeatureError':"getFeatureFromEvent is von en Laag ahn Render opropen worrn. Dat bedüüdt normalerwies, dat en Laag wegmaakt worrn is, aver nich de Handler, de dor op verwiest.",'commitSuccess':"WFS-Transakschoon: hett klappt ${response}",'commitFailed':"WFS-Transakschoon: hett nich klappt ${response}",'scale':"Skaal = 1 : ${scaleDenom}",'layerAlreadyAdded':"Du versöchst de Laag „${layerName}“ to de Koort totofögen, man de is al toföögt",'methodDeprecated':"Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för.",'boundsAddError':"De Weert x un y, de mööt all beid an de add-Funkschoon övergeven warrn.",'lonlatAddError':"De Weert lon un lat, de mööt all beid an de add-Funkschoon övergeven warrn.",'pixelAddError':"De Weert x un y, de mööt all beid an de add-Funkschoon övergeven warrn.",'unsupportedGeometryType':"Nich ünnerstütt Geometrie-Typ: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition güng nich: Element mit de Id ${elemId} is villicht an’n verkehrten Platz."});OpenLayers.Lang["nn"]=OpenLayers.Util.applyDefaults({'scale':"Skala = 1 : ${scaleDenom}",'layerAlreadyAdded':"Du freista å leggja til laget «${layerName}» på kartet, men det har alt vorte lagt til.",'boundsAddError':"Du er nøydd til å gje både ein x- og ein y-verdi til «add»-funksjonen.",'lonlatAddError':"Du er nøydd til å gje både lon- og lat-verdiar til «add»-funksjonen.",'pixelAddError':"Du er nøydd til å gje både ein x- og ein y-verdi til «add»-funksjonen."});OpenLayers.Lang["oc"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requèsta pas gerida, retorna ${statusText}",'permalink':"Permaligam",'overlays':"Calques",'baseLayer':"Calc de basa",'sameProjection':"La carta de situacion fonciona pas que quora sa projeccion es la meteissa que la de la carta principala",'readNotImplemented':"Lectura pas implementada.",'writeNotImplemented':"Escritura pas implementada.",'noFID':"Impossible de metre a jorn un objècte sens identificant (fid).",'errorLoadingGML':"Error al cargament del fichièr GML ${url}",'browserNotSupported':"Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}",'componentShouldBe':"addFeatures : lo compausant deuriá èsser de tipe ${geomType}",'getFeatureError':"getFeatureFromEvent es estat apelat sus un calc sens renderer. Aquò significa generalament qu\'avètz destruch aqueste jaç, mas qu\'avètz conservat un handler que li èra associat.",'minZoomLevelError':"La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu\'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d\'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d\'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaccion WFS : SUCCES ${response}",'commitFailed':"Transaccion WFS : FRACAS ${response}",'googleWarning':"Lo jaç Google es pas estat en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l\'API correspond pas a vòstre site.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquò, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'getLayerWarning':"Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una  BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquí, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'scale':"Escala ~ 1 : ${scaleDenom}",'W':"O",'E':"È",'N':"N",'S':"S",'layerAlreadyAdded':"Avètz ensajat d\'apondre a la carta lo calc : ${layerName}, mas ja es present",'reprojectDeprecated':"Utilizatz l\'opcion \'reproject\' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d\'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d\'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d\'utilizar ${newMethod} a la plaça.",'boundsAddError':"Vos cal passar las doas valors x e y a la foncion add.",'lonlatAddError':"Vos cal passar las doas valors lon e lat a la foncion add.",'pixelAddError':"Vos cal passar las doas valors x e y a la foncion add.",'unsupportedGeometryType':"Tipe de geometria pas suportat : ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition a fracassat : l\'element d\'id ${elemId} poiriá èsser mal posicionat.",'filterEvaluateNotImplemented':"evaluar es pas encara estat implementat per aqueste tipe de filtre."});OpenLayers.Lang["pt"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Servidor devolveu erro não contemplado ${statusText}",'permalink':"Ligação permanente",'overlays':"Sobreposições",'baseLayer':"Camada Base",'sameProjection':"O mapa panorâmico só funciona quando está na mesma projeção que o mapa principal",'readNotImplemented':"Leitura não implementada.",'writeNotImplemented':"Escrita não implementada.",'noFID':"Não é possível atualizar um elemento para a qual não há FID.",'errorLoadingGML':"Erro ao carregar ficheiro GML ${url}",'browserNotSupported':"O seu navegador não suporta renderização vetorial. Actualmente os renderizadores suportados são:\n${renderers}",'componentShouldBe':"addFeatures: componente deve ser um(a) ${geomType}",'getFeatureError':"getFeatureFromEvent foi chamado numa camada sem renderizador. Isto normalmente significa que destruiu uma camada, mas não um manipulador \'\'(handler)\'\' que lhe está associado.",'minZoomLevelError':"A propriedade minZoomLevel só deve ser usada com as camadas descendentes da FixedZoomLevels. A verificação da propriedade por esta camada wfs é uma relíquia do passado. No entanto, não podemos removê-la sem correr o risco de afectar aplicações OL que dependam dela. Portanto, estamos a torná-la obsoleta -- a verificação minZoomLevel será removida na versão 3.0. Em vez dela, por favor, use as opções de resolução min/max descritas aqui: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacção WFS: SUCESSO ${response}",'commitFailed':"Transacção WFS: FALHOU ${response}",'googleWarning':"A Camada Google não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara deixar de receber esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca do Google Maps não foi incluído ou não contém a chave API correcta para o seu sítio.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .",'getLayerWarning':"A camada ${layerType} não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara desactivar esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca ${layerLib} não foi incluído correctamente.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .",'scale':"Escala = 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S",'layerAlreadyAdded':"Você tentou adicionar a camada: ${layerName} ao mapa, mas ela já tinha sido adicionada antes",'reprojectDeprecated':"Está usando a opção \'reproject\' na camada ${layerName}. Esta opção é obsoleta: foi concebida para permitir a apresentação de dados sobre mapas-base comerciais, mas esta funcionalidade é agora suportada pelo Mercator Esférico. Mais informação está disponível em http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método foi declarado obsoleto e será removido na versão 3.0. Por favor, use ${newMethod} em vez disso.",'boundsAddError':"Você deve passar tanto o valor x como o y à função de adição.",'lonlatAddError':"Você deve passar tanto o valor lon como o lat à função de adição.",'pixelAddError':"Você deve passar tanto o valor x como o y à função de adição.",'unsupportedGeometryType':"Tipo de geometria não suportado: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition falhou: o elemento com o id ${elemId} poderá estar mal-posicionado.",'filterEvaluateNotImplemented':"avaliar não está implementado para este tipo de filtro."});OpenLayers.Lang["ru"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Необработанный запрос вернул ${statusText}",'permalink':"Постоянная ссылка",'overlays':"Слои",'baseLayer':"Основной слой",'sameProjection':"Обзорная карта работает только тогда, когда имеет ту же проекцию, что и основная",'readNotImplemented':"Чтение не реализовано.",'writeNotImplemented':"Запись не реализована.",'noFID':"Невозможно обновить объект, для которого нет FID.",'errorLoadingGML':"Ошибка при загрузке файла GML ${url}",'browserNotSupported':"Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}",'componentShouldBe':"addFeatures: компонент должен быть ${geomType}",'getFeatureError':"getFeatureFromEvent вызван для слоя без рендерера. Обычно это говорит о том, что вы уничтожили слой, но оставили связанный с ним обработчик.",'minZoomLevelError':"Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Транзакция WFS: УСПЕШНО ${response}",'commitFailed':"Транзакция WFS: ОШИБКА ${response}",'googleWarning':"Слой Google не удалось нормально загрузить.\x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'getLayerWarning':"Слой ${layerType} не удалось нормально загрузить. \x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'scale':"Масштаб = 1 : ${scaleDenom}",'W':"З",'E':"В",'N':"С",'S':"Ю",'layerAlreadyAdded':"Вы попытались добавить слой «${layerName}» на карту, но он уже был добавлен",'reprojectDeprecated':"Вы используете опцию \'reproject\' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}.",'boundsAddError':"Функции add надо передавать оба значения, x и y.",'lonlatAddError':"Функции add надо передавать оба значения, lon и lat.",'pixelAddError':"Функции add надо передавать оба значения, x и y.",'unsupportedGeometryType':"Неподдерживаемый тип геометрии: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: элемент с id ${elemId} может находиться не в нужном месте.",'filterEvaluateNotImplemented':"evaluate не реализовано для фильтра данного типа."});OpenLayers.Lang["sk"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Neobslúžené požiadavky vracajú ${statusText}",'permalink':"Trvalý odkaz",'overlays':"Prekrytia",'baseLayer':"Základná vrstva",'sameProjection':"Prehľadová mapka funguje iba vtedy, keď je v rovnakej projekcii ako hlavná mapa",'readNotImplemented':"Čítanie nie je implementované.",'writeNotImplemented':"Zápis nie je implementovaný.",'noFID':"Nie je možné aktualizovať vlastnosť, pre ktorú neexistuje FID.",'errorLoadingGML':"Chyba pri načítaní súboru GML ${url}",'browserNotSupported':"Váš prehliadač nepodporuje vykresľovanie vektorov. Momentálne podporované vykresľovače sú:\n${renderers}",'componentShouldBe':"addFeatures: komponent by mal byť ${geomType}",'getFeatureError':"getFeatureFromEvent bola zavolaná na vrstve bez vykresľovača. To zvyčajne znamená, že ste odstránili vrstvu, ale nie niektorú z obslúh, ktorá je s ňou asociovaná.",'minZoomLevelError':"Vlastnosť minZoomLevel je určený iba na použitie s vrstvami odvodenými od FixedZoomLevels. To, že táto wfs vrstva kontroluje minZoomLevel je pozostatok z minulosti. Nemôžeme ho však odstrániť, aby sme sa vyhli možnému porušeniu aplikácií založených na Open Layers, ktoré na tomto môže závisieť. Preto ho označujeme ako zavrhovaný - dolu uvedená kontrola minZoomLevel bude odstránená vo verzii 3.0. Použite prosím namiesto toho kontrolu min./max. rozlíšenia podľa tu uvedeného popisu: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transakcia WFS: ÚSPEŠNÁ ${response}",'commitFailed':"Transakcia WFS: ZLYHALA ${response}",'googleWarning':"Vrstvu Google nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice Google Maps buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e",'getLayerWarning':"Vrstvu ${layerType} nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice ${layerType} buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/${layerType}\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e",'scale':"Mierka = 1 : ${scaleDenom}",'layerAlreadyAdded':"Pokúsili ste sa do mapy pridať vrstvu ${layerName}, ale tá už bola pridaná",'reprojectDeprecated':"Používate voľby „reproject“ vrstvy ${layerType}. Táto voľba je zzavrhovaná: jej použitie bolo navrhnuté na podporu zobrazovania údajov nad komerčnými základovými mapami, ale túto funkcionalitu je teraz možné dosiahnuť pomocou Spherical Mercator. Ďalšie informácie získate na stránke http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Táto metóda je zavrhovaná a bude odstránená vo verzii 3.0. Použite prosím namiesto nej metódu ${newMethod}.",'boundsAddError':"Sčítacej funkcii musíte dať hodnoty x aj y.",'lonlatAddError':"Sčítacej funkcii musíte dať hodnoty lon (zem. dĺžka) aj lat (zem. šírka).",'pixelAddError':"Sčítacej funkcii musíte dať hodnoty x aj y.",'unsupportedGeometryType':"Nepodporovaný typ geometrie: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition zlyhalo: prvok s id ${elemId} môže byť zle umiestnený.",'filterEvaluateNotImplemented':"evaluate nie je implementovaný pre tento typ filtra"});OpenLayers.Lang["te"]=OpenLayers.Util.applyDefaults({'permalink':"స్థిరలింకు",'W':"ప",'E':"తూ",'N':"ఉ",'S':"ద"});OpenLayers.Lang["vi"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Không xử lý được phản hồi ${statusText} cho yêu cầu",'permalink':"Liên kết thường trực",'overlays':"Lấp bản đồ",'baseLayer':"Lớp nền",'sameProjection':"Bản đồ toàn cảnh chỉ hoạt động khi cùng phép chiếu với bản đồ chính",'readNotImplemented':"Chưa hỗ trợ chức năng đọc.",'writeNotImplemented':"Chưa hỗ trợ chức năng viết.",'noFID':"Không thể cập nhật tính năng thiếu FID.",'errorLoadingGML':"Lỗi tải tập tin GML tại ${url}",'browserNotSupported':"Trình duyệt của bạn không hỗ trợ chức năng vẽ bằng vectơ. Hiện hỗ trợ các bộ kết xuất:\n${renderers}",'componentShouldBe':"addFeatures: bộ phận cần phải là ${geomType}",'getFeatureError':"getFeatureFromEvent được gọi từ lớp không có bộ kết xuất. Thường thì có lẽ lớp bị xóa nhưng một phần xử lý của nó vẫn còn.",'minZoomLevelError':"Chỉ nên sử dụng thuộc tính minZoomLevel với các lớp FixedZoomLevels-descendent. Việc lớp wfs này tìm cho minZoomLevel là di tích còn lại từ xưa. Tuy nhiên, nếu chúng tôi dời nó thì sẽ vỡ các chương trình OpenLayers mà dựa trên nó. Bởi vậy chúng tôi phản đối sử dụng nó\x26nbsp;– bước tìm cho minZoomLevel sẽ được dời vào phiên bản 3.0. Xin sử dụng thiết lập độ phân tích tối thiểu / tối đa thay thế, theo hướng dẫn này: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Giao dịch WFS: THÀNH CÔNG ${response}",'commitFailed':"Giao dịch WFS: THẤT BẠI ${response}",'googleWarning':"Không thể tải lớp Google đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện Google Maps hoặc không được bao gồm hoặc không chứa khóa API hợp với website của bạn.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.",'getLayerWarning':"Không thể tải lớp ${layerType} đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện ${layerLib} không được bao gồm đúng kiểu.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.",'scale':"Tỷ lệ = 1 : ${scaleDenom}",'W':"T",'E':"Đ",'N':"B",'S':"N",'layerAlreadyAdded':"Bạn muốn thêm lớp ${layerName} vào bản đồ, nhưng lớp này đã được thêm",'reprojectDeprecated':"Bạn đang áp dụng chế độ “reproject” vào lớp ${layerName}. Chế độ này đã bị phản đối: nó có mục đích hỗ trợ lấp dữ liệu trên các nền bản đồ thương mại; nên thực hiện hiệu ứng đó dùng tính năng Mercator Hình cầu. Có sẵn thêm chi tiết tại http://trac.openlayers.org/wiki/SphericalMercator .",'methodDeprecated':"Phương thức này đã bị phản đối và sẽ bị dời vào phiên bản 3.0. Xin hãy sử dụng ${newMethod} thay thế.",'boundsAddError':"Cần phải cho cả giá trị x và y vào hàm add.",'lonlatAddError':"Cần phải cho cả giá trị lon và lat vào hàm add.",'pixelAddError':"Cần phải cho cả giá trị x và y vào hàm add.",'unsupportedGeometryType':"Không hỗ trợ kiểu địa lý: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition bị thất bại: nguyên tố với ID ${elemId} có thể ở chỗ sai.",'filterEvaluateNotImplemented':"chưa hỗ trợ evaluate cho loại bộ lọc này."});OpenLayers.Popup.AnchoredBubble=OpenLayers.Class(OpenLayers.Popup.Anchored,{rounded:false,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){this.padding=new OpenLayers.Bounds(0,OpenLayers.Popup.AnchoredBubble.CORNER_SIZE,0,OpenLayers.Popup.AnchoredBubble.CORNER_SIZE);OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);},draw:function(px){OpenLayers.Popup.Anchored.prototype.draw.apply(this,arguments);this.setContentHTML();this.setBackgroundColor();this.setOpacity();return this.div;},updateRelativePosition:function(){this.setRicoCorners();},setSize:function(contentSize){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.setRicoCorners();},setBackgroundColor:function(color){if(color!=undefined){this.backgroundColor=color;}
if(this.div!=null){if(this.contentDiv!=null){this.div.style.background="transparent";OpenLayers.Rico.Corner.changeColor(this.groupDiv,this.backgroundColor);}}},setOpacity:function(opacity){OpenLayers.Popup.Anchored.prototype.setOpacity.call(this,opacity);if(this.div!=null){if(this.groupDiv!=null){OpenLayers.Rico.Corner.changeOpacity(this.groupDiv,this.opacity);}}},setBorder:function(border){this.border=0;},setRicoCorners:function(){var corners=this.getCornersToRound(this.relativePosition);var options={corners:corners,color:this.backgroundColor,bgColor:"transparent",blend:false};if(!this.rounded){OpenLayers.Rico.Corner.round(this.div,options);this.rounded=true;}else{OpenLayers.Rico.Corner.reRound(this.groupDiv,options);this.setBackgroundColor();this.setOpacity();}},getCornersToRound:function(){var corners=['tl','tr','bl','br'];var corner=OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);OpenLayers.Util.removeItem(corners,corner);return corners.join(" ");},CLASS_NAME:"OpenLayers.Popup.AnchoredBubble"});OpenLayers.Popup.AnchoredBubble.CORNER_SIZE=5;OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:false,positionBlocks:null,blocks:null,fixedRelativePosition:false,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);if(this.fixedRelativePosition){this.updateRelativePosition();this.calculateRelativePosition=function(px){return this.relativePosition;};}
this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;if(closeBox){this.closeDiv.style.zIndex=1;}
this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%";},destroy:function(){this.imageSrc=null;this.imageSize=null;this.isAlphaImage=null;this.fixedRelativePosition=false;this.positionBlocks=null;for(var i=0;i<this.blocks.length;i++){var block=this.blocks[i];if(block.image){block.div.removeChild(block.image);}
block.image=null;if(block.div){this.groupDiv.removeChild(block.div);}
block.div=null;}
this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,arguments);},setBackgroundColor:function(color){},setBorder:function(){},setOpacity:function(opacity){},setSize:function(contentSize){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks();},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+
this.padding.right+"px";this.closeDiv.style.top=contentDivPadding.top+
this.padding.top+"px";}
this.updateBlocks();},calculateNewPx:function(px){var newPx=OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);newPx=newPx.offset(this.positionBlocks[this.relativePosition].offset);return newPx;},createBlocks:function(){this.blocks=[];var firstPosition=null;for(var key in this.positionBlocks){firstPosition=key;break;}
var position=this.positionBlocks[firstPosition];for(var i=0;i<position.blocks.length;i++){var block={};this.blocks.push(block);var divId=this.id+'_FrameDecorationDiv_'+i;block.div=OpenLayers.Util.createDiv(divId,null,null,null,"absolute",null,"hidden",null);var imgId=this.id+'_FrameDecorationImg_'+i;var imageCreator=(this.isAlphaImage)?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage;block.image=imageCreator(imgId,null,this.imageSize,this.imageSrc,"absolute",null,null,null);block.div.appendChild(block.image);this.groupDiv.appendChild(block.div);}},updateBlocks:function(){if(!this.blocks){this.createBlocks();}
if(this.size&&this.relativePosition){var position=this.positionBlocks[this.relativePosition];for(var i=0;i<position.blocks.length;i++){var positionBlock=position.blocks[i];var block=this.blocks[i];var l=positionBlock.anchor.left;var b=positionBlock.anchor.bottom;var r=positionBlock.anchor.right;var t=positionBlock.anchor.top;var w=(isNaN(positionBlock.size.w))?this.size.w-(r+l):positionBlock.size.w;var h=(isNaN(positionBlock.size.h))?this.size.h-(b+t):positionBlock.size.h;block.div.style.width=(w<0?0:w)+'px';block.div.style.height=(h<0?0:h)+'px';block.div.style.left=(l!=null)?l+'px':'';block.div.style.bottom=(b!=null)?b+'px':'';block.div.style.right=(r!=null)?r+'px':'';block.div.style.top=(t!=null)?t+'px':'';block.image.style.left=positionBlock.position.x+'px';block.image.style.top=positionBlock.position.y+'px';}
this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px";}},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},toString:function(){return this.getCode();},equals:function(projection){if(projection&&projection.getCode){return this.getCode()==projection.getCode();}else{return false;}},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.addTransform=function(from,to,method){if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};}
OpenLayers.Projection.transforms[from][to]=method;};OpenLayers.Projection.transform=function(point,source,dest){if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}else if(source&&dest&&OpenLayers.Projection.transforms[source.getCode()]&&OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]){OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);}
return point;};OpenLayers.Protocol.WFS.v1=OpenLayers.Class(OpenLayers.Protocol,{version:null,srsName:"EPSG:4326",featureType:null,featureNS:null,geometryName:"the_geom",schema:null,featurePrefix:"feature",formatOptions:null,readFormat:null,initialize:function(options){OpenLayers.Protocol.prototype.initialize.apply(this,[options]);if(!options.format){this.format=OpenLayers.Format.WFST(OpenLayers.Util.extend({version:this.version,featureType:this.featureType,featureNS:this.featureNS,featurePrefix:this.featurePrefix,geometryName:this.geometryName,srsName:this.srsName,schema:this.schema},this.formatOptions));}
if(!this.featureNS&&this.featurePrefix){var readNode=this.format.readNode;this.format.readNode=function(node,obj){if(!this.featureNS&&node.prefix==this.featurePrefix){this.featureNS=node.namespaceURI;this.setNamespace("feature",this.featureNS);}
return readNode.apply(this,arguments);};}},destroy:function(){if(this.options&&!this.options.format){this.format.destroy();}
this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this);},read:function(options){OpenLayers.Protocol.prototype.read.apply(this,arguments);options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options||{});var response=new OpenLayers.Protocol.Response({requestType:"read"});var data=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",options)]);response.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleRead,response,options),params:options.params,headers:options.headers,data:data});return response;},handleRead:function(response,options){if(options.callback){var request=response.priv;if(request.status>=200&&request.status<300){response.features=this.parseFeatures(request);response.code=OpenLayers.Protocol.Response.SUCCESS;}else{response.code=OpenLayers.Protocol.Response.FAILURE;}
options.callback.call(options.scope,response);}},parseFeatures:function(request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
if(!doc||doc.length<=0){return null;}
return(this.readFormat!==null)?this.readFormat.read(doc):this.format.read(doc);},commit:function(features,options){options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options);var response=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:features});response.priv=OpenLayers.Request.POST({url:options.url,data:this.format.write(features,options),callback:this.createCallback(this.handleCommit,response,options)});return response;},handleCommit:function(response,options){if(options.callback){var request=response.priv;var data=request.responseXML;if(!data||!data.documentElement){data=request.responseText;}
var obj=this.format.read(data)||{};response.insertIds=obj.insertIds||[];response.code=(obj.success)?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE;options.callback.call(options.scope,response);}},filterDelete:function(filter,options){options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options);var response=new OpenLayers.Protocol.Response({requestType:"commit"});var root=this.format.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version}});var deleteNode=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(options.featureNS?this.featurePrefix+":":"")+
options.featureType}});if(options.featureNS){deleteNode.setAttribute("xmlns:"+this.featurePrefix,options.featureNS);}
var filterNode=this.format.writeNode("ogc:Filter",filter);deleteNode.appendChild(filterNode);root.appendChild(deleteNode);var data=OpenLayers.Format.XML.prototype.write.apply(this.format,[root]);return OpenLayers.Request.POST({url:this.url,callback:options.callback||function(){},data:data});},abort:function(response){if(response){response.priv.abort();}},CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15000,translationParameters:null,symbolMetrics:null,isGecko:null,supportUse:null,initialize:function(containerID){if(!this.supported()){return;}
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);this.translationParameters={x:0,y:0};this.supportUse=(navigator.userAgent.toLowerCase().indexOf("applewebkit/5")==-1);this.isGecko=(navigator.userAgent.toLowerCase().indexOf("gecko/")!=-1);this.symbolMetrics={};},destroy:function(){OpenLayers.Renderer.Elements.prototype.destroy.apply(this,arguments);},supported:function(){var svgFeature="http://www.w3.org/TR/SVG11/feature#";return(document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature(svgFeature+"SVG","1.1")||document.implementation.hasFeature(svgFeature+"BasicStructure","1.1")));},inValidRange:function(x,y,xyOnly){var left=x+(xyOnly?0:this.translationParameters.x);var top=y+(xyOnly?0:this.translationParameters.y);return(left>=-this.MAX_PIXEL&&left<=this.MAX_PIXEL&&top>=-this.MAX_PIXEL&&top<=this.MAX_PIXEL);},setExtent:function(extent,resolutionChanged){OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();var left=-extent.left/resolution;var top=extent.top/resolution;if(resolutionChanged){this.left=left;this.top=top;var extentString="0 0 "+this.size.w+" "+this.size.h;this.rendererRoot.setAttributeNS(null,"viewBox",extentString);this.translate(0,0);return true;}else{var inRange=this.translate(left-this.left,top-this.top);if(!inRange){this.setExtent(extent,true);}
return inRange;}},translate:function(x,y){if(!this.inValidRange(x,y,true)){return false;}else{var transformString="";if(x||y){transformString="translate("+x+","+y+")";}
this.root.setAttributeNS(null,"transform",transformString);this.translationParameters={x:x,y:y};return true;}},setSize:function(size){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w);this.rendererRoot.setAttributeNS(null,"height",this.size.h);},getNodeType:function(geometry,style){var nodeType=null;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.externalGraphic){nodeType="image";}else if(this.isComplexSymbol(style.graphicName)){nodeType=this.supportUse===false?"svg":"use";}else{nodeType="circle";}
break;case"OpenLayers.Geometry.Rectangle":nodeType="rect";break;case"OpenLayers.Geometry.LineString":nodeType="polyline";break;case"OpenLayers.Geometry.LinearRing":nodeType="polygon";break;case"OpenLayers.Geometry.Polygon":case"OpenLayers.Geometry.Curve":case"OpenLayers.Geometry.Surface":nodeType="path";break;default:break;}
return nodeType;},setStyle:function(node,style,options){style=style||node._style;options=options||node._options;var r=parseFloat(node.getAttributeNS(null,"r"));var widthFactor=1;var pos;if(node._geometryClass=="OpenLayers.Geometry.Point"&&r){node.style.visibility="";if(style.graphic===false){node.style.visibility="hidden";}else if(style.externalGraphic){pos=this.getPosition(node);if(style.graphicTitle){node.setAttributeNS(null,"title",style.graphicTitle);}
if(style.graphicWidth&&style.graphicHeight){node.setAttributeNS(null,"preserveAspectRatio","none");}
var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);var opacity=style.graphicOpacity||style.fillOpacity;node.setAttributeNS(null,"x",(pos.x+xOffset).toFixed());node.setAttributeNS(null,"y",(pos.y+yOffset).toFixed());node.setAttributeNS(null,"width",width);node.setAttributeNS(null,"height",height);node.setAttributeNS(this.xlinkns,"href",style.externalGraphic);node.setAttributeNS(null,"style","opacity: "+opacity);}else if(this.isComplexSymbol(style.graphicName)){var offset=style.pointRadius*3;var size=offset*2;var id=this.importSymbol(style.graphicName);pos=this.getPosition(node);widthFactor=this.symbolMetrics[id][0]*3/size;var parent=node.parentNode;var nextSibling=node.nextSibling;if(parent){parent.removeChild(node);}
if(this.supportUse===false){var src=document.getElementById(id);node.firstChild&&node.removeChild(node.firstChild);node.appendChild(src.firstChild.cloneNode(true));node.setAttributeNS(null,"viewBox",src.getAttributeNS(null,"viewBox"));}else{node.setAttributeNS(this.xlinkns,"href","#"+id);}
node.setAttributeNS(null,"width",size);node.setAttributeNS(null,"height",size);node.setAttributeNS(null,"x",pos.x-offset);node.setAttributeNS(null,"y",pos.y-offset);if(nextSibling){parent.insertBefore(node,nextSibling);}else if(parent){parent.appendChild(node);}}else{node.setAttributeNS(null,"r",style.pointRadius);}
var rotation=style.rotation;if((rotation!==undefined||node._rotation!==undefined)&&pos){node._rotation=rotation;rotation|=0;if(node.nodeName!=="svg"){node.setAttributeNS(null,"transform","rotate("+rotation+" "+pos.x+" "+
pos.y+")");}else{var metrics=this.symbolMetrics[id];node.firstChild.setAttributeNS(null,"transform","rotate("+style.rotation+" "+metrics[1]+" "+metrics[2]+")");}}}
if(options.isFilled){node.setAttributeNS(null,"fill",style.fillColor);node.setAttributeNS(null,"fill-opacity",style.fillOpacity);}else{node.setAttributeNS(null,"fill","none");}
if(options.isStroked){node.setAttributeNS(null,"stroke",style.strokeColor);node.setAttributeNS(null,"stroke-opacity",style.strokeOpacity);node.setAttributeNS(null,"stroke-width",style.strokeWidth*widthFactor);node.setAttributeNS(null,"stroke-linecap",style.strokeLinecap||"round");node.setAttributeNS(null,"stroke-linejoin","round");style.strokeDashstyle&&node.setAttributeNS(null,"stroke-dasharray",this.dashStyle(style,widthFactor));}else{node.setAttributeNS(null,"stroke","none");}
if(style.pointerEvents){node.setAttributeNS(null,"pointer-events",style.pointerEvents);}
if(style.cursor!=null){node.setAttributeNS(null,"cursor",style.cursor);}
return node;},dashStyle:function(style,widthFactor){var w=style.strokeWidth*widthFactor;var str=style.strokeDashstyle;switch(str){case'solid':return'none';case'dot':return[1,4*w].join();case'dash':return[4*w,4*w].join();case'dashdot':return[4*w,4*w,1,4*w].join();case'longdash':return[8*w,4*w].join();case'longdashdot':return[8*w,4*w,1,4*w].join();default:return OpenLayers.String.trim(str).replace(/\s+/g,",");}},createNode:function(type,id){var node=document.createElementNS(this.xmlns,type);if(id){node.setAttributeNS(null,"id",id);}
return node;},nodeTypeCompare:function(node,type){return(type==node.nodeName);},createRenderRoot:function(){return this.nodeFactory(this.container.id+"_svgRoot","svg");},createRoot:function(suffix){return this.nodeFactory(this.container.id+suffix,"g");},createDefs:function(){var defs=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(defs);return defs;},drawPoint:function(node,geometry){return this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){var resolution=this.getResolution();var x=(geometry.x/resolution+this.left);var y=(this.top-geometry.y/resolution);if(this.inValidRange(x,y)){node.setAttributeNS(null,"cx",x);node.setAttributeNS(null,"cy",y);node.setAttributeNS(null,"r",radius);return node;}else{return false;}},drawLineString:function(node,geometry){var componentsResult=this.getComponentsString(geometry.components);if(componentsResult.path){node.setAttributeNS(null,"points",componentsResult.path);return(componentsResult.complete?node:null);}else{return false;}},drawLinearRing:function(node,geometry){var componentsResult=this.getComponentsString(geometry.components);if(componentsResult.path){node.setAttributeNS(null,"points",componentsResult.path);return(componentsResult.complete?node:null);}else{return false;}},drawPolygon:function(node,geometry){var d="";var draw=true;var complete=true;var linearRingResult,path;for(var j=0,len=geometry.components.length;j<len;j++){d+=" M";linearRingResult=this.getComponentsString(geometry.components[j].components," ");path=linearRingResult.path;if(path){d+=" "+path;complete=linearRingResult.complete&&complete;}else{draw=false;}}
d+=" z";if(draw){node.setAttributeNS(null,"d",d);node.setAttributeNS(null,"fill-rule","evenodd");return complete?node:null;}else{return false;}},drawRectangle:function(node,geometry){var resolution=this.getResolution();var x=(geometry.x/resolution+this.left);var y=(this.top-geometry.y/resolution);if(this.inValidRange(x,y)){node.setAttributeNS(null,"x",x);node.setAttributeNS(null,"y",y);node.setAttributeNS(null,"width",geometry.width/resolution);node.setAttributeNS(null,"height",geometry.height/resolution);return node;}else{return false;}},drawSurface:function(node,geometry){var d=null;var draw=true;for(var i=0,len=geometry.components.length;i<len;i++){if((i%3)==0&&(i/3)==0){var component=this.getShortString(geometry.components[i]);if(!component){draw=false;}
d="M "+component;}else if((i%3)==1){var component=this.getShortString(geometry.components[i]);if(!component){draw=false;}
d+=" C "+component;}else{var component=this.getShortString(geometry.components[i]);if(!component){draw=false;}
d+=" "+component;}}
d+=" Z";if(draw){node.setAttributeNS(null,"d",d);return node;}else{return false;}},drawText:function(featureId,style,location){var resolution=this.getResolution();var x=(location.x/resolution+this.left);var y=(location.y/resolution-this.top);var label=this.nodeFactory(featureId+this.LABEL_ID_SUFFIX,"text");var tspan=this.nodeFactory(featureId+this.LABEL_ID_SUFFIX+"_tspan","tspan");label.setAttributeNS(null,"x",x);label.setAttributeNS(null,"y",-y);if(style.fontColor){label.setAttributeNS(null,"fill",style.fontColor);}
if(style.fontOpacity){label.setAttributeNS(null,"opacity",style.fontOpacity);}
if(style.fontFamily){label.setAttributeNS(null,"font-family",style.fontFamily);}
if(style.fontSize){label.setAttributeNS(null,"font-size",style.fontSize);}
if(style.fontWeight){label.setAttributeNS(null,"font-weight",style.fontWeight);}
if(style.labelSelect===true){label.setAttributeNS(null,"pointer-events","visible");label._featureId=featureId;tspan._featureId=featureId;tspan._geometry=location;tspan._geometryClass=location.CLASS_NAME;}else{label.setAttributeNS(null,"pointer-events","none");}
var align=style.labelAlign||"cm";label.setAttributeNS(null,"text-anchor",OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]]||"middle");if(this.isGecko){label.setAttributeNS(null,"dominant-baseline",OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]]||"central");}else{tspan.setAttributeNS(null,"baseline-shift",OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]]||"-35%");}
tspan.textContent=style.label;if(!label.parentNode){label.appendChild(tspan);this.textRoot.appendChild(label);}},getComponentsString:function(components,separator){var renderCmp=[];var complete=true;var len=components.length;var strings=[];var str,component;for(var i=0;i<len;i++){component=components[i];renderCmp.push(component);str=this.getShortString(component);if(str){strings.push(str);}else{if(i>0){if(this.getShortString(components[i-1])){strings.push(this.clipLine(components[i],components[i-1]));}}
if(i<len-1){if(this.getShortString(components[i+1])){strings.push(this.clipLine(components[i],components[i+1]));}}
complete=false;}}
return{path:strings.join(separator||","),complete:complete};},clipLine:function(badComponent,goodComponent){if(goodComponent.equals(badComponent)){return"";}
var resolution=this.getResolution();var maxX=this.MAX_PIXEL-this.translationParameters.x;var maxY=this.MAX_PIXEL-this.translationParameters.y;var x1=goodComponent.x/resolution+this.left;var y1=this.top-goodComponent.y/resolution;var x2=badComponent.x/resolution+this.left;var y2=this.top-badComponent.y/resolution;var k;if(x2<-maxX||x2>maxX){k=(y2-y1)/(x2-x1);x2=x2<0?-maxX:maxX;y2=y1+(x2-x1)*k;}
if(y2<-maxY||y2>maxY){k=(x2-x1)/(y2-y1);y2=y2<0?-maxY:maxY;x2=x1+(y2-y1)*k;}
return x2+","+y2;},getShortString:function(point){var resolution=this.getResolution();var x=(point.x/resolution+this.left);var y=(this.top-point.y/resolution);if(this.inValidRange(x,y)){return x+","+y;}else{return false;}},getPosition:function(node){return({x:parseFloat(node.getAttributeNS(null,"cx")),y:parseFloat(node.getAttributeNS(null,"cy"))});},importSymbol:function(graphicName){if(!this.defs){this.defs=this.createDefs();}
var id=this.container.id+"-"+graphicName;if(document.getElementById(id)!=null){return id;}
var symbol=OpenLayers.Renderer.symbol[graphicName];if(!symbol){throw new Error(graphicName+' is not a valid symbol name');}
var symbolNode=this.nodeFactory(id,"symbol");var node=this.nodeFactory(null,"polygon");symbolNode.appendChild(node);var symbolExtent=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);var points=[];var x,y;for(var i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];symbolExtent.left=Math.min(symbolExtent.left,x);symbolExtent.bottom=Math.min(symbolExtent.bottom,y);symbolExtent.right=Math.max(symbolExtent.right,x);symbolExtent.top=Math.max(symbolExtent.top,y);points.push(x,",",y);}
node.setAttributeNS(null,"points",points.join(" "));var width=symbolExtent.getWidth();var height=symbolExtent.getHeight();var viewBox=[symbolExtent.left-width,symbolExtent.bottom-height,width*3,height*3];symbolNode.setAttributeNS(null,"viewBox",viewBox.join(" "));this.symbolMetrics[id]=[Math.max(width,height),symbolExtent.getCenterLonLat().lon,symbolExtent.getCenterLonLat().lat];this.defs.appendChild(symbolNode);return symbolNode.id;},getFeatureIdFromEvent:function(evt){var featureId=OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this,arguments);if(this.supportUse===false&&!featureId){var target=evt.target;featureId=target.parentNode&&target!=this.rendererRoot&&target.parentNode._featureId;}
return featureId;},CLASS_NAME:"OpenLayers.Renderer.SVG"});OpenLayers.Renderer.SVG.LABEL_ALIGN={"l":"start","r":"end","b":"bottom","t":"hanging"};OpenLayers.Renderer.SVG.LABEL_VSHIFT={"t":"-70%","b":"0"};OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(containerID){if(!this.supported()){return;}
if(!document.namespaces.olv){document.namespaces.add("olv",this.xmlns);var style=document.createStyleSheet();var shapes=['shape','rect','oval','fill','stroke','imagedata','group','textbox'];for(var i=0,len=shapes.length;i<len;i++){style.addRule('olv\\:'+shapes[i],"behavior: url(#default#VML); "+"position: absolute; display: inline-block;");}}
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Renderer.Elements.prototype.destroy.apply(this,arguments);},supported:function(){return!!(document.namespaces);},setExtent:function(extent,resolutionChanged){OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();var left=(extent.left/resolution)|0;var top=(extent.top/resolution-this.size.h)|0;if(resolutionChanged||!this.offset){this.offset={x:left,y:top};left=0;top=0;}else{left=left-this.offset.x;top=top-this.offset.y;}
var org=left+" "+top;this.root.coordorigin=org;var roots=[this.root,this.vectorRoot,this.textRoot];var root;for(var i=0,len=roots.length;i<len;++i){root=roots[i];var size=this.size.w+" "+this.size.h;root.coordsize=size;}
this.root.style.flip="y";return true;},setSize:function(size){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);var roots=[this.rendererRoot,this.root,this.vectorRoot,this.textRoot];var w=this.size.w+"px";var h=this.size.h+"px";var root;for(var i=0,len=roots.length;i<len;++i){root=roots[i];root.style.width=w;root.style.height=h;}},getNodeType:function(geometry,style){var nodeType=null;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.externalGraphic){nodeType="olv:rect";}else if(this.isComplexSymbol(style.graphicName)){nodeType="olv:shape";}else{nodeType="olv:oval";}
break;case"OpenLayers.Geometry.Rectangle":nodeType="olv:rect";break;case"OpenLayers.Geometry.LineString":case"OpenLayers.Geometry.LinearRing":case"OpenLayers.Geometry.Polygon":case"OpenLayers.Geometry.Curve":case"OpenLayers.Geometry.Surface":nodeType="olv:shape";break;default:break;}
return nodeType;},setStyle:function(node,style,options,geometry){style=style||node._style;options=options||node._options;var fillColor=style.fillColor;if(node._geometryClass==="OpenLayers.Geometry.Point"){if(style.externalGraphic){if(style.graphicTitle){node.title=style.graphicTitle;}
var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var resolution=this.getResolution();var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);node.style.left=(((geometry.x/resolution-this.offset.x)+xOffset)|0)+"px";node.style.top=(((geometry.y/resolution-this.offset.y)-(yOffset+height))|0)+"px";node.style.width=width+"px";node.style.height=height+"px";node.style.flip="y";fillColor="none";options.isStroked=false;}else if(this.isComplexSymbol(style.graphicName)){var cache=this.importSymbol(style.graphicName);node.path=cache.path;node.coordorigin=cache.left+","+cache.bottom;var size=cache.size;node.coordsize=size+","+size;this.drawCircle(node,geometry,style.pointRadius);node.style.flip="y";}else{this.drawCircle(node,geometry,style.pointRadius);}}
if(options.isFilled){node.fillcolor=fillColor;}else{node.filled="false";}
var fills=node.getElementsByTagName("fill");var fill=(fills.length==0)?null:fills[0];if(!options.isFilled){if(fill){node.removeChild(fill);}}else{if(!fill){fill=this.createNode('olv:fill',node.id+"_fill");}
fill.opacity=style.fillOpacity;if(node._geometryClass==="OpenLayers.Geometry.Point"&&style.externalGraphic){if(style.graphicOpacity){fill.opacity=style.graphicOpacity;}
fill.src=style.externalGraphic;fill.type="frame";if(!(style.graphicWidth&&style.graphicHeight)){fill.aspect="atmost";}}
if(fill.parentNode!=node){node.appendChild(fill);}}
var rotation=style.rotation;if((rotation!==undefined||node._rotation!==undefined)){node._rotation=rotation;if(style.externalGraphic){this.graphicRotate(node,xOffset,yOffset,style);fill.opacity=0;}else if(node._geometryClass==="OpenLayers.Geometry.Point"){node.style.rotation=rotation||0;}}
var strokes=node.getElementsByTagName("stroke");var stroke=(strokes.length==0)?null:strokes[0];if(!options.isStroked){node.stroked=false;if(stroke){stroke.on=false;}}else{if(!stroke){stroke=this.createNode('olv:stroke',node.id+"_stroke");node.appendChild(stroke);}
stroke.on=true;stroke.color=style.strokeColor;stroke.weight=style.strokeWidth+"px";stroke.opacity=style.strokeOpacity;stroke.endcap=style.strokeLinecap=='butt'?'flat':(style.strokeLinecap||'round');if(style.strokeDashstyle){stroke.dashstyle=this.dashStyle(style);}}
if(style.cursor!="inherit"&&style.cursor!=null){node.style.cursor=style.cursor;}
return node;},graphicRotate:function(node,xOffset,yOffset,style){var style=style||node._style;var rotation=style.rotation||0;var aspectRatio,size;if(!(style.graphicWidth&&style.graphicHeight)){var img=new Image();img.onreadystatechange=OpenLayers.Function.bind(function(){if(img.readyState=="complete"||img.readyState=="interactive"){aspectRatio=img.width/img.height;size=Math.max(style.pointRadius*2,style.graphicWidth||0,style.graphicHeight||0);xOffset=xOffset*aspectRatio;style.graphicWidth=size*aspectRatio;style.graphicHeight=size;this.graphicRotate(node,xOffset,yOffset,style);}},this);img.src=style.externalGraphic;return;}else{size=Math.max(style.graphicWidth,style.graphicHeight);aspectRatio=style.graphicWidth/style.graphicHeight;}
var width=Math.round(style.graphicWidth||size*aspectRatio);var height=Math.round(style.graphicHeight||size);node.style.width=width+"px";node.style.height=height+"px";var image=document.getElementById(node.id+"_image");if(!image){image=this.createNode("olv:imagedata",node.id+"_image");node.appendChild(image);}
image.style.width=width+"px";image.style.height=height+"px";image.src=style.externalGraphic;image.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader("+"src='', sizingMethod='scale')";var rot=rotation*Math.PI/180;var sintheta=Math.sin(rot);var costheta=Math.cos(rot);var filter="progid:DXImageTransform.Microsoft.Matrix(M11="+costheta+",M12="+(-sintheta)+",M21="+sintheta+",M22="+costheta+",SizingMethod='auto expand')\n";var opacity=style.graphicOpacity||style.fillOpacity;if(opacity&&opacity!=1){filter+="progid:DXImageTransform.Microsoft.BasicImage(opacity="+
opacity+")\n";}
node.style.filter=filter;var centerPoint=new OpenLayers.Geometry.Point(-xOffset,-yOffset);var imgBox=new OpenLayers.Bounds(0,0,width,height).toGeometry();imgBox.rotate(style.rotation,centerPoint);var imgBounds=imgBox.getBounds();node.style.left=Math.round(parseInt(node.style.left)+imgBounds.left)+"px";node.style.top=Math.round(parseInt(node.style.top)-imgBounds.bottom)+"px";},postDraw:function(node){node.style.visibility="visible";var fillColor=node._style.fillColor;var strokeColor=node._style.strokeColor;if(fillColor=="none"&&node.fillcolor!=fillColor){node.fillcolor=fillColor;}
if(strokeColor=="none"&&node.strokecolor!=strokeColor){node.strokecolor=strokeColor;}},setNodeDimension:function(node,geometry){var bbox=geometry.getBounds();if(bbox){var resolution=this.getResolution();var scaledBox=new OpenLayers.Bounds((bbox.left/resolution-this.offset.x)|0,(bbox.bottom/resolution-this.offset.y)|0,(bbox.right/resolution-this.offset.x)|0,(bbox.top/resolution-this.offset.y)|0);node.style.left=scaledBox.left+"px";node.style.top=scaledBox.top+"px";node.style.width=scaledBox.getWidth()+"px";node.style.height=scaledBox.getHeight()+"px";node.coordorigin=scaledBox.left+" "+scaledBox.top;node.coordsize=scaledBox.getWidth()+" "+scaledBox.getHeight();}},dashStyle:function(style){var dash=style.strokeDashstyle;switch(dash){case'solid':case'dot':case'dash':case'dashdot':case'longdash':case'longdashdot':return dash;default:var parts=dash.split(/[ ,]/);if(parts.length==2){if(1*parts[0]>=2*parts[1]){return"longdash";}
return(parts[0]==1||parts[1]==1)?"dot":"dash";}else if(parts.length==4){return(1*parts[0]>=2*parts[1])?"longdashdot":"dashdot";}
return"solid";}},createNode:function(type,id){var node=document.createElement(type);if(id){node.id=id;}
node.unselectable='on';node.onselectstart=OpenLayers.Function.False;return node;},nodeTypeCompare:function(node,type){var subType=type;var splitIndex=subType.indexOf(":");if(splitIndex!=-1){subType=subType.substr(splitIndex+1);}
var nodeName=node.nodeName;splitIndex=nodeName.indexOf(":");if(splitIndex!=-1){nodeName=nodeName.substr(splitIndex+1);}
return(subType==nodeName);},createRenderRoot:function(){return this.nodeFactory(this.container.id+"_vmlRoot","div");},createRoot:function(suffix){return this.nodeFactory(this.container.id+suffix,"olv:group");},drawPoint:function(node,geometry){return this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){if(!isNaN(geometry.x)&&!isNaN(geometry.y)){var resolution=this.getResolution();node.style.left=(((geometry.x/resolution-this.offset.x)|0)-radius)+"px";node.style.top=(((geometry.y/resolution-this.offset.y)|0)-radius)+"px";var diameter=radius*2;node.style.width=diameter+"px";node.style.height=diameter+"px";return node;}
return false;},drawLineString:function(node,geometry){return this.drawLine(node,geometry,false);},drawLinearRing:function(node,geometry){return this.drawLine(node,geometry,true);},drawLine:function(node,geometry,closeLine){this.setNodeDimension(node,geometry);var resolution=this.getResolution();var numComponents=geometry.components.length;var parts=new Array(numComponents);var comp,x,y;for(var i=0;i<numComponents;i++){comp=geometry.components[i];x=(comp.x/resolution-this.offset.x)|0;y=(comp.y/resolution-this.offset.y)|0;parts[i]=" "+x+","+y+" l ";}
var end=(closeLine)?" x e":" e";node.path="m"+parts.join("")+end;return node;},drawPolygon:function(node,geometry){this.setNodeDimension(node,geometry);var resolution=this.getResolution();var path=[];var linearRing,i,j,len,ilen,comp,x,y;for(j=0,len=geometry.components.length;j<len;j++){linearRing=geometry.components[j];path.push("m");for(i=0,ilen=linearRing.components.length;i<ilen;i++){comp=linearRing.components[i];x=(comp.x/resolution-this.offset.x)|0;y=(comp.y/resolution-this.offset.y)|0;path.push(" "+x+","+y);if(i==0){path.push(" l");}}
path.push(" x ");}
path.push("e");node.path=path.join("");return node;},drawRectangle:function(node,geometry){var resolution=this.getResolution();node.style.left=((geometry.x/resolution-this.offset.x)|0)+"px";node.style.top=((geometry.y/resolution-this.offset.y)|0)+"px";node.style.width=((geometry.width/resolution)|0)+"px";node.style.height=((geometry.height/resolution)|0)+"px";return node;},drawText:function(featureId,style,location){var label=this.nodeFactory(featureId+this.LABEL_ID_SUFFIX,"olv:rect");var textbox=this.nodeFactory(featureId+this.LABEL_ID_SUFFIX+"_textbox","olv:textbox");var resolution=this.getResolution();label.style.left=((location.x/resolution-this.offset.x)|0)+"px";label.style.top=((location.y/resolution-this.offset.y)|0)+"px";label.style.flip="y";textbox.innerText=style.label;if(style.fontColor){textbox.style.color=style.fontColor;}
if(style.fontOpacity){textbox.style.filter='alpha(opacity='+(style.fontOpacity*100)+')';}
if(style.fontFamily){textbox.style.fontFamily=style.fontFamily;}
if(style.fontSize){textbox.style.fontSize=style.fontSize;}
if(style.fontWeight){textbox.style.fontWeight=style.fontWeight;}
if(style.labelSelect===true){label._featureId=featureId;textbox._featureId=featureId;textbox._geometry=location;textbox._geometryClass=location.CLASS_NAME;}
textbox.style.whiteSpace="nowrap";textbox.inset="1px,0px,0px,0px";if(!label.parentNode){label.appendChild(textbox);this.textRoot.appendChild(label);}
var align=style.labelAlign||"cm";if(align.length==1){align+="m";}
var xshift=textbox.clientWidth*(OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);var yshift=textbox.clientHeight*(OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);label.style.left=parseInt(label.style.left)-xshift-1+"px";label.style.top=parseInt(label.style.top)+yshift+"px";},drawSurface:function(node,geometry){this.setNodeDimension(node,geometry);var resolution=this.getResolution();var path=[];var comp,x,y;for(var i=0,len=geometry.components.length;i<len;i++){comp=geometry.components[i];x=(comp.x/resolution-this.offset.x)|0;y=(comp.y/resolution-this.offset.y)|0;if((i%3)==0&&(i/3)==0){path.push("m");}else if((i%3)==1){path.push(" c");}
path.push(" "+x+","+y);}
path.push(" x e");node.path=path.join("");return node;},moveRoot:function(renderer){var layer=this.map.getLayer(renderer.container.id);if(layer instanceof OpenLayers.Layer.Vector.RootContainer){layer=this.map.getLayer(this.container.id);}
layer&&layer.renderer.clear();OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this,arguments);layer&&layer.redraw();},importSymbol:function(graphicName){var id=this.container.id+"-"+graphicName;var cache=this.symbolCache[id];if(cache){return cache;}
var symbol=OpenLayers.Renderer.symbol[graphicName];if(!symbol){throw new Error(graphicName+' is not a valid symbol name');}
var symbolExtent=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);var pathitems=["m"];for(var i=0;i<symbol.length;i=i+2){var x=symbol[i];var y=symbol[i+1];symbolExtent.left=Math.min(symbolExtent.left,x);symbolExtent.bottom=Math.min(symbolExtent.bottom,y);symbolExtent.right=Math.max(symbolExtent.right,x);symbolExtent.top=Math.max(symbolExtent.top,y);pathitems.push(x);pathitems.push(y);if(i==0){pathitems.push("l");}}
pathitems.push("x e");var path=pathitems.join(" ");var diff=(symbolExtent.getWidth()-symbolExtent.getHeight())/2;if(diff>0){symbolExtent.bottom=symbolExtent.bottom-diff;symbolExtent.top=symbolExtent.top+diff;}else{symbolExtent.left=symbolExtent.left+diff;symbolExtent.right=symbolExtent.right-diff;}
cache={path:path,size:symbolExtent.getWidth(),left:symbolExtent.left,bottom:symbolExtent.bottom};this.symbolCache[id]=cache;return cache;},CLASS_NAME:"OpenLayers.Renderer.VML"});OpenLayers.Renderer.VML.LABEL_SHIFT={"l":0,"c":.5,"r":1,"t":0,"m":.5,"b":1};OpenLayers.Tile=OpenLayers.Class({EVENT_TYPES:["loadstart","loadend","reload","unload"],events:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,initialize:function(layer,position,bounds,url,size){this.layer=layer;this.position=position.clone();this.bounds=bounds.clone();this.url=url;this.size=size.clone();this.id=OpenLayers.Util.createUniqueID("Tile_");this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},unload:function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("unload");}},destroy:function(){this.layer=null;this.bounds=null;this.size=null;this.position=null;this.events.destroy();this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Tile(this.layer,this.position,this.bounds,this.url,this.size);}
OpenLayers.Util.applyDefaults(obj,this);return obj;},draw:function(){var maxExtent=this.layer.maxExtent;var withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));this.shouldDraw=(withinMaxExtent||this.layer.displayOutsideMaxExtent);this.clear();return this.shouldDraw;},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
this.bounds=bounds.clone();this.position=position.clone();if(redraw){this.draw();}},clear:function(){},getBoundsFromBaseLayer:function(position){var msg=OpenLayers.i18n('reprojectDeprecated',{'layerName':this.layer.name});OpenLayers.Console.warn(msg);var topLeft=this.layer.map.getLonLatFromLayerPx(position);var bottomRightPx=position.clone();bottomRightPx.x+=this.size.w;bottomRightPx.y+=this.size.h;var bottomRight=this.layer.map.getLonLatFromLayerPx(bottomRightPx);if(topLeft.lon>bottomRight.lon){if(topLeft.lon<0){topLeft.lon=-180-(topLeft.lon+180);}else{bottomRight.lon=180+bottomRight.lon+180;}}
var bounds=new OpenLayers.Bounds(topLeft.lon,bottomRight.lat,bottomRight.lon,topLeft.lat);return bounds;},showTile:function(){if(this.shouldDraw){this.show();}},show:function(){},hide:function(){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Control.MouseToolbar=OpenLayers.Class(OpenLayers.Control.MouseDefaults,{mode:null,buttons:null,direction:"vertical",buttonClicked:null,initialize:function(position,direction){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.position=new OpenLayers.Pixel(OpenLayers.Control.MouseToolbar.X,OpenLayers.Control.MouseToolbar.Y);if(position){this.position=position;}
if(direction){this.direction=direction;}
this.measureDivs=[];},destroy:function(){for(var btnId in this.buttons){var btn=this.buttons[btnId];btn.map=null;btn.events.destroy();}
OpenLayers.Control.MouseDefaults.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);OpenLayers.Control.MouseDefaults.prototype.draw.apply(this,arguments);this.buttons={};var sz=new OpenLayers.Size(28,28);var centered=new OpenLayers.Pixel(OpenLayers.Control.MouseToolbar.X,0);this._addButton("zoombox","drag-rectangle-off.png","drag-rectangle-on.png",centered,sz,"Shift->Drag to zoom to area");centered=centered.add((this.direction=="vertical"?0:sz.w),(this.direction=="vertical"?sz.h:0));this._addButton("pan","panning-hand-off.png","panning-hand-on.png",centered,sz,"Drag the map to pan.");centered=centered.add((this.direction=="vertical"?0:sz.w),(this.direction=="vertical"?sz.h:0));this.switchModeTo("pan");return this.div;},_addButton:function(id,img,activeImg,xy,sz,title){var imgLocation=OpenLayers.Util.getImagesLocation()+img;var activeImgLocation=OpenLayers.Util.getImagesLocation()+activeImg;var btn=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MouseToolbar_"+id,xy,sz,imgLocation,"absolute");this.div.appendChild(btn);btn.imgLocation=imgLocation;btn.activeImgLocation=activeImgLocation;btn.events=new OpenLayers.Events(this,btn,null,true);btn.events.on({"mousedown":this.buttonDown,"mouseup":this.buttonUp,"dblclick":OpenLayers.Event.stop,scope:this});btn.action=id;btn.title=title;btn.alt=title;btn.map=this.map;this.buttons[id]=btn;return btn;},buttonDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
this.buttonClicked=evt.element.action;OpenLayers.Event.stop(evt);},buttonUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
if(this.buttonClicked!=null){if(this.buttonClicked==evt.element.action){this.switchModeTo(evt.element.action);}
OpenLayers.Event.stop(evt);this.buttonClicked=null;}},defaultDblClick:function(evt){this.switchModeTo("pan");this.performedDrag=false;var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);OpenLayers.Event.stop(evt);return false;},defaultMouseDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
this.mouseDragStart=evt.xy.clone();this.performedDrag=false;this.startViaKeyboard=false;if(evt.shiftKey&&this.mode!="zoombox"){this.switchModeTo("zoombox");this.startViaKeyboard=true;}else if(evt.altKey&&this.mode!="measure"){this.switchModeTo("measure");}else if(!this.mode){this.switchModeTo("pan");}
switch(this.mode){case"zoombox":this.map.div.style.cursor="crosshair";this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.mouseDragStart,null,null,"absolute","2px solid red");this.zoomBox.style.backgroundColor="white";this.zoomBox.style.filter="alpha(opacity=50)";this.zoomBox.style.opacity="0.50";this.zoomBox.style.fontSize="1px";this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);this.performedDrag=true;break;case"measure":var distance="";if(this.measureStart){var measureEnd=this.map.getLonLatFromViewPortPx(this.mouseDragStart);distance=OpenLayers.Util.distVincenty(this.measureStart,measureEnd);distance=Math.round(distance*100)/100;distance=distance+"km";this.measureStartBox=this.measureBox;}
this.measureStart=this.map.getLonLatFromViewPortPx(this.mouseDragStart);;this.measureBox=OpenLayers.Util.createDiv(null,this.mouseDragStart.add(-2-parseInt(this.map.layerContainerDiv.style.left),-2-parseInt(this.map.layerContainerDiv.style.top)),null,null,"absolute");this.measureBox.style.width="4px";this.measureBox.style.height="4px";this.measureBox.style.fontSize="1px";this.measureBox.style.backgroundColor="red";this.measureBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.layerContainerDiv.appendChild(this.measureBox);if(distance){this.measureBoxDistance=OpenLayers.Util.createDiv(null,this.mouseDragStart.add(-2-parseInt(this.map.layerContainerDiv.style.left),2-parseInt(this.map.layerContainerDiv.style.top)),null,null,"absolute");this.measureBoxDistance.innerHTML=distance;this.measureBoxDistance.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.layerContainerDiv.appendChild(this.measureBoxDistance);this.measureDivs.push(this.measureBoxDistance);}
this.measureBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.layerContainerDiv.appendChild(this.measureBox);this.measureDivs.push(this.measureBox);break;default:this.map.div.style.cursor="move";break;}
document.onselectstart=OpenLayers.Function.False;OpenLayers.Event.stop(evt);},switchModeTo:function(mode){if(mode!=this.mode){if(this.mode&&this.buttons[this.mode]){OpenLayers.Util.modifyAlphaImageDiv(this.buttons[this.mode],null,null,null,this.buttons[this.mode].imgLocation);}
if(this.mode=="measure"&&mode!="measure"){for(var i=0,len=this.measureDivs.length;i<len;i++){if(this.measureDivs[i]){this.map.layerContainerDiv.removeChild(this.measureDivs[i]);}}
this.measureDivs=[];this.measureStart=null;}
this.mode=mode;if(this.buttons[mode]){OpenLayers.Util.modifyAlphaImageDiv(this.buttons[mode],null,null,null,this.buttons[mode].activeImgLocation);}
switch(this.mode){case"zoombox":this.map.div.style.cursor="crosshair";break;default:this.map.div.style.cursor="";break;}}},leaveMode:function(){this.switchModeTo("pan");},defaultMouseMove:function(evt){if(this.mouseDragStart!=null){switch(this.mode){case"zoombox":var deltaX=Math.abs(this.mouseDragStart.x-evt.xy.x);var deltaY=Math.abs(this.mouseDragStart.y-evt.xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";if(evt.xy.x<this.mouseDragStart.x){this.zoomBox.style.left=evt.xy.x+"px";}
if(evt.xy.y<this.mouseDragStart.y){this.zoomBox.style.top=evt.xy.y+"px";}
break;default:var deltaX=this.mouseDragStart.x-evt.xy.x;var deltaY=this.mouseDragStart.y-evt.xy.y;var size=this.map.getSize();var newXY=new OpenLayers.Pixel(size.w/2+deltaX,size.h/2+deltaY);var newCenter=this.map.getLonLatFromViewPortPx(newXY);this.map.setCenter(newCenter,null,true);this.mouseDragStart=evt.xy.clone();}
this.performedDrag=true;}},defaultMouseUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
switch(this.mode){case"zoombox":this.zoomBoxEnd(evt);if(this.startViaKeyboard){this.leaveMode();}
break;case"pan":if(this.performedDrag){this.map.setCenter(this.map.center);}}
document.onselectstart=null;this.mouseDragStart=null;this.map.div.style.cursor="default";},defaultMouseOut:function(evt){if(this.mouseDragStart!=null&&OpenLayers.Util.mouseLeft(evt,this.map.div)){if(this.zoomBox){this.removeZoomBox();if(this.startViaKeyboard){this.leaveMode();}}
this.mouseDragStart=null;this.map.div.style.cursor="default";}},defaultClick:function(evt){if(this.performedDrag){this.performedDrag=false;return false;}},CLASS_NAME:"OpenLayers.Control.MouseToolbar"});OpenLayers.Control.MouseToolbar.X=6;OpenLayers.Control.MouseToolbar.Y=300;OpenLayers.Control.NavigationHistory=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOGGLE,previous:null,previousOptions:null,next:null,nextOptions:null,limit:50,autoActivate:true,clearOnDeactivate:false,registry:null,nextStack:null,previousStack:null,listeners:null,restoring:false,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.registry=OpenLayers.Util.extend({"moveend":this.getState},this.registry);var previousOptions={trigger:OpenLayers.Function.bind(this.previousTrigger,this),displayClass:this.displayClass+" "+this.displayClass+"Previous"};OpenLayers.Util.extend(previousOptions,this.previousOptions);this.previous=new OpenLayers.Control.Button(previousOptions);var nextOptions={trigger:OpenLayers.Function.bind(this.nextTrigger,this),displayClass:this.displayClass+" "+this.displayClass+"Next"};OpenLayers.Util.extend(nextOptions,this.nextOptions);this.next=new OpenLayers.Control.Button(nextOptions);this.clear();},onPreviousChange:function(state,length){if(state&&!this.previous.active){this.previous.activate();}else if(!state&&this.previous.active){this.previous.deactivate();}},onNextChange:function(state,length){if(state&&!this.next.active){this.next.activate();}else if(!state&&this.next.active){this.next.deactivate();}},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this);this.previous.destroy();this.next.destroy();this.deactivate();for(var prop in this){this[prop]=null;}},setMap:function(map){this.map=map;this.next.setMap(map);this.previous.setMap(map);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.next.draw();this.previous.draw();},previousTrigger:function(){var current=this.previousStack.shift();var state=this.previousStack.shift();if(state!=undefined){this.nextStack.unshift(current);this.previousStack.unshift(state);this.restoring=true;this.restore(state);this.restoring=false;this.onNextChange(this.nextStack[0],this.nextStack.length);this.onPreviousChange(this.previousStack[1],this.previousStack.length-1);}else{this.previousStack.unshift(current);}
return state;},nextTrigger:function(){var state=this.nextStack.shift();if(state!=undefined){this.previousStack.unshift(state);this.restoring=true;this.restore(state);this.restoring=false;this.onNextChange(this.nextStack[0],this.nextStack.length);this.onPreviousChange(this.previousStack[1],this.previousStack.length-1);}
return state;},clear:function(){this.previousStack=[];this.previous.deactivate();this.nextStack=[];this.next.deactivate();},getState:function(){return{center:this.map.getCenter(),resolution:this.map.getResolution(),projection:this.map.getProjectionObject(),units:this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units};},restore:function(state){var center,zoom;if(this.map.getProjectionObject()==state.projection){zoom=this.map.getZoomForResolution(state.resolution);center=state.center;}else{center=state.center.clone();center.transform(state.projection,this.map.getProjectionObject());var sourceUnits=state.units;var targetUnits=this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units;var resolutionFactor=sourceUnits&&targetUnits?OpenLayers.INCHES_PER_UNIT[sourceUnits]/OpenLayers.INCHES_PER_UNIT[targetUnits]:1;zoom=this.map.getZoomForResolution(resolutionFactor*state.resolution);}
this.map.setCenter(center,zoom);},setListeners:function(){this.listeners={};for(var type in this.registry){this.listeners[type]=OpenLayers.Function.bind(function(){if(!this.restoring){var state=this.registry[type].apply(this,arguments);this.previousStack.unshift(state);if(this.previousStack.length>1){this.onPreviousChange(this.previousStack[1],this.previousStack.length-1);}
if(this.previousStack.length>(this.limit+1)){this.previousStack.pop();}
if(this.nextStack.length>0){this.nextStack=[];this.onNextChange(null,0);}}
return true;},this);}},activate:function(){var activated=false;if(this.map){if(OpenLayers.Control.prototype.activate.apply(this)){if(this.listeners==null){this.setListeners();}
for(var type in this.listeners){this.map.events.register(type,this,this.listeners[type]);}
activated=true;if(this.previousStack.length==0){this.initStack();}}}
return activated;},initStack:function(){if(this.map.getCenter()){this.listeners.moveend();}},deactivate:function(){var deactivated=false;if(this.map){if(OpenLayers.Control.prototype.deactivate.apply(this)){for(var type in this.listeners){this.map.events.unregister(type,this,this.listeners[type]);}
if(this.clearOnDeactivate){this.clear();}
deactivated=true;}}
return deactivated;},CLASS_NAME:"OpenLayers.Control.NavigationHistory"});OpenLayers.Control.PanPanel=OpenLayers.Class(OpenLayers.Control.Panel,{slideFactor:50,initialize:function(options){OpenLayers.Control.Panel.prototype.initialize.apply(this,[options]);this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH,{slideFactor:this.slideFactor}),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH,{slideFactor:this.slideFactor}),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST,{slideFactor:this.slideFactor}),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST,{slideFactor:this.slideFactor})]);},CLASS_NAME:"OpenLayers.Control.PanPanel"});OpenLayers.Control.PanZoomBar=OpenLayers.Class(OpenLayers.Control.PanZoom,{zoomStopWidth:18,zoomStopHeight:11,slider:null,sliderEvents:null,zoombarDiv:null,divEvents:null,zoomWorldIcon:false,forceFixedZoomLevel:false,mouseDragStart:null,zoomStart:null,initialize:function(){OpenLayers.Control.PanZoom.prototype.initialize.apply(this,arguments);},destroy:function(){this._removeZoomBar();this.map.events.un({"changebaselayer":this.redraw,scope:this});OpenLayers.Control.PanZoom.prototype.destroy.apply(this,arguments);delete this.mouseDragStart;delete this.zoomStart;},setMap:function(map){OpenLayers.Control.PanZoom.prototype.setMap.apply(this,arguments);this.map.events.register("changebaselayer",this,this.redraw);},redraw:function(){if(this.div!=null){this.removeButtons();this._removeZoomBar();}
this.draw();},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position.clone();this.buttons=[];var sz=new OpenLayers.Size(18,18);var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);var wposition=sz.w;if(this.zoomWorldIcon){centered=new OpenLayers.Pixel(px.x+sz.w,px.y);}
this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);if(this.zoomWorldIcon){this._addButton("zoomworld","zoom-world-mini.png",px.add(sz.w,0),sz);wposition*=2;}
this._addButton("panright","east-mini.png",px.add(wposition,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);centered=this._addZoomBar(centered.add(0,sz.h*4+5));this._addButton("zoomout","zoom-minus-mini.png",centered,sz);return this.div;},_addZoomBar:function(centered){var imgLocation=OpenLayers.Util.getImagesLocation();var id=this.id+"_"+this.map.id;var zoomsToEnd=this.map.getNumZoomLevels()-1-this.map.getZoom();var slider=OpenLayers.Util.createAlphaImageDiv(id,centered.add(-1,zoomsToEnd*this.zoomStopHeight),new OpenLayers.Size(20,9),imgLocation+"slider.png","absolute");this.slider=slider;this.sliderEvents=new OpenLayers.Events(this,slider,null,true,{includeXY:true});this.sliderEvents.on({"mousedown":this.zoomBarDown,"mousemove":this.zoomBarDrag,"mouseup":this.zoomBarUp,"dblclick":this.doubleClick,"click":this.doubleClick});var sz=new OpenLayers.Size();sz.h=this.zoomStopHeight*this.map.getNumZoomLevels();sz.w=this.zoomStopWidth;var div=null;if(OpenLayers.Util.alphaHack()){var id=this.id+"_"+this.map.id;div=OpenLayers.Util.createAlphaImageDiv(id,centered,new OpenLayers.Size(sz.w,this.zoomStopHeight),imgLocation+"zoombar.png","absolute",null,"crop");div.style.height=sz.h+"px";}else{div=OpenLayers.Util.createDiv('OpenLayers_Control_PanZoomBar_Zoombar'+this.map.id,centered,sz,imgLocation+"zoombar.png");}
this.zoombarDiv=div;this.divEvents=new OpenLayers.Events(this,div,null,true,{includeXY:true});this.divEvents.on({"mousedown":this.divClick,"mousemove":this.passEventToSlider,"dblclick":this.doubleClick,"click":this.doubleClick});this.div.appendChild(div);this.startTop=parseInt(div.style.top);this.div.appendChild(slider);this.map.events.register("zoomend",this,this.moveZoomBar);centered=centered.add(0,this.zoomStopHeight*this.map.getNumZoomLevels());return centered;},_removeZoomBar:function(){this.sliderEvents.un({"mousedown":this.zoomBarDown,"mousemove":this.zoomBarDrag,"mouseup":this.zoomBarUp,"dblclick":this.doubleClick,"click":this.doubleClick});this.sliderEvents.destroy();this.divEvents.un({"mousedown":this.divClick,"mousemove":this.passEventToSlider,"dblclick":this.doubleClick,"click":this.doubleClick});this.divEvents.destroy();this.div.removeChild(this.zoombarDiv);this.zoombarDiv=null;this.div.removeChild(this.slider);this.slider=null;this.map.events.unregister("zoomend",this,this.moveZoomBar);},passEventToSlider:function(evt){this.sliderEvents.handleBrowserEvent(evt);},divClick:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
var y=evt.xy.y;var top=OpenLayers.Util.pagePosition(evt.object)[1];var levels=(y-top)/this.zoomStopHeight;if(this.forceFixedZoomLevel||!this.map.fractionalZoom){levels=Math.floor(levels);}
var zoom=(this.map.getNumZoomLevels()-1)-levels;zoom=Math.min(Math.max(zoom,0),this.map.getNumZoomLevels()-1);this.map.zoomTo(zoom);OpenLayers.Event.stop(evt);},zoomBarDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
this.map.events.on({"mousemove":this.passEventToSlider,"mouseup":this.passEventToSlider,scope:this});this.mouseDragStart=evt.xy.clone();this.zoomStart=evt.xy.clone();this.div.style.cursor="move";this.zoombarDiv.offsets=null;OpenLayers.Event.stop(evt);},zoomBarDrag:function(evt){if(this.mouseDragStart!=null){var deltaY=this.mouseDragStart.y-evt.xy.y;var offsets=OpenLayers.Util.pagePosition(this.zoombarDiv);if((evt.clientY-offsets[1])>0&&(evt.clientY-offsets[1])<parseInt(this.zoombarDiv.style.height)-2){var newTop=parseInt(this.slider.style.top)-deltaY;this.slider.style.top=newTop+"px";this.mouseDragStart=evt.xy.clone();}
OpenLayers.Event.stop(evt);}},zoomBarUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
if(this.mouseDragStart){this.div.style.cursor="";this.map.events.un({"mouseup":this.passEventToSlider,"mousemove":this.passEventToSlider,scope:this});var deltaY=this.zoomStart.y-evt.xy.y;var zoomLevel=this.map.zoom;if(!this.forceFixedZoomLevel&&this.map.fractionalZoom){zoomLevel+=deltaY/this.zoomStopHeight;zoomLevel=Math.min(Math.max(zoomLevel,0),this.map.getNumZoomLevels()-1);}else{zoomLevel+=Math.round(deltaY/this.zoomStopHeight);}
this.map.zoomTo(zoomLevel);this.mouseDragStart=null;this.zoomStart=null;OpenLayers.Event.stop(evt);}},moveZoomBar:function(){var newTop=((this.map.getNumZoomLevels()-1)-this.map.getZoom())*this.zoomStopHeight+this.startTop+1;this.slider.style.top=newTop+"px";},CLASS_NAME:"OpenLayers.Control.PanZoomBar"});OpenLayers.Control.Permalink=OpenLayers.Class(OpenLayers.Control,{argParserClass:OpenLayers.Control.ArgParser,element:null,base:'',displayProjection:null,initialize:function(element,base,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.element=OpenLayers.Util.getElement(element);this.base=base||document.location.href;},destroy:function(){if(this.element.parentNode==this.div){this.div.removeChild(this.element);}
this.element=null;this.map.events.unregister('moveend',this,this.updateLink);OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0,len=this.map.controls.length;i<len;i++){var control=this.map.controls[i];if(control.CLASS_NAME==this.argParserClass.CLASS_NAME){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
break;}}
if(i==this.map.controls.length){this.map.addControl(new this.argParserClass({'displayProjection':this.displayProjection}));}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.className=this.displayClass;this.element=document.createElement("a");this.element.innerHTML=OpenLayers.i18n("permalink");this.element.href="";this.div.appendChild(this.element);}
this.map.events.on({'moveend':this.updateLink,'changelayer':this.updateLink,'changebaselayer':this.updateLink,scope:this});this.updateLink();return this.div;},updateLink:function(){var href=this.base;if(href.indexOf('?')!=-1){href=href.substring(0,href.indexOf('?'));}
href+='?'+OpenLayers.Util.getParameterString(this.createParams());this.element.href=href;},createParams:function(center,zoom,layers){center=center||this.map.getCenter();var params=OpenLayers.Util.getParameters(this.base);if(center){params.zoom=zoom||this.map.getZoom();var lat=center.lat;var lon=center.lon;if(this.displayProjection){var mapPosition=OpenLayers.Projection.transform({x:lon,y:lat},this.map.getProjectionObject(),this.displayProjection);lon=mapPosition.x;lat=mapPosition.y;}
params.lat=Math.round(lat*100000)/100000;params.lon=Math.round(lon*100000)/100000;layers=layers||this.map.layers;params.layers='';for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];if(layer.isBaseLayer){params.layers+=(layer==this.map.baseLayer)?"B":"0";}else{params.layers+=(layer.getVisibility())?"T":"F";}}}
return params;},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Control.ZoomPanel=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(options){OpenLayers.Control.Panel.prototype.initialize.apply(this,[options]);this.addControls([new OpenLayers.Control.ZoomIn(),new OpenLayers.Control.ZoomToMaxExtent(),new OpenLayers.Control.ZoomOut()]);},CLASS_NAME:"OpenLayers.Control.ZoomPanel"});OpenLayers.Format.CSWGetDomain=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Format.CSWGetDomain.DEFAULTS);var cls=OpenLayers.Format.CSWGetDomain["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported CSWGetDomain version: "+options.version;}
return new cls(options);};OpenLayers.Format.CSWGetDomain.DEFAULTS={"version":"2.0.2"};OpenLayers.Format.CSWGetRecords=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Format.CSWGetRecords.DEFAULTS);var cls=OpenLayers.Format.CSWGetRecords["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported CSWGetRecords version: "+options.version;}
return new cls(options);};OpenLayers.Format.CSWGetRecords.DEFAULTS={"version":"2.0.2"};OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:"    ",space:" ",newline:"\n",level:0,pretty:false,initialize:function(options){OpenLayers.Format.prototype.initialize.apply(this,[options]);},read:function(json,filter){try{if(/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){var object=eval('('+json+')');if(typeof filter==='function'){function walk(k,v){if(v&&typeof v==='object'){for(var i in v){if(v.hasOwnProperty(i)){v[i]=walk(i,v[i]);}}}
return filter(k,v);}
object=walk('',object);}
if(this.keepData){this.data=object;}
return object;}}catch(e){}
return null;},write:function(value,pretty){this.pretty=!!pretty;var json=null;var type=typeof value;if(this.serialize[type]){try{json=this.serialize[type].apply(this,[value]);}catch(err){OpenLayers.Console.error("Trouble serializing: "+err);}}
return json;},writeIndent:function(){var pieces=[];if(this.pretty){for(var i=0;i<this.level;++i){pieces.push(this.indent);}}
return pieces.join('');},writeNewline:function(){return(this.pretty)?this.newline:'';},writeSpace:function(){return(this.pretty)?this.space:'';},serialize:{'object':function(object){if(object==null){return"null";}
if(object.constructor==Date){return this.serialize.date.apply(this,[object]);}
if(object.constructor==Array){return this.serialize.array.apply(this,[object]);}
var pieces=['{'];this.level+=1;var key,keyJSON,valueJSON;var addComma=false;for(key in object){if(object.hasOwnProperty(key)){keyJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[key,this.pretty]);valueJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[object[key],this.pretty]);if(keyJSON!=null&&valueJSON!=null){if(addComma){pieces.push(',');}
pieces.push(this.writeNewline(),this.writeIndent(),keyJSON,':',this.writeSpace(),valueJSON);addComma=true;}}}
this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),'}');return pieces.join('');},'array':function(array){var json;var pieces=['['];this.level+=1;for(var i=0,len=array.length;i<len;++i){json=OpenLayers.Format.JSON.prototype.write.apply(this,[array[i],this.pretty]);if(json!=null){if(i>0){pieces.push(',');}
pieces.push(this.writeNewline(),this.writeIndent(),json);}}
this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),']');return pieces.join('');},'string':function(string){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};if(/["\\\x00-\x1f]/.test(string)){return'"'+string.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}
c=b.charCodeAt();return'\\u00'+
Math.floor(c/16).toString(16)+
(c%16).toString(16);})+'"';}
return'"'+string+'"';},'number':function(number){return isFinite(number)?String(number):"null";},'boolean':function(bool){return String(bool);},'date':function(date){function format(number){return(number<10)?'0'+number:number;}
return'"'+date.getFullYear()+'-'+
format(date.getMonth()+1)+'-'+
format(date.getDate())+'T'+
format(date.getHours())+':'+
format(date.getMinutes())+':'+
format(date.getSeconds())+'"';}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Format.WFST=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Format.WFST.DEFAULTS);var cls=OpenLayers.Format.WFST["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported WFST version: "+options.version;}
return new cls(options);};OpenLayers.Format.WFST.DEFAULTS={"version":"1.0.0"};OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(options){if(window.ActiveXObject){this.xmldom=new ActiveXObject("Microsoft.XMLDOM");}
OpenLayers.Format.prototype.initialize.apply(this,[options]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var alias in this.namespaces){this.namespaceAlias[this.namespaces[alias]]=alias;}},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,arguments);},setNamespace:function(alias,uri){this.namespaces[alias]=uri;this.namespaceAlias[uri]=alias;},read:function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
var node=OpenLayers.Util.Try(OpenLayers.Function.bind((function(){var xmldom;if(window.ActiveXObject&&!this.xmldom){xmldom=new ActiveXObject("Microsoft.XMLDOM");}else{xmldom=this.xmldom;}
xmldom.loadXML(text);return xmldom;}),this),function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
req.send(null);return req.responseXML;});if(this.keepData){this.data=node;}
return node;},write:function(node){var data;if(this.xmldom){data=node.xml;}else{var serializer=new XMLSerializer();if(node.nodeType==1){var doc=document.implementation.createDocument("","",null);if(doc.importNode){node=doc.importNode(node,true);}
doc.appendChild(node);data=serializer.serializeToString(doc);}else{data=serializer.serializeToString(node);}}
return data;},createElementNS:function(uri,name){var element;if(this.xmldom){if(typeof uri=="string"){element=this.xmldom.createNode(1,name,uri);}else{element=this.xmldom.createNode(1,name,"");}}else{element=document.createElementNS(uri,name);}
return element;},createTextNode:function(text){var node;if(typeof text!=="string"){text=String(text);}
if(this.xmldom){node=this.xmldom.createTextNode(text);}else{node=document.createTextNode(text);}
return node;},getElementsByTagNameNS:function(node,uri,name){var elements=[];if(node.getElementsByTagNameNS){elements=node.getElementsByTagNameNS(uri,name);}else{var allNodes=node.getElementsByTagName("*");var potentialNode,fullName;for(var i=0,len=allNodes.length;i<len;++i){potentialNode=allNodes[i];fullName=(potentialNode.prefix)?(potentialNode.prefix+":"+name):name;if((name=="*")||(fullName==potentialNode.nodeName)){if((uri=="*")||(uri==potentialNode.namespaceURI)){elements.push(potentialNode);}}}}
return elements;},getAttributeNodeNS:function(node,uri,name){var attributeNode=null;if(node.getAttributeNodeNS){attributeNode=node.getAttributeNodeNS(uri,name);}else{var attributes=node.attributes;var potentialNode,fullName;for(var i=0,len=attributes.length;i<len;++i){potentialNode=attributes[i];if(potentialNode.namespaceURI==uri){fullName=(potentialNode.prefix)?(potentialNode.prefix+":"+name):name;if(fullName==potentialNode.nodeName){attributeNode=potentialNode;break;}}}}
return attributeNode;},getAttributeNS:function(node,uri,name){var attributeValue="";if(node.getAttributeNS){attributeValue=node.getAttributeNS(uri,name)||"";}else{var attributeNode=this.getAttributeNodeNS(node,uri,name);if(attributeNode){attributeValue=attributeNode.nodeValue;}}
return attributeValue;},getChildValue:function(node,def){var value=def||"";if(node){for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 3:case 4:value+=child.nodeValue;}}}
return value;},concatChildValues:function(node,def){var value="";var child=node.firstChild;var childValue;while(child){childValue=child.nodeValue;if(childValue){value+=childValue;}
child=child.nextSibling;}
if(value==""&&def!=undefined){value=def;}
return value;},isSimpleContent:function(node){var simple=true;for(var child=node.firstChild;child;child=child.nextSibling){if(child.nodeType===1){simple=false;break;}}
return simple;},contentType:function(node){var simple=false,complex=false;var type=OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 1:complex=true;break;case 8:break;default:simple=true;}
if(complex&&simple){break;}}
if(complex&&simple){type=OpenLayers.Format.XML.CONTENT_TYPE.MIXED;}else if(complex){return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;}else if(simple){return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;}
return type;},hasAttributeNS:function(node,uri,name){var found=false;if(node.hasAttributeNS){found=node.hasAttributeNS(uri,name);}else{found=!!this.getAttributeNodeNS(node,uri,name);}
return found;},setAttributeNS:function(node,uri,name,value){if(node.setAttributeNS){node.setAttributeNS(uri,name,value);}else{if(this.xmldom){if(uri){var attribute=node.ownerDocument.createNode(2,name,uri);attribute.nodeValue=value;node.setAttributeNode(attribute);}else{node.setAttribute(name,value);}}else{throw"setAttributeNS not implemented";}}},createElementNSPlus:function(name,options){options=options||{};var uri=options.uri||this.namespaces[options.prefix];if(!uri){var loc=name.indexOf(":");uri=this.namespaces[name.substring(0,loc)];}
if(!uri){uri=this.namespaces[this.defaultPrefix];}
var node=this.createElementNS(uri,name);if(options.attributes){this.setAttributes(node,options.attributes);}
var value=options.value;if(value!=null){node.appendChild(this.createTextNode(value));}
return node;},setAttributes:function(node,obj){var value,uri;for(var name in obj){if(obj[name]!=null&&obj[name].toString){value=obj[name].toString();uri=this.namespaces[name.substring(0,name.indexOf(":"))]||null;this.setAttributeNS(node,uri,name,value);}}},readNode:function(node,obj){if(!obj){obj={};}
var group=this.readers[node.namespaceURI?this.namespaceAlias[node.namespaceURI]:this.defaultPrefix];if(group){var local=node.localName||node.nodeName.split(":").pop();var reader=group[local]||group["*"];if(reader){reader.apply(this,[node,obj]);}}
return obj;},readChildNodes:function(node,obj){if(!obj){obj={};}
var children=node.childNodes;var child;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){this.readNode(child,obj);}}
return obj;},writeNode:function(name,obj,parent){var prefix,local;var split=name.indexOf(":");if(split>0){prefix=name.substring(0,split);local=name.substring(split+1);}else{if(parent){prefix=this.namespaceAlias[parent.namespaceURI];}else{prefix=this.defaultPrefix;}
local=name;}
var child=this.writers[prefix][local].apply(this,[obj]);if(parent){parent.appendChild(child);}
return child;},getChildEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.firstChild,name,uri);},getNextEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.nextSibling,name,uri);},getThisOrNextEl:function(node,name,uri){outer:for(var sibling=node;sibling;sibling=sibling.nextSibling){switch(sibling.nodeType){case 1:if((!name||name===(sibling.localName||sibling.nodeName.split(":").pop()))&&(!uri||uri===sibling.namespaceURI)){break outer;}
sibling=null;break outer;case 3:if(/^\s*$/.test(sibling.nodeValue)){break;}
case 4:case 6:case 12:case 10:case 11:sibling=null;break outer;}}
return sibling||null;},lookupNamespaceURI:function(node,prefix){var uri=null;if(node){if(node.lookupNamespaceURI){uri=node.lookupNamespaceURI(prefix);}else{outer:switch(node.nodeType){case 1:if(node.namespaceURI!==null&&node.prefix===prefix){uri=node.namespaceURI;break outer;}
var len=node.attributes.length;if(len){var attr;for(var i=0;i<len;++i){attr=node.attributes[i];if(attr.prefix==="xmlns"&&attr.name==="xmlns:"+prefix){uri=attr.value||null;break outer;}else if(attr.name==="xmlns"&&prefix===null){uri=attr.value||null;break outer;}}}
uri=this.lookupNamespaceURI(node.parentNode,prefix);break outer;case 2:uri=this.lookupNamespaceURI(node.ownerElement,prefix);break outer;case 9:uri=this.lookupNamespaceURI(node.documentElement,prefix);break outer;case 6:case 12:case 10:case 11:break outer;default:uri=this.lookupNamespaceURI(node.parentNode,prefix);break outer;}}}
return uri;},CLASS_NAME:"OpenLayers.Format.XML"});OpenLayers.Format.XML.CONTENT_TYPE={EMPTY:0,SIMPLE:1,COMPLEX:2,MIXED:3};OpenLayers.Format.XML.lookupNamespaceURI=OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI,OpenLayers.Format.XML.prototype);OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;var map=this.map||control.map;if(map){this.setMap(map);}
this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
this.active=false;return true;},callback:function(name,args){if(name&&this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1000},EVENT_TYPES:["preaddlayer","addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,fractionalZoom:false,events:null,allOverlays:false,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,paddingForPopups:null,initialize:function(div,options){if(arguments.length===1&&typeof div==="object"){options=div;div=options&&options.div;}
this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()?OpenLayers._getScriptLocation()+'theme/default/style.css':null;OpenLayers.Util.extend(this,options);this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);if(!this.div){this.div=document.createElement("div");this.div.style.height="1px";this.div.style.width="1px";}
OpenLayers.Element.addClass(this.div,'olMap');var id=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);id=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough,{includeXY:true});this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
this.events.register("movestart",this,this.updateSize);if(OpenLayers.String.contains(navigator.appName,"Microsoft")){this.events.register("resize",this,this.updateSize);}else{this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,'resize',this.updateSizeDestroy);}
if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0,len=nodes.length;i<len;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
if(this.controls==null){if(OpenLayers.Control!=null){this.controls=[new OpenLayers.Control.Navigation(),new OpenLayers.Control.PanZoom(),new OpenLayers.Control.ArgParser(),new OpenLayers.Control.Attribution()];}else{this.controls=[];}}
for(var i=0,len=this.controls.length;i<len;i++){this.addControlToMap(this.controls[i]);}
this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);if(options&&options.layers){this.addLayers(options.layers);if(options.center){this.setCenter(options.center,options.zoom);}}},render:function(div){this.div=OpenLayers.Util.getElement(div);OpenLayers.Element.addClass(this.div,'olMap');this.events.attachToElement(this.div);this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);this.div.appendChild(this.viewPortDiv);this.updateSize();},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
if(this.panTween){this.panTween.stop();this.panTween=null;}
OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.updateSizeDestroy){OpenLayers.Event.stopObserving(window,'resize',this.updateSizeDestroy);}else{this.events.unregister("resize",this,this.updateSize);}
this.paddingForPopups=null;if(this.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
this.controls=null;}
if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);}
this.layers=null;}
if(this.viewPortDiv){this.div.removeChild(this.viewPortDiv);}
this.viewPortDiv=null;if(this.eventListeners){this.events.un(this.eventListeners);this.eventListeners=null;}
this.events.destroy();this.events=null;},setOptions:function(options){OpenLayers.Util.extend(this,options);},getTileSize:function(){return this.tileSize;},getBy:function(array,property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this[array],function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getLayersBy:function(property,match){return this.getBy("layers",property,match);},getLayersByName:function(match){return this.getLayersBy("name",match);},getLayersByClass:function(match){return this.getLayersBy("CLASS_NAME",match);},getControlsBy:function(property,match){return this.getBy("controls",property,match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},getLayer:function(id){var foundLayer=null;for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;break;}}
return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
+zIdx*5);},resetLayersZIndex:function(){for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];this.setLayerZIndex(layer,i);}},addLayer:function(layer){for(var i=0,len=this.layers.length;i<len;i++){if(this.layers[i]==layer){var msg=OpenLayers.i18n('layerAlreadyAdded',{'layerName':layer.name});OpenLayers.Console.warn(msg);return false;}}
if(this.allOverlays){layer.isBaseLayer=false;}
if(this.events.triggerEvent("preaddlayer",{layer:layer})===false){return;}
layer.div.className="olLayerDiv";layer.div.style.overflow="";this.setLayerZIndex(layer,this.layers.length);if(layer.isFixed){this.viewPortDiv.appendChild(layer.div);}else{this.layerContainerDiv.appendChild(layer.div);}
this.layers.push(layer);layer.setMap(this);if(layer.isBaseLayer||(this.allOverlays&&!this.baseLayer)){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
this.events.triggerEvent("addlayer",{layer:layer});layer.afterAdd();},addLayers:function(layers){for(var i=0,len=layers.length;i<len;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
if(layer.isFixed){this.viewPortDiv.removeChild(layer.div);}else{this.layerContainerDiv.removeChild(layer.div);}
OpenLayers.Util.removeItem(this.layers,layer);layer.removeMap(this);layer.map=null;if(this.baseLayer==layer){this.baseLayer=null;if(setNewBaseLayer){for(var i=0,len=this.layers.length;i<len;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer||this.allOverlays){this.setBaseLayer(iLayer);break;}}}}
this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:layer});},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},setLayerIndex:function(layer,idx){var base=this.getLayerIndex(layer);if(idx<0){idx=0;}else if(idx>this.layers.length){idx=this.layers.length;}
if(base!=idx){this.layers.splice(base,1);this.layers.splice(idx,0,layer);for(var i=0,len=this.layers.length;i<len;i++){this.setLayerZIndex(this.layers[i],i);}
this.events.triggerEvent("changelayer",{layer:layer,property:"order"});if(this.allOverlays){if(idx===0){this.setBaseLayer(layer);}else if(this.baseLayer!==this.layers[0]){this.setBaseLayer(this.layers[0]);}}}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){var center=this.getCenter();var newResolution=OpenLayers.Util.getResolutionFromScale(this.getScale(),newBaseLayer.units);if(this.baseLayer!=null&&!this.allOverlays){this.baseLayer.setVisibility(false);}
this.baseLayer=newBaseLayer;this.viewRequestID++;if(!this.allOverlays||this.baseLayer.visibility){this.baseLayer.setVisibility(true);}
if(center!=null){var newZoom=this.getZoomForResolution(newResolution||this.resolution,true);this.setCenter(center,newZoom,false,true);}
this.events.triggerEvent("changebaselayer",{layer:this.baseLayer});}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControls:function(controls,pixels){var pxs=(arguments.length===1)?[]:pixels;for(var i=0,len=controls.length;i<len;i++){var ctrl=controls[i];var px=(pxs[i])?pxs[i]:null;this.addControl(ctrl,px);}},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);if(this.displayProjection&&!control.displayProjection){control.displayProjection=this.displayProjection;}
control.setMap(this);var div=control.draw(px);if(div){if(!control.outsideViewport){div.style.zIndex=this.Z_INDEX_BASE['Control']+
this.controls.length;this.viewPortDiv.appendChild(div);}}
if(control.autoActivate){control.activate();}},getControl:function(id){var returnControl=null;for(var i=0,len=this.controls.length;i<len;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
return returnControl;},removeControl:function(control){if((control)&&(control==this.getControl(control.id))){if(control.div&&(control.div.parentNode==this.viewPortDiv)){this.viewPortDiv.removeChild(control.div);}
OpenLayers.Util.removeItem(this.controls,control);}},addPopup:function(popup,exclusive){if(exclusive){for(var i=this.popups.length-1;i>=0;--i){this.removePopup(this.popups[i]);}}
popup.map=this;this.popups.push(popup);var popupDiv=popup.draw();if(popupDiv){popupDiv.style.zIndex=this.Z_INDEX_BASE['Popup']+
this.popups.length;this.layerContainerDiv.appendChild(popupDiv);}},removePopup:function(popup){OpenLayers.Util.removeItem(this.popups,popup);if(popup.div){try{this.layerContainerDiv.removeChild(popup.div);}
catch(e){}}
popup.map=null;},getSize:function(){var size=null;if(this.size!=null){size=this.size.clone();}
return size;},updateSize:function(){var newSize=this.getCurrentSize();if(newSize&&!isNaN(newSize.h)&&!isNaN(newSize.w)){this.events.clearMouseCache();var oldSize=this.getSize();if(oldSize==null){this.size=oldSize=newSize;}
if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0,len=this.layers.length;i<len;i++){this.layers[i].onMapResize();}
var center=this.getCenter();if(this.baseLayer!=null&&center!=null){var zoom=this.getZoom();this.zoom=null;this.setCenter(center,zoom);}}}},getCurrentSize:function(){var size=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=this.div.offsetWidth;size.h=this.div.offsetHeight;}
if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=parseInt(this.div.style.width);size.h=parseInt(this.div.style.height);}
return size;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCenter();}
if(resolution==null){resolution=this.getResolution();}
if((center!=null)&&(resolution!=null)){var size=this.getSize();var w_deg=size.w*resolution;var h_deg=size.h*resolution;extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);}
return extent;},getCenter:function(){var center=null;if(this.center){center=this.center.clone();}
return center;},getZoom:function(){return this.zoom;},pan:function(dx,dy,options){options=OpenLayers.Util.applyDefaults(options,{animate:true,dragging:false});var centerPx=this.getViewPortPxFromLonLat(this.getCenter());var newCenterPx=centerPx.add(dx,dy);if(!options.dragging||!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);if(options.animate){this.panTo(newCenterLonLat);}else{this.setCenter(newCenterLonLat,null,options.dragging);}}},panTo:function(lonlat){if(this.panMethod&&this.getExtent().scale(this.panRatio).containsLonLat(lonlat)){if(!this.panTween){this.panTween=new OpenLayers.Tween(this.panMethod);}
var center=this.getCenter();if(lonlat.lon==center.lon&&lonlat.lat==center.lat){return;}
var from={lon:center.lon,lat:center.lat};var to={lon:lonlat.lon,lat:lonlat.lat};this.panTween.start(from,to,this.panDuration,{callbacks:{start:OpenLayers.Function.bind(function(lonlat){this.events.triggerEvent("movestart");},this),eachStep:OpenLayers.Function.bind(function(lonlat){lonlat=new OpenLayers.LonLat(lonlat.lon,lonlat.lat);this.moveTo(lonlat,this.zoom,{'dragging':true,'noEvent':true});},this),done:OpenLayers.Function.bind(function(lonlat){lonlat=new OpenLayers.LonLat(lonlat.lon,lonlat.lat);this.moveTo(lonlat,this.zoom,{'noEvent':true});this.events.triggerEvent("moveend");},this)}});}else{this.setCenter(lonlat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){this.moveTo(lonlat,zoom,{'dragging':dragging,'forceZoomChange':forceZoomChange,'caller':'setCenter'});},moveTo:function(lonlat,zoom,options){if(!options){options={};}
if(zoom!=null){zoom=parseFloat(zoom);if(!this.fractionalZoom){zoom=Math.round(zoom);}}
var dragging=options.dragging;var forceZoomChange=options.forceZoomChange;var noEvent=options.noEvent;if(this.panTween&&options.caller=="setCenter"){this.panTween.stop();}
if(!this.center&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();}
if(this.restrictedExtent!=null){if(lonlat==null){lonlat=this.getCenter();}
if(zoom==null){zoom=this.getZoom();}
var resolution=this.getResolutionForZoom(zoom);var extent=this.calculateBounds(lonlat,resolution);if(!this.restrictedExtent.containsBounds(extent)){var maxCenter=this.restrictedExtent.getCenterLonLat();if(extent.getWidth()>this.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.left<this.restrictedExtent.left){lonlat=lonlat.add(this.restrictedExtent.left-
extent.left,0);}else if(extent.right>this.restrictedExtent.right){lonlat=lonlat.add(this.restrictedExtent.right-
extent.right,0);}
if(extent.getHeight()>this.restrictedExtent.getHeight()){lonlat=new OpenLayers.LonLat(lonlat.lon,maxCenter.lat);}else if(extent.bottom<this.restrictedExtent.bottom){lonlat=lonlat.add(0,this.restrictedExtent.bottom-
extent.bottom);}
else if(extent.top>this.restrictedExtent.top){lonlat=lonlat.add(0,this.restrictedExtent.top-
extent.top);}}}
var zoomChanged=forceZoomChange||((this.isValidZoomLevel(zoom))&&(zoom!=this.getZoom()));var centerChanged=(this.isValidLonLat(lonlat))&&(!lonlat.equals(this.center));if(zoomChanged||centerChanged||!dragging){if(!this.dragging&&!noEvent){this.events.triggerEvent("movestart");}
if(centerChanged){if((!zoomChanged)&&(this.center)){this.centerLayerContainer(lonlat);}
this.center=lonlat.clone();}
if((zoomChanged)||(this.layerContainerOrigin==null)){this.layerContainerOrigin=this.center.clone();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";}
if(zoomChanged){this.zoom=zoom;this.resolution=this.getResolutionForZoom(zoom);this.viewRequestID++;}
var bounds=this.getExtent();if(this.baseLayer.visibility){this.baseLayer.moveTo(bounds,zoomChanged,dragging);if(dragging){this.baseLayer.events.triggerEvent("move");}else{this.baseLayer.events.triggerEvent("moveend",{"zoomChanged":zoomChanged});}}
bounds=this.baseLayer.getExtent();for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];if(layer!==this.baseLayer&&!layer.isBaseLayer){var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;if(!inRange){layer.display(false);}
this.events.triggerEvent("changelayer",{layer:layer,property:"visibility"});}
if(inRange&&layer.visibility){layer.moveTo(bounds,zoomChanged,dragging);if(dragging){layer.events.triggerEvent("move");}else{layer.events.triggerEvent("moveend",{"zoomChanged":zoomChanged});}}}}
if(zoomChanged){for(var i=0,len=this.popups.length;i<len;i++){this.popups[i].updatePosition();}}
this.events.triggerEvent("move");if(zoomChanged){this.events.triggerEvent("zoomend");}}
if(!dragging&&!noEvent){this.events.triggerEvent("moveend");}
this.dragging=!!dragging;},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){this.layerContainerDiv.style.left=Math.round(originPx.x-newPx.x)+"px";this.layerContainerDiv.style.top=Math.round(originPx.y-newPx.y)+"px";}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();valid=maxExtent.containsLonLat(lonlat);}
return valid;},getProjection:function(){var projection=this.getProjectionObject();return projection?projection.getCode():null;},getProjectionObject:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
return maxResolution;},getMaxExtent:function(options){var maxExtent=null;if(options&&options.restricted&&this.restrictedExtent){maxExtent=this.restrictedExtent;}else if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}else if(this.allOverlays===true&&this.layers.length>0){resolution=this.layers[0].getResolution();}
return resolution;},getUnits:function(){var units=null;if(this.baseLayer!=null){units=this.baseLayer.units;}
return units;},getScale:function(){var scale=null;if(this.baseLayer!=null){var res=this.getResolution();var units=this.baseLayer.units;scale=OpenLayers.Util.getScaleFromResolution(res,units);}
return scale;},getZoomForExtent:function(bounds,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds,closest);}
return zoom;},getResolutionForZoom:function(zoom){var resolution=null;if(this.baseLayer){resolution=this.baseLayer.getResolutionForZoom(zoom);}
return resolution;},getZoomForResolution:function(resolution,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution,closest);}
return zoom;},zoomTo:function(zoom){if(this.isValidZoomLevel(zoom)){this.setCenter(null,zoom);}},zoomIn:function(){this.zoomTo(this.getZoom()+1);},zoomOut:function(){this.zoomTo(this.getZoom()-1);},zoomToExtent:function(bounds,closest){var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right<bounds.left){bounds.right+=maxExtent.getWidth();}
center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
this.setCenter(center,this.getZoomForExtent(bounds,closest));},zoomToMaxExtent:function(options){var restricted=(options)?options.restricted:true;var maxExtent=this.getMaxExtent({'restricted':restricted});this.zoomToExtent(maxExtent);},zoomToScale:function(scale,closest){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var size=this.getSize();var w_deg=size.w*res;var h_deg=size.h*res;var center=this.getCenter();var extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);this.zoomToExtent(extent,closest);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
return px;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);px.x=Math.round(px.x);px.y=Math.round(px.y);return px;},getGeodesicPixelSize:function(px){var lonlat=px?this.getLonLatFromPixel(px):(this.getCenter()||new OpenLayers.LonLat(0,0));var res=this.getResolution();var left=lonlat.add(-res/2,0);var right=lonlat.add(res/2,0);var bottom=lonlat.add(0,-res/2);var top=lonlat.add(0,res/2);var dest=new OpenLayers.Projection("EPSG:4326");var source=this.getProjectionObject()||dest;if(!source.equals(dest)){left.transform(source,dest);right.transform(source,dest);bottom.transform(source,dest);top.transform(source,dest);}
return new OpenLayers.Size(OpenLayers.Util.distVincenty(left,right),OpenLayers.Util.distVincenty(bottom,top));},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=parseInt(this.layerContainerDiv.style.left);var dY=parseInt(this.layerContainerDiv.style.top);viewPortPx=layerPx.add(dX,dY);}
return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-parseInt(this.layerContainerDiv.style.left);var dY=-parseInt(this.layerContainerDiv.style.top);layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getPixelFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
this.events=new OpenLayers.Events(this,this.icon.imageDiv,null);},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},erase:function(){if(this.icon!=null){this.icon.erase();}},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
this.lonlat=this.map.getLonLatFromLayerPx(px);},isDrawn:function(){var isDrawn=(this.icon&&this.icon.isDrawn());return isDrawn;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
return onScreen;},inflate:function(inflate){if(this.icon){var newSize=new OpenLayers.Size(this.icon.size.w*inflate,this.icon.size.h*inflate);this.icon.setSize(newSize);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){var url=OpenLayers.Util.getImagesLocation()+"marker.png";var size=new OpenLayers.Size(21,25);var calculateOffset=function(size){return new OpenLayers.Pixel(-(size.w/2),-size.h);};return new OpenLayers.Icon(url,size,null,calculateOffset);};OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{contentDisplayClass:"olFramedCloudPopupContent",autoSize:true,panMapIfOutOfView:true,imageSize:new OpenLayers.Size(1276,736),isAlphaImage:false,fixedRelativePosition:false,positionBlocks:{"tl":{'offset':new OpenLayers.Pixel(44,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,18),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-632)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-688)}]},"tr":{'offset':new OpenLayers.Pixel(-45,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,19),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-631)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(0,0,null,null),position:new OpenLayers.Pixel(-215,-687)}]},"bl":{'offset':new OpenLayers.Pixel(45,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},"br":{'offset':new OpenLayers.Pixel(-44,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(1200,660),initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){this.imageSrc=OpenLayers.Util.getImagesLocation()+'cloud-popup-relative.png';OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className=this.contentDisplayClass;},destroy:function(){OpenLayers.Popup.Framed.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Request={DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:true,user:undefined,password:undefined,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},events:new OpenLayers.Events(this,null,["complete","success","failure"]),issue:function(config){var defaultConfig=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});config=OpenLayers.Util.applyDefaults(config,defaultConfig);var request=new OpenLayers.Request.XMLHttpRequest();var url=config.url;if(config.params){var paramString=OpenLayers.Util.getParameterString(config.params);if(paramString.length>0){var separator=(url.indexOf('?')>-1)?'&':'?';url+=separator+paramString;}}
if(config.proxy&&(url.indexOf("http")==0)){if(typeof config.proxy=="function"){url=config.proxy(url);}else{url=config.proxy+encodeURIComponent(url);}}
request.open(config.method,url,config.async,config.user,config.password);for(var header in config.headers){request.setRequestHeader(header,config.headers[header]);}
var events=this.events;var self=this;request.onreadystatechange=function(){if(request.readyState==OpenLayers.Request.XMLHttpRequest.DONE){var proceed=events.triggerEvent("complete",{request:request,config:config,requestUrl:url});if(proceed!==false){self.runCallbacks({request:request,config:config,requestUrl:url});}}};if(config.async===false){request.send(config.data);}else{window.setTimeout(function(){if(request._aborted!==true){request.send(config.data);}},0);}
return request;},runCallbacks:function(options){var request=options.request;var config=options.config;var complete=(config.scope)?OpenLayers.Function.bind(config.callback,config.scope):config.callback;var success;if(config.success){success=(config.scope)?OpenLayers.Function.bind(config.success,config.scope):config.success;}
var failure;if(config.failure){failure=(config.scope)?OpenLayers.Function.bind(config.failure,config.scope):config.failure;}
complete(request);if(!request.status||(request.status>=200&&request.status<300)){this.events.triggerEvent("success",options);if(success){success(request);}}
if(request.status&&(request.status<200||request.status>=300)){this.events.triggerEvent("failure",options);if(failure){failure(request);}}},GET:function(config){config=OpenLayers.Util.extend(config,{method:"GET"});return OpenLayers.Request.issue(config);},POST:function(config){config=OpenLayers.Util.extend(config,{method:"POST"});config.headers=config.headers?config.headers:{};if(!("CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(config.headers))){config.headers["Content-Type"]="application/xml";}
return OpenLayers.Request.issue(config);},PUT:function(config){config=OpenLayers.Util.extend(config,{method:"PUT"});config.headers=config.headers?config.headers:{};if(!("CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(config.headers))){config.headers["Content-Type"]="application/xml";}
return OpenLayers.Request.issue(config);},DELETE:function(config){config=OpenLayers.Util.extend(config,{method:"DELETE"});return OpenLayers.Request.issue(config);},HEAD:function(config){config=OpenLayers.Util.extend(config,{method:"HEAD"});return OpenLayers.Request.issue(config);},OPTIONS:function(config){config=OpenLayers.Util.extend(config,{method:"OPTIONS"});return OpenLayers.Request.issue(config);}};OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,layerAlphaHack:null,isBackBuffer:false,lastRatio:1,isFirstDraw:true,backBufferTile:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.frame=document.createElement('div');this.frame.style.overflow='hidden';this.frame.style.position='absolute';this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();},destroy:function(){if(this.imgDiv!=null){if(this.layerAlphaHack){OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0]);}
OpenLayers.Event.stopObservingElement(this.imgDiv);if(this.imgDiv.parentNode==this.frame){this.frame.removeChild(this.imgDiv);this.imgDiv.map=null;}
this.imgDiv.urls=null;this.imgDiv.src=OpenLayers.Util.getImagesLocation()+"blank.gif";}
this.imgDiv=null;if((this.frame!=null)&&(this.frame.parentNode==this.layer.div)){this.layer.div.removeChild(this.frame);}
this.frame=null;if(this.backBufferTile){this.backBufferTile.destroy();this.backBufferTile=null;}
this.layer.events.unregister("loadend",this,this.resetBackBuffer);OpenLayers.Tile.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Tile.Image(this.layer,this.position,this.bounds,this.url,this.size);}
obj=OpenLayers.Tile.prototype.clone.apply(this,[obj]);obj.imgDiv=null;return obj;},draw:function(){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
var drawTile=OpenLayers.Tile.prototype.draw.apply(this,arguments);if((OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1)||this.layer.singleTile){if(drawTile){if(!this.backBufferTile){this.backBufferTile=this.clone();this.backBufferTile.hide();this.backBufferTile.isBackBuffer=true;this.events.register('loadend',this,this.resetBackBuffer);this.layer.events.register("loadend",this,this.resetBackBuffer);}
this.startTransition();}else{if(this.backBufferTile){this.backBufferTile.clear();}}}else{if(drawTile&&this.isFirstDraw){this.events.register('loadend',this,this.showTile);this.isFirstDraw=false;}}
if(!drawTile){return false;}
if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
return this.renderTile();},resetBackBuffer:function(){this.showTile();if(this.backBufferTile&&(this.isFirstDraw||!this.layer.numLoadingTiles)){this.isFirstDraw=false;var maxExtent=this.layer.maxExtent;var withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));if(withinMaxExtent){this.backBufferTile.position=this.position;this.backBufferTile.bounds=this.bounds;this.backBufferTile.size=this.size;this.backBufferTile.imageSize=this.layer.getImageSize(this.bounds)||this.size;this.backBufferTile.imageOffset=this.layer.imageOffset;this.backBufferTile.resolution=this.layer.getResolution();this.backBufferTile.renderTile();}
this.backBufferTile.hide();}},renderTile:function(){if(this.imgDiv==null){this.initImgDiv();}
this.imgDiv.viewRequestID=this.layer.map.viewRequestID;if(this.layer.async){this.layer.getURLasync(this.bounds,this,"url",this.positionImage);}else{if(this.layer.url instanceof Array){this.imgDiv.urls=this.layer.url.slice();}
this.url=this.layer.getURL(this.bounds);this.positionImage();}
return true;},positionImage:function(){if(this.layer===null){return;}
OpenLayers.Util.modifyDOMElement(this.frame,null,this.position,this.size);var imageSize=this.layer.getImageSize(this.bounds);if(this.layerAlphaHack){OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,null,null,imageSize,this.url);}else{OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,imageSize);this.imgDiv.src=this.url;}},clear:function(){if(this.imgDiv){this.hide();if(OpenLayers.Tile.Image.useBlankTile){this.imgDiv.src=OpenLayers.Util.getImagesLocation()+"blank.gif";}}},initImgDiv:function(){var offset=this.layer.imageOffset;var size=this.layer.getImageSize(this.bounds);if(this.layerAlphaHack){this.imgDiv=OpenLayers.Util.createAlphaImageDiv(null,offset,size,null,"relative",null,null,null,true);}else{this.imgDiv=OpenLayers.Util.createImage(null,offset,size,null,"relative",null,null,true);}
this.imgDiv.className='olTileImage';this.frame.style.zIndex=this.isBackBuffer?0:1;this.frame.appendChild(this.imgDiv);this.layer.div.appendChild(this.frame);if(this.layer.opacity!=null){OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,null,null,null,null,this.layer.opacity);}
this.imgDiv.map=this.layer.map;var onload=function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("loadend");}};if(this.layerAlphaHack){OpenLayers.Event.observe(this.imgDiv.childNodes[0],'load',OpenLayers.Function.bind(onload,this));}else{OpenLayers.Event.observe(this.imgDiv,'load',OpenLayers.Function.bind(onload,this));}
var onerror=function(){if(this.imgDiv._attempts>OpenLayers.IMAGE_RELOAD_ATTEMPTS){onload.call(this);}};OpenLayers.Event.observe(this.imgDiv,"error",OpenLayers.Function.bind(onerror,this));},checkImgURL:function(){if(this.layer){var loaded=this.layerAlphaHack?this.imgDiv.firstChild.src:this.imgDiv.src;if(!OpenLayers.Util.isEquivalentUrl(loaded,this.url)){this.hide();}}},startTransition:function(){if(!this.backBufferTile||!this.backBufferTile.imgDiv){return;}
var ratio=1;if(this.backBufferTile.resolution){ratio=this.backBufferTile.resolution/this.layer.getResolution();}
if(ratio!=this.lastRatio){if(this.layer.transitionEffect=='resize'){var upperLeft=new OpenLayers.LonLat(this.backBufferTile.bounds.left,this.backBufferTile.bounds.top);var size=new OpenLayers.Size(this.backBufferTile.size.w*ratio,this.backBufferTile.size.h*ratio);var px=this.layer.map.getLayerPxFromLonLat(upperLeft);OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,null,px,size);var imageSize=this.backBufferTile.imageSize;imageSize=new OpenLayers.Size(imageSize.w*ratio,imageSize.h*ratio);var imageOffset=this.backBufferTile.imageOffset;if(imageOffset){imageOffset=new OpenLayers.Pixel(imageOffset.x*ratio,imageOffset.y*ratio);}
OpenLayers.Util.modifyDOMElement(this.backBufferTile.imgDiv,null,imageOffset,imageSize);this.backBufferTile.show();}}else{if(this.layer.singleTile){this.backBufferTile.show();}else{this.backBufferTile.hide();}}
this.lastRatio=ratio;},show:function(){this.frame.style.display='';if(OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1){if(navigator.userAgent.toLowerCase().indexOf("gecko")!=-1){this.frame.scrollLeft=this.frame.scrollLeft;}}},hide:function(){this.frame.style.display='none';},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Tile.Image.useBlankTile=(OpenLayers.Util.getBrowserName()=="safari"||OpenLayers.Util.getBrowserName()=="opera");OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{element:null,ovmap:null,size:new OpenLayers.Size(180,90),layers:null,minRectSize:15,minRectDisplayClass:"RectReplacement",minRatio:8,maxRatio:32,mapOptions:null,autoPan:false,handlers:null,resolutionFactor:1,maximized:false,initialize:function(options){this.layers=[];this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,[options]);},destroy:function(){if(!this.mapDiv){return;}
if(this.handlers.click){this.handlers.click.destroy();}
if(this.handlers.drag){this.handlers.drag.destroy();}
this.mapDiv.removeChild(this.extentRectangle);this.extentRectangle=null;if(this.rectEvents){this.rectEvents.destroy();this.rectEvents=null;}
if(this.ovmap){this.ovmap.destroy();this.ovmap=null;}
this.element.removeChild(this.mapDiv);this.mapDiv=null;this.div.removeChild(this.element);this.element=null;if(this.maximizeDiv){OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.div.removeChild(this.maximizeDiv);this.maximizeDiv=null;}
if(this.minimizeDiv){OpenLayers.Event.stopObservingElement(this.minimizeDiv);this.div.removeChild(this.minimizeDiv);this.minimizeDiv=null;}
this.map.events.un({"moveend":this.update,"changebaselayer":this.baseLayerDraw,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!(this.layers.length>0)){if(this.map.baseLayer){var layer=this.map.baseLayer.clone();this.layers=[layer];}else{this.map.events.register("changebaselayer",this,this.baseLayerDraw);return this.div;}}
this.element=document.createElement('div');this.element.className=this.displayClass+'Element';this.element.style.display='none';this.mapDiv=document.createElement('div');this.mapDiv.style.width=this.size.w+'px';this.mapDiv.style.height=this.size.h+'px';this.mapDiv.style.position='relative';this.mapDiv.style.overflow='hidden';this.mapDiv.id=OpenLayers.Util.createUniqueID('overviewMap');this.extentRectangle=document.createElement('div');this.extentRectangle.style.position='absolute';this.extentRectangle.style.zIndex=1000;this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);if(!this.outsideViewport){this.div.className+=" "+this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();var img=imgLocation+'layer-switcher-maximize.png';this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+'MaximizeButton',null,new OpenLayers.Size(18,18),img,'absolute');this.maximizeDiv.style.display='none';this.maximizeDiv.className=this.displayClass+'MaximizeButton';OpenLayers.Event.observe(this.maximizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.maximizeControl,this));this.div.appendChild(this.maximizeDiv);var img=imgLocation+'layer-switcher-minimize.png';this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv('OpenLayers_Control_minimizeDiv',null,new OpenLayers.Size(18,18),img,'absolute');this.minimizeDiv.style.display='none';this.minimizeDiv.className=this.displayClass+'MinimizeButton';OpenLayers.Event.observe(this.minimizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.minimizeControl,this));this.div.appendChild(this.minimizeDiv);var eventsToStop=['dblclick','mousedown'];for(var i=0,len=eventsToStop.length;i<len;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
this.minimizeControl();}else{this.element.style.display='';}
if(this.map.getExtent()){this.update();}
this.map.events.register('moveend',this,this.update);if(this.maximized){this.maximizeControl();}
return this.div;},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);},rectDrag:function(px){var deltaX=this.handlers.drag.last.x-px.x;var deltaY=this.handlers.drag.last.y-px.y;if(deltaX!=0||deltaY!=0){var rectTop=this.rectPxBounds.top;var rectLeft=this.rectPxBounds.left;var rectHeight=Math.abs(this.rectPxBounds.getHeight());var rectWidth=this.rectPxBounds.getWidth();var newTop=Math.max(0,(rectTop-deltaY));newTop=Math.min(newTop,this.ovmap.size.h-this.hComp-rectHeight);var newLeft=Math.max(0,(rectLeft-deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-this.wComp-rectWidth);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+rectHeight,newLeft+rectWidth,newTop));}},mapDivClick:function(evt){var pxCenter=this.rectPxBounds.getCenterPixel();var deltaX=evt.xy.x-pxCenter.x;var deltaY=evt.xy.y-pxCenter.y;var top=this.rectPxBounds.top;var left=this.rectPxBounds.left;var height=Math.abs(this.rectPxBounds.getHeight());var width=this.rectPxBounds.getWidth();var newTop=Math.max(0,(top+deltaY));newTop=Math.min(newTop,this.ovmap.size.h-height);var newLeft=Math.max(0,(left+deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-width);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+height,newLeft+width,newTop));this.updateMapToRect();},maximizeControl:function(e){this.element.style.display='';this.showToggle(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.element.style.display='none';this.showToggle(true);if(e!=null){OpenLayers.Event.stop(e);}},showToggle:function(minimize){this.maximizeDiv.style.display=minimize?'':'none';this.minimizeDiv.style.display=minimize?'none':'';},update:function(){if(this.ovmap==null){this.createMap();}
if(this.autoPan||!this.isSuitableOverview()){this.updateOverview();}
this.updateRectToMap();},isSuitableOverview:function(){var mapExtent=this.map.getExtent();var maxExtent=this.map.maxExtent;var testExtent=new OpenLayers.Bounds(Math.max(mapExtent.left,maxExtent.left),Math.max(mapExtent.bottom,maxExtent.bottom),Math.min(mapExtent.right,maxExtent.right),Math.min(mapExtent.top,maxExtent.top));if(this.ovmap.getProjection()!=this.map.getProjection()){testExtent=testExtent.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject());}
var resRatio=this.ovmap.getResolution()/this.map.getResolution();return((resRatio>this.minRatio)&&(resRatio<=this.maxRatio)&&(this.ovmap.getExtent().containsBounds(testExtent)));},updateOverview:function(){var mapRes=this.map.getResolution();var targetRes=this.ovmap.getResolution();var resRatio=targetRes/mapRes;if(resRatio>this.maxRatio){targetRes=this.minRatio*mapRes;}else if(resRatio<=this.minRatio){targetRes=this.maxRatio*mapRes;}
var center;if(this.ovmap.getProjection()!=this.map.getProjection()){center=this.map.center.clone();center.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject());}else{center=this.map.center;}
this.ovmap.setCenter(center,this.ovmap.getZoomForResolution(targetRes*this.resolutionFactor));this.updateRectToMap();},createMap:function(){var options=OpenLayers.Util.extend({controls:[],maxResolution:'auto',fallThrough:false},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,options);OpenLayers.Event.stopObserving(window,'unload',this.ovmap.unloadDestroy);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-left-width'))+
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-right-width'));this.wComp=(this.wComp)?this.wComp:2;this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-top-width'))+
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-bottom-width'));this.hComp=(this.hComp)?this.hComp:2;this.handlers.drag=new OpenLayers.Handler.Drag(this,{move:this.rectDrag,done:this.updateMapToRect},{map:this.ovmap});this.handlers.click=new OpenLayers.Handler.Click(this,{"click":this.mapDivClick},{"single":true,"double":false,"stopSingle":true,"stopDouble":true,"pixelTolerance":1,map:this.ovmap});this.handlers.click.activate();this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,true);this.rectEvents.register("mouseover",this,function(e){if(!this.handlers.drag.active&&!this.map.dragging){this.handlers.drag.activate();}});this.rectEvents.register("mouseout",this,function(e){if(!this.handlers.drag.dragging){this.handlers.drag.deactivate();}});if(this.ovmap.getProjection()!=this.map.getProjection()){var sourceUnits=this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units;var targetUnits=this.ovmap.getProjectionObject().getUnits()||this.ovmap.units||this.ovmap.baseLayer.units;this.resolutionFactor=sourceUnits&&targetUnits?OpenLayers.INCHES_PER_UNIT[sourceUnits]/OpenLayers.INCHES_PER_UNIT[targetUnits]:1;}},updateRectToMap:function(){var bounds;if(this.ovmap.getProjection()!=this.map.getProjection()){bounds=this.map.getExtent().transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject());}else{bounds=this.map.getExtent();}
var pxBounds=this.getRectBoundsFromMapBounds(bounds);if(pxBounds){this.setRectPxBounds(pxBounds);}},updateMapToRect:function(){var lonLatBounds=this.getMapBoundsFromRectBounds(this.rectPxBounds);if(this.ovmap.getProjection()!=this.map.getProjection()){lonLatBounds=lonLatBounds.transform(this.ovmap.getProjectionObject(),this.map.getProjectionObject());}
this.map.panTo(lonLatBounds.getCenterLonLat());},setRectPxBounds:function(pxBounds){var top=Math.max(pxBounds.top,0);var left=Math.max(pxBounds.left,0);var bottom=Math.min(pxBounds.top+Math.abs(pxBounds.getHeight()),this.ovmap.size.h-this.hComp);var right=Math.min(pxBounds.left+pxBounds.getWidth(),this.ovmap.size.w-this.wComp);var width=Math.max(right-left,0);var height=Math.max(bottom-top,0);if(width<this.minRectSize||height<this.minRectSize){this.extentRectangle.className=this.displayClass+
this.minRectDisplayClass;var rLeft=left+(width/2)-(this.minRectSize/2);var rTop=top+(height/2)-(this.minRectSize/2);this.extentRectangle.style.top=Math.round(rTop)+'px';this.extentRectangle.style.left=Math.round(rLeft)+'px';this.extentRectangle.style.height=this.minRectSize+'px';this.extentRectangle.style.width=this.minRectSize+'px';}else{this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.extentRectangle.style.top=Math.round(top)+'px';this.extentRectangle.style.left=Math.round(left)+'px';this.extentRectangle.style.height=Math.round(height)+'px';this.extentRectangle.style.width=Math.round(width)+'px';}
this.rectPxBounds=new OpenLayers.Bounds(Math.round(left),Math.round(bottom),Math.round(right),Math.round(top));},getRectBoundsFromMapBounds:function(lonLatBounds){var leftBottomLonLat=new OpenLayers.LonLat(lonLatBounds.left,lonLatBounds.bottom);var rightTopLonLat=new OpenLayers.LonLat(lonLatBounds.right,lonLatBounds.top);var leftBottomPx=this.getOverviewPxFromLonLat(leftBottomLonLat);var rightTopPx=this.getOverviewPxFromLonLat(rightTopLonLat);var bounds=null;if(leftBottomPx&&rightTopPx){bounds=new OpenLayers.Bounds(leftBottomPx.x,leftBottomPx.y,rightTopPx.x,rightTopPx.y);}
return bounds;},getMapBoundsFromRectBounds:function(pxBounds){var leftBottomPx=new OpenLayers.Pixel(pxBounds.left,pxBounds.bottom);var rightTopPx=new OpenLayers.Pixel(pxBounds.right,pxBounds.top);var leftBottomLonLat=this.getLonLatFromOverviewPx(leftBottomPx);var rightTopLonLat=this.getLonLatFromOverviewPx(rightTopPx);return new OpenLayers.Bounds(leftBottomLonLat.lon,leftBottomLonLat.lat,rightTopLonLat.lon,rightTopLonLat.lat);},getLonLatFromOverviewPx:function(overviewMapPx){var size=this.ovmap.size;var res=this.ovmap.getResolution();var center=this.ovmap.getExtent().getCenterLonLat();var delta_x=overviewMapPx.x-(size.w/2);var delta_y=overviewMapPx.y-(size.h/2);return new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);},getOverviewPxFromLonLat:function(lonlat){var res=this.ovmap.getResolution();var extent=this.ovmap.getExtent();var px=null;if(extent){px=new OpenLayers.Pixel(Math.round(1/res*(lonlat.lon-extent.left)),Math.round(1/res*(extent.top-lonlat.lat)));}
return px;},CLASS_NAME:'OpenLayers.Control.OverviewMap'});OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:OpenLayers.Popup.AnchoredBubble,popup:null,initialize:function(layer,lonlat,data){this.layer=layer;this.lonlat=lonlat;this.data=(data!=null)?data:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if((this.layer!=null)&&(this.layer.map!=null)){if(this.popup!=null){this.layer.map.removePopup(this.popup);}}
if(this.layer!=null&&this.marker!=null){this.layer.removeMarker(this.marker);}
this.layer=null;this.id=null;this.lonlat=null;this.data=null;if(this.marker!=null){this.destroyMarker(this.marker);this.marker=null;}
if(this.popup!=null){this.destroyPopup(this.popup);this.popup=null;}},onScreen:function(){var onScreen=false;if((this.layer!=null)&&(this.layer.map!=null)){var screenBounds=this.layer.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
return onScreen;},createMarker:function(){if(this.lonlat!=null){this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon);}
return this.marker;},destroyMarker:function(){this.marker.destroy();},createPopup:function(closeBox){if(this.lonlat!=null){var id=this.id+"_popup";var anchor=(this.marker)?this.marker.icon:null;if(!this.popup){this.popup=new this.popupClass(id,this.lonlat,this.data.popupSize,this.data.popupContentHTML,anchor,closeBox);}
if(this.data.overflow!=null){this.popup.contentDiv.style.overflow=this.data.overflow;}
this.popup.feature=this;}
return this.popup;},destroyPopup:function(){if(this.popup){this.popup.feature=null;this.popup.destroy();this.popup=null;}},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.Format.CSWGetDomain.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",csw:"http://www.opengis.net/cat/csw/2.0.2"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",PropertyName:null,ParameterName:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var obj={};this.readNode(data,obj);return obj;},readers:{"csw":{"GetDomainResponse":function(node,obj){this.readChildNodes(node,obj);},"DomainValues":function(node,obj){if(!(obj.DomainValues instanceof Array)){obj.DomainValues=[];}
var attrs=node.attributes;var domainValue={};for(var i=0,len=attrs.length;i<len;++i){domainValue[attrs[i].name]=attrs[i].nodeValue;}
this.readChildNodes(node,domainValue);obj.DomainValues.push(domainValue);},"PropertyName":function(node,obj){obj.PropertyName=this.getChildValue(node);},"ParameterName":function(node,obj){obj.ParameterName=this.getChildValue(node);},"ListOfValues":function(node,obj){if(!(obj.ListOfValues instanceof Array)){obj.ListOfValues=[];}
this.readChildNodes(node,obj.ListOfValues);},"Value":function(node,obj){var attrs=node.attributes;var value={}
for(var i=0,len=attrs.length;i<len;++i){value[attrs[i].name]=attrs[i].nodeValue;}
value.value=this.getChildValue(node);obj.push({Value:value});},"ConceptualScheme":function(node,obj){obj.ConceptualScheme={};this.readChildNodes(node,obj.ConceptualScheme);},"Name":function(node,obj){obj.Name=this.getChildValue(node);},"Document":function(node,obj){obj.Document=this.getChildValue(node);},"Authority":function(node,obj){obj.Authority=this.getChildValue(node);},"RangeOfValues":function(node,obj){obj.RangeOfValues={};this.readChildNodes(node,obj.RangeOfValues);},"MinValue":function(node,obj){var attrs=node.attributes;var value={}
for(var i=0,len=attrs.length;i<len;++i){value[attrs[i].name]=attrs[i].nodeValue;}
value.value=this.getChildValue(node);obj.MinValue=value;},"MaxValue":function(node,obj){var attrs=node.attributes;var value={}
for(var i=0,len=attrs.length;i<len;++i){value[attrs[i].name]=attrs[i].nodeValue;}
value.value=this.getChildValue(node);obj.MaxValue=value;}}},write:function(options){var node=this.writeNode("csw:GetDomain",options);return OpenLayers.Format.XML.prototype.write.apply(this,[node]);},writers:{"csw":{"GetDomain":function(options){var node=this.createElementNSPlus("csw:GetDomain",{attributes:{service:"CSW",version:this.version}});if(options.PropertyName||this.PropertyName){this.writeNode("csw:PropertyName",options.PropertyName||this.PropertyName,node);}else if(options.ParameterName||this.ParameterName){this.writeNode("csw:ParameterName",options.ParameterName||this.ParameterName,node);}
this.readChildNodes(node,options);return node;},"PropertyName":function(value){var node=this.createElementNSPlus("csw:PropertyName",{value:value});return node;},"ParameterName":function(value){var node=this.createElementNSPlus("csw:ParameterName",{value:value});return node;}}},CLASS_NAME:"OpenLayers.Format.CSWGetDomain.v2_0_2"});OpenLayers.Format.Context=OpenLayers.Class({version:null,layerOptions:null,layerParams:null,parser:null,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;},read:function(data,options){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version;if(!version){version=root.getAttribute("version");}
var parser=this.getParser(version);var context=parser.read(data,options);var map;if(options&&options.map){this.context=context;if(options.map instanceof OpenLayers.Map){map=this.mergeContextToMap(context,options.map);}else{var mapOptions=options.map;if(OpenLayers.Util.isElement(mapOptions)||typeof mapOptions=="string"){mapOptions={div:mapOptions};}
map=this.contextToMap(context,mapOptions);}}else{map=context;}
return map;},getLayerFromContext:function(layerContext){var i,len;var options={queryable:layerContext.queryable,visibility:layerContext.visibility,maxExtent:layerContext.maxExtent,metadata:OpenLayers.Util.applyDefaults(layerContext.metadata,{styles:layerContext.styles}),numZoomLevels:layerContext.numZoomLevels,units:layerContext.units,isBaseLayer:layerContext.isBaseLayer,opacity:layerContext.opacity,displayInLayerSwitcher:layerContext.displayInLayerSwitcher,singleTile:layerContext.singleTile,tileSize:(layerContext.tileSize)?new OpenLayers.Size(layerContext.tileSize.width,layerContext.tileSize.height):undefined,minScale:layerContext.minScale||layerContext.maxScaleDenominator,maxScale:layerContext.maxScale||layerContext.minScaleDenominator};if(this.layerOptions){OpenLayers.Util.applyDefaults(options,this.layerOptions);}
var params={layers:layerContext.name,transparent:layerContext.transparent,version:layerContext.version};if(layerContext.formats&&layerContext.formats.length>0){params.format=layerContext.formats[0].value;for(i=0,len=layerContext.formats.length;i<len;i++){var format=layerContext.formats[i];if(format.current==true){params.format=format.value;break;}}}
if(layerContext.styles&&layerContext.styles.length>0){for(i=0,len=layerContext.styles.length;i<len;i++){var style=layerContext.styles[i];if(style.current==true){if(style.href){params.sld=style.href;}else if(style.body){params.sld_body=style.body;}else{params.styles=style.name;}
break;}}}
if(this.layerParams){OpenLayers.Util.applyDefaults(params,this.layerParams);}
var layer=null;var service=layerContext.service;if(service==OpenLayers.Format.Context.serviceTypes.WFS){options.strategies=[new OpenLayers.Strategy.BBOX()];options.protocol=new OpenLayers.Protocol.WFS({url:layerContext.url,featurePrefix:layerContext.name.split(":")[0],featureType:layerContext.name.split(":").pop()});layer=new OpenLayers.Layer.Vector(layerContext.title||layerContext.name,options);}else if(service==OpenLayers.Format.Context.serviceTypes.KML){options.strategies=[new OpenLayers.Strategy.Fixed()];options.protocol=new OpenLayers.Protocol.HTTP({url:layerContext.url,format:new OpenLayers.Format.KML()});layer=new OpenLayers.Layer.Vector(layerContext.title||layerContext.name,options);}else if(service==OpenLayers.Format.Context.serviceTypes.GML){options.strategies=[new OpenLayers.Strategy.Fixed()];options.protocol=new OpenLayers.Protocol.HTTP({url:layerContext.url,format:new OpenLayers.Format.GML()});layer=new OpenLayers.Layer.Vector(layerContext.title||layerContext.name,options);}else if(layerContext.features){layer=new OpenLayers.Layer.Vector(layerContext.title||layerContext.name,options);layer.addFeatures(layerContext.features);}else if(layerContext.categoryLayer!==true){layer=new OpenLayers.Layer.WMS(layerContext.title||layerContext.name,layerContext.url,params,options);}
return layer;},getLayersFromContext:function(layersContext){var layers=[];for(var i=0,len=layersContext.length;i<len;i++){var layer=this.getLayerFromContext(layersContext[i]);if(layer!==null){layers.push(layer);}}
return layers;},contextToMap:function(context,options){options=OpenLayers.Util.applyDefaults({maxExtent:context.maxExtent,projection:context.projection},options);var map=new OpenLayers.Map(options);map.addLayers(this.getLayersFromContext(context.layersContext));map.setCenter(context.bounds.getCenterLonLat(),map.getZoomForExtent(context.bounds,true));return map;},mergeContextToMap:function(context,map){map.addLayers(this.getLayersFromContext(context.layersContext));return map;},write:function(obj,options){obj=this.toContext(obj);var version=options&&options.version;var parser=this.getParser(version);var context=parser.write(obj,options);return context;},CLASS_NAME:"OpenLayers.Format.Context"});OpenLayers.Format.Context.serviceTypes={"WMS":"urn:ogc:serviceType:WMS","WFS":"urn:ogc:serviceType:WFS","WCS":"urn:ogc:serviceType:WCS","GML":"urn:ogc:serviceType:GML","SLD":"urn:ogc:serviceType:SLD","FES":"urn:ogc:serviceType:FES","KML":"urn:ogc:serviceType:KML"};if(!OpenLayers.Format.OWSCommon){OpenLayers.Format.OWSCommon={};}
OpenLayers.Format.OWSCommon.v1=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},readers:{"ows":{"ServiceIdentification":function(node,obj){obj.serviceIdentification={};this.readChildNodes(node,obj.serviceIdentification);},"Title":function(node,obj){obj.title=this.getChildValue(node);},"Abstract":function(node,serviceIdentification){serviceIdentification["abstract"]=this.getChildValue(node);},"Keywords":function(node,serviceIdentification){serviceIdentification.keywords={};this.readChildNodes(node,serviceIdentification.keywords);},"Keyword":function(node,keywords){keywords[this.getChildValue(node)]=true;},"ServiceType":function(node,serviceIdentification){serviceIdentification.serviceType={codeSpace:node.getAttribute('codeSpace'),value:this.getChildValue(node)};},"ServiceTypeVersion":function(node,serviceIdentification){serviceIdentification.serviceTypeVersion=this.getChildValue(node);},"Fees":function(node,serviceIdentification){serviceIdentification.fees=this.getChildValue(node);},"AccessConstraints":function(node,serviceIdentification){serviceIdentification.accessConstraints=this.getChildValue(node);},"ServiceProvider":function(node,obj){obj.serviceProvider={};this.readChildNodes(node,obj.serviceProvider);},"ProviderName":function(node,serviceProvider){serviceProvider.providerName=this.getChildValue(node);},"ProviderSite":function(node,serviceProvider){serviceProvider.providerSite=this.getAttributeNS(node,this.namespaces.xlink,"href");},"ServiceContact":function(node,serviceProvider){serviceProvider.serviceContact={};this.readChildNodes(node,serviceProvider.serviceContact);},"IndividualName":function(node,serviceContact){serviceContact.individualName=this.getChildValue(node);},"PositionName":function(node,serviceContact){serviceContact.positionName=this.getChildValue(node);},"ContactInfo":function(node,serviceContact){serviceContact.contactInfo={};this.readChildNodes(node,serviceContact.contactInfo);},"Phone":function(node,contactInfo){contactInfo.phone={};this.readChildNodes(node,contactInfo.phone);},"Voice":function(node,phone){phone.voice=this.getChildValue(node);},"Address":function(node,contactInfo){contactInfo.address={};this.readChildNodes(node,contactInfo.address);},"DeliveryPoint":function(node,address){address.deliveryPoint=this.getChildValue(node);},"City":function(node,address){address.city=this.getChildValue(node);},"AdministrativeArea":function(node,address){address.administrativeArea=this.getChildValue(node);},"PostalCode":function(node,address){address.postalCode=this.getChildValue(node);},"Country":function(node,address){address.country=this.getChildValue(node);},"ElectronicMailAddress":function(node,address){address.electronicMailAddress=this.getChildValue(node);},"Role":function(node,serviceContact){serviceContact.role=this.getChildValue(node);},"OperationsMetadata":function(node,obj){obj.operationsMetadata={};this.readChildNodes(node,obj.operationsMetadata);},"Operation":function(node,operationsMetadata){var name=node.getAttribute("name");operationsMetadata[name]={};this.readChildNodes(node,operationsMetadata[name]);},"DCP":function(node,operation){operation.dcp={};this.readChildNodes(node,operation.dcp);},"HTTP":function(node,dcp){dcp.http={};this.readChildNodes(node,dcp.http);},"Get":function(node,http){http.get=this.getAttributeNS(node,this.namespaces.xlink,"href");},"Post":function(node,http){http.post=this.getAttributeNS(node,this.namespaces.xlink,"href");},"Parameter":function(node,operation){if(!operation.parameters){operation.parameters={};}
var name=node.getAttribute("name");operation.parameters[name]={};this.readChildNodes(node,operation.parameters[name]);},"Value":function(node,allowedValues){allowedValues[this.getChildValue(node)]=true;},"OutputFormat":function(node,obj){obj.formats.push({value:this.getChildValue(node)});this.readChildNodes(node,obj);},"WGS84BoundingBox":function(node,obj){var boundingBox={};boundingBox.crs=node.getAttribute("crs");if(obj.BoundingBox){obj.BoundingBox.push(boundingBox);}else{obj.projection=boundingBox.crs;boundingBox=obj;}
this.readChildNodes(node,boundingBox);},"BoundingBox":function(node,obj){this.readers['ows']['WGS84BoundingBox'].apply(this,[node,obj]);},"LowerCorner":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");str=str.replace(this.regExes.trimComma,",");var pointList=str.split(this.regExes.splitSpace);obj.left=pointList[0];obj.bottom=pointList[1];},"UpperCorner":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");str=str.replace(this.regExes.trimComma,",");var pointList=str.split(this.regExes.splitSpace);obj.right=pointList[0];obj.top=pointList[1];obj.bounds=new OpenLayers.Bounds(obj.left,obj.bottom,obj.right,obj.top);delete obj.left;delete obj.bottom;delete obj.right;delete obj.top;}}},writers:{"ows":{"BoundingBox":function(options){var node=this.createElementNSPlus("ows:BoundingBox",{attributes:{crs:options.projection}});this.writeNode("ows:LowerCorner",options,node);this.writeNode("ows:UpperCorner",options,node);return node;},"LowerCorner":function(options){var node=this.createElementNSPlus("ows:LowerCorner",{value:options.bounds.left+" "+options.bounds.bottom});return node;},"UpperCorner":function(options){var node=this.createElementNSPlus("ows:UpperCorner",{value:options.bounds.right+" "+options.bounds.top});return node;},"Title":function(title){var node=this.createElementNSPlus("ows:Title",{value:title});return node;},"OutputFormat":function(format){var node=this.createElementNSPlus("ows:OutputFormat",{value:format});return node;}}},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1"});OpenLayers.Format.SOSCapabilities=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.0.0",version:null,parser:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version||root.getAttribute("version")||this.defaultVersion;if(!this.parser||this.parser.version!==version){var constr=OpenLayers.Format.SOSCapabilities["v"+version.replace(/\./g,"_")];if(!constr){throw"Can't find a SOS capabilities parser for version "+version;}
var parser=new constr(this.options);}
var capabilities=parser.read(data);capabilities.version=version;return capabilities;},CLASS_NAME:"OpenLayers.Format.SOSCapabilities"});OpenLayers.Format.WFSCapabilities=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.1.0",version:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version;if(!version){version=root.getAttribute("version");if(!version){version=this.defaultVersion;}}
var constr=OpenLayers.Format.WFSCapabilities["v"+version.replace(/\./g,"_")];if(!constr){throw"Can't find a WFS capabilities parser for version "+version;}
var parser=new constr(this.options);var capabilities=parser.read(data);capabilities.version=version;return capabilities;},CLASS_NAME:"OpenLayers.Format.WFSCapabilities"});OpenLayers.Format.WFSDescribeFeatureType=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xsd:"http://www.w3.org/2001/XMLSchema"},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},readers:{"xsd":{"schema":function(node,obj){var complexTypes=[];var customTypes={};var schema={complexTypes:complexTypes,customTypes:customTypes};this.readChildNodes(node,schema);var attributes=node.attributes;var attr,name;for(var i=0,len=attributes.length;i<len;++i){attr=attributes[i];name=attr.name;if(name.indexOf("xmlns")==0){this.setNamespace(name.split(":")[1]||"",attr.value);}else{obj[name]=attr.value;}}
obj.featureTypes=complexTypes;obj.targetPrefix=this.namespaceAlias[obj.targetNamespace];var complexType,customType;for(var i=0,len=complexTypes.length;i<len;++i){complexType=complexTypes[i];customType=customTypes[complexType.typeName];if(customTypes[complexType.typeName]){complexType.typeName=customType.name;}}},"complexType":function(node,obj){var complexType={"typeName":node.getAttribute("name")};this.readChildNodes(node,complexType);obj.complexTypes.push(complexType);},"complexContent":function(node,obj){this.readChildNodes(node,obj);},"extension":function(node,obj){this.readChildNodes(node,obj);},"sequence":function(node,obj){var sequence={elements:[]};this.readChildNodes(node,sequence);obj.properties=sequence.elements;},"element":function(node,obj){if(obj.elements){var element={};var attributes=node.attributes;var attr;for(var i=0,len=attributes.length;i<len;++i){attr=attributes[i];element[attr.name]=attr.value;}
var type=element.type;if(!type){type={};this.readChildNodes(node,type);element.restriction=type;element.type=type.base;}
var fullType=type.base||type;element.localType=fullType.split(":").pop();obj.elements.push(element);}
if(obj.complexTypes){var type=node.getAttribute("type");var localType=type.split(":").pop();obj.customTypes[localType]={"name":node.getAttribute("name"),"type":type};}},"simpleType":function(node,obj){this.readChildNodes(node,obj);},"restriction":function(node,obj){obj.base=node.getAttribute("base");this.readRestriction(node,obj);}}},readRestriction:function(node,obj){var children=node.childNodes;var child,nodeName,value;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){nodeName=child.nodeName.split(":").pop();value=child.getAttribute("value");if(!obj[nodeName]){obj[nodeName]=value;}else{if(typeof obj[nodeName]=="string"){obj[nodeName]=[obj[nodeName]];}
obj[nodeName].push(value);}}}},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var schema={};this.readNode(data,schema);return schema;},CLASS_NAME:"OpenLayers.Format.WFSDescribeFeatureType"});OpenLayers.Format.WFST.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs",gml:"http://www.opengis.net/gml",ogc:"http://www.opengis.net/ogc"},defaultPrefix:"wfs",version:null,schemaLocations:null,srsName:null,extractAttributes:true,xy:true,stateName:null,initialize:function(options){this.stateName={};this.stateName[OpenLayers.State.INSERT]="wfs:Insert";this.stateName[OpenLayers.State.UPDATE]="wfs:Update";this.stateName[OpenLayers.State.DELETE]="wfs:Delete";OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},getSrsName:function(feature,options){var srsName=options&&options.srsName;if(!srsName){if(feature&&feature.layer){srsName=feature.layer.projection.getCode();}else{srsName=this.srsName;}}
return srsName;},read:function(data,options){options=options||{};OpenLayers.Util.applyDefaults(options,{output:"features"});if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var obj={};if(data){this.readNode(data,obj);}
if(obj.features&&options.output==="features"){obj=obj.features;}
return obj;},readers:{"wfs":{"FeatureCollection":function(node,obj){obj.features=[];this.readChildNodes(node,obj);}}},write:function(features){var node=this.writeNode("wfs:Transaction",features);var value=this.schemaLocationAttr();if(value){this.setAttributeNS(node,this.namespaces["xsi"],"xsi:schemaLocation",value)}
return OpenLayers.Format.XML.prototype.write.apply(this,[node]);},writers:{"wfs":{"GetFeature":function(options){var node=this.createElementNSPlus("wfs:GetFeature",{attributes:{service:"WFS",version:this.version,outputFormat:options&&options.outputFormat,maxFeatures:options&&options.maxFeatures,"xsi:schemaLocation":this.schemaLocationAttr(options)}});if(typeof this.featureType=="string"){this.writeNode("Query",options,node);}else{for(var i=0,len=this.featureType.length;i<len;i++){options.featureType=this.featureType[i];this.writeNode("Query",options,node);}}
return node;},"Transaction":function(features){var node=this.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version}});if(features){var name,feature;for(var i=0,len=features.length;i<len;++i){feature=features[i];name=this.stateName[feature.state];if(name){this.writeNode(name,feature,node);}}}
return node;},"Insert":function(feature){var node=this.createElementNSPlus("wfs:Insert");this.srsName=this.getSrsName(feature);this.writeNode("feature:_typeName",feature,node);return node;},"Update":function(feature){var node=this.createElementNSPlus("wfs:Update",{attributes:{typeName:(this.featureNS?this.featurePrefix+":":"")+
this.featureType}});if(this.featureNS){node.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);}
if(this.geometryName!==null){this.writeNode("Property",{name:this.geometryName,value:feature},node);}
for(var key in feature.attributes){if(feature.attributes[key]!==undefined){this.writeNode("Property",{name:key,value:feature.attributes[key]},node);}}
this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[feature.fid]}),node);return node;},"Property":function(obj){var node=this.createElementNSPlus("wfs:Property");this.writeNode("Name",obj.name,node);if(obj.value!==null){this.writeNode("Value",obj.value,node);}
return node;},"Name":function(name){return this.createElementNSPlus("wfs:Name",{value:name});},"Value":function(obj){var node;if(obj instanceof OpenLayers.Feature.Vector){node=this.createElementNSPlus("wfs:Value");this.srsName=this.getSrsName(obj);var geom=this.writeNode("feature:_geometry",obj.geometry).firstChild;node.appendChild(geom);}else{node=this.createElementNSPlus("wfs:Value",{value:obj});}
return node;},"Delete":function(feature){var node=this.createElementNSPlus("wfs:Delete",{attributes:{typeName:(this.featureNS?this.featurePrefix+":":"")+
this.featureType}});if(this.featureNS){node.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);}
this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[feature.fid]}),node);return node;}}},schemaLocationAttr:function(options){options=OpenLayers.Util.extend({featurePrefix:this.featurePrefix,schema:this.schema},options);var schemaLocations=OpenLayers.Util.extend({},this.schemaLocations);if(options.schema){schemaLocations[options.featurePrefix]=options.schema;}
var parts=[];var uri;for(var key in schemaLocations){uri=this.namespaces[key];if(uri){parts.push(uri+" "+schemaLocations[key]);}}
var value=parts.join(" ")||undefined;return value;},setFilterProperty:function(filter){if(filter.filters){for(var i=0,len=filter.filters.length;i<len;++i){this.setFilterProperty(filter.filters[i]);}}else{if(filter instanceof OpenLayers.Filter.Spatial){filter.property=this.geometryName;}}},CLASS_NAME:"OpenLayers.Format.WFST.v1"});OpenLayers.Format.WMSCapabilities=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.1.1",version:null,parser:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version||root.getAttribute("version")||this.defaultVersion;if(!this.parser||this.parser.version!==version){var constr=OpenLayers.Format.WMSCapabilities["v"+version.replace(/\./g,"_")];if(!constr){throw"Can't find a WMS capabilities parser for version "+version;}
this.parser=new constr(this.options);}
var capabilities=this.parser.read(data);capabilities.version=version;return capabilities;},CLASS_NAME:"OpenLayers.Format.WMSCapabilities"});OpenLayers.Format.WMSDescribeLayer=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.1.1",version:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version;if(!version){version=root.getAttribute("version");if(!version){version=this.defaultVersion;}}
if(version=="1.1.1"||version=="1.1.0"){version="1.1";}
var constructor=OpenLayers.Format.WMSDescribeLayer["v"+version.replace(/\./g,"_")];if(!constructor){throw"Can't find a WMS DescribeLayer parser for version "+
version;}
var parser=new constructor(this.options);var describelayer=parser.read(data);describelayer.version=version;return describelayer;},CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer"});OpenLayers.Format.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Format.XML,{layerIdentifier:'_layer',featureIdentifier:'_feature',regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},gmlFormat:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,arguments);OpenLayers.Util.extend(this,options);this.options=options;},read:function(data){var result;if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;if(root){var scope=this;var read=this["read_"+root.nodeName];if(read){result=read.call(this,root);}else{result=new OpenLayers.Format.GML((this.options?this.options:{})).read(data);}}else{result=data;}
return result;},read_msGMLOutput:function(data){var response=[];var layerNodes=this.getSiblingNodesByTagCriteria(data,this.layerIdentifier);if(layerNodes){for(var i=0,len=layerNodes.length;i<len;++i){var node=layerNodes[i];var layerName=node.nodeName;if(node.prefix){layerName=layerName.split(':')[1];}
var layerName=layerName.replace(this.layerIdentifier,'');var featureNodes=this.getSiblingNodesByTagCriteria(node,this.featureIdentifier);if(featureNodes){for(var j=0;j<featureNodes.length;j++){var featureNode=featureNodes[j];var geomInfo=this.parseGeometry(featureNode);var attributes=this.parseAttributes(featureNode);var feature=new OpenLayers.Feature.Vector(geomInfo.geometry,attributes,null);feature.bounds=geomInfo.bounds;feature.type=layerName;response.push(feature);}}}}
return response;},read_FeatureInfoResponse:function(data){var response=[];var featureNodes=this.getElementsByTagNameNS(data,'*','FIELDS');for(var i=0,len=featureNodes.length;i<len;i++){var featureNode=featureNodes[i];var geom=null;var attributes={};for(var j=0,jlen=featureNode.attributes.length;j<jlen;j++){var attribute=featureNode.attributes[j];attributes[attribute.nodeName]=attribute.nodeValue;}
response.push(new OpenLayers.Feature.Vector(geom,attributes,null));}
return response;},getSiblingNodesByTagCriteria:function(node,criteria){var nodes=[];var children,tagName,n,matchNodes,child;if(node&&node.hasChildNodes()){children=node.childNodes;n=children.length;for(var k=0;k<n;k++){child=children[k];while(child&&child.nodeType!=1){child=child.nextSibling;k++;}
tagName=(child?child.nodeName:'');if(tagName.length>0&&tagName.indexOf(criteria)>-1){nodes.push(child);}else{matchNodes=this.getSiblingNodesByTagCriteria(child,criteria);if(matchNodes.length>0){(nodes.length==0)?nodes=matchNodes:nodes.push(matchNodes);}}}}
return nodes;},parseAttributes:function(node){var attributes={};if(node.nodeType==1){var children=node.childNodes;var n=children.length;for(var i=0;i<n;++i){var child=children[i];if(child.nodeType==1){var grandchildren=child.childNodes;if(grandchildren.length==1){var grandchild=grandchildren[0];if(grandchild.nodeType==3||grandchild.nodeType==4){var name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var value=grandchild.nodeValue.replace(this.regExes.trimSpace,"");attributes[name]=value;}}}}}
return attributes;},parseGeometry:function(node){if(!this.gmlFormat){this.gmlFormat=new OpenLayers.Format.GML();}
var feature=this.gmlFormat.parseFeature(node);var geometry,bounds=null;if(feature){geometry=feature.geometry&&feature.geometry.clone();bounds=feature.bounds&&feature.bounds.clone();feature.destroy();}
return{geometry:geometry,bounds:bounds};},CLASS_NAME:"OpenLayers.Format.WMSGetFeatureInfo"});OpenLayers.Format.WMTSCapabilities=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.0.0",version:null,parser:null,yx:{"urn:ogc:def:crs:EPSG::4326":true},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version||root.getAttribute("version")||this.defaultVersion;if(!this.parser||this.parser.version!==version){var constr=OpenLayers.Format.WMTSCapabilities["v"+version.replace(/\./g,"_")];if(!constr){throw new Error("Can't find a WMTS capabilities parser for version "+version);}
this.parser=new constr(this.options);}
return this.parser.read(data);},createLayer:function(capabilities,config){var layer;var required={layer:true,matrixSet:true};for(var prop in required){if(!(prop in config)){throw new Error("Missing property '"+prop+"' in layer configuration.");}}
var contents=capabilities.contents;var matrixSet=contents.tileMatrixSets[config.matrixSet];var layers=contents.layers;var layerDef;for(var i=0,ii=contents.layers.length;i<ii;++i){if(contents.layers[i].identifier===config.layer){layerDef=contents.layers[i];break;}}
if(layerDef&&matrixSet){var style;for(var i=0,ii=layerDef.styles.length;i<ii;++i){style=layerDef.styles[i];if(style.isDefault){break;}}
layer=new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(config,{url:capabilities.operationsMetadata.GetTile.dcp.http.get,name:layerDef.title,style:style,matrixIds:matrixSet.matrixIds}));}
return layer;},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,stopSingle:false,stopDouble:false,timerId:null,down:null,rightclickTimerId:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(this.pixelTolerance!=null){this.mousedown=function(evt){this.down=evt.xy;return true;};}},mousedown:null,mouseup:function(evt){var propagate=true;if(this.checkModifiers(evt)&&this.control.handleRightClicks&&OpenLayers.Event.isRightClick(evt)){propagate=this.rightclick(evt);}
return propagate;},rightclick:function(evt){if(this.passesTolerance(evt)){if(this.rightclickTimerId!=null){this.clearTimer();this.callback('dblrightclick',[evt]);return!this.stopDouble;}else{var clickEvent=this['double']?OpenLayers.Util.extend({},evt):this.callback('rightclick',[evt]);var delayedRightCall=OpenLayers.Function.bind(this.delayedRightCall,this,clickEvent);this.rightclickTimerId=window.setTimeout(delayedRightCall,this.delay);}}
return!this.stopSingle;},delayedRightCall:function(evt){this.rightclickTimerId=null;if(evt){this.callback('rightclick',[evt]);}
return!this.stopSingle;},dblclick:function(evt){if(this.passesTolerance(evt)){if(this["double"]){this.callback('dblclick',[evt]);}
this.clearTimer();}
return!this.stopDouble;},click:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){this.clearTimer();}else{var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,clickEvent),this.delay);}}
return!this.stopSingle;},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down){var dpx=Math.sqrt(Math.pow(this.down.x-evt.xy.x,2)+
Math.pow(this.down.y-evt.xy.y,2));if(dpx>this.pixelTolerance){passes=false;}}
return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}
if(this.rightclickTimerId!=null){window.clearTimeout(this.rightclickTimerId);this.rightclickTimerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback('click',[evt]);}},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();this.down=null;deactivated=true;}
return deactivated;},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,stopDown:true,dragging:false,last:null,start:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:false,documentEvents:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&OpenLayers.Event.isLeftClick(evt)){this.started=true;this.start=evt.xy;this.last=evt.xy;OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown");this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.stop(evt);if(!this.oldOnselectstart){this.oldOnselectstart=(document.onselectstart)?document.onselectstart:OpenLayers.Function.True;}
document.onselectstart=OpenLayers.Function.False;propagate=!this.stopDown;}else{this.started=false;this.start=null;this.last=null;}
return propagate;},mousemove:function(evt){if(this.started&&!this.timeoutId&&(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y)){if(this.documentDrag===true&&this.documentEvents){if(evt.element===document){this.adjustXY(evt);this.setEvent(evt);}else{this.destroyDocumentEvents();}}
if(this.interval>0){this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);}
this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=OpenLayers.Function.False;}
this.last=this.evt.xy;}
return true;},removeTimeout:function(){this.timeoutId=null;},mouseup:function(evt){if(this.started){if(this.documentDrag===true&&this.documentEvents){this.adjustXY(evt);this.destroyDocumentEvents();}
var dragged=(this.start!=this.last);this.started=false;this.dragging=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(evt);this.callback("up",[evt.xy]);if(dragged){this.callback("done",[evt.xy]);}
document.onselectstart=this.oldOnselectstart;}
return true;},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.div)){if(this.documentDrag===true){this.documentEvents=new OpenLayers.Events(this,document,null,null,{includeXY:true});this.documentEvents.on({mousemove:this.mousemove,mouseup:this.mouseup});OpenLayers.Element.addClass(document.body,"olDragDown");}else{var dragged=(this.start!=this.last);this.started=false;this.dragging=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(evt);this.callback("out",[]);if(dragged){this.callback("done",[evt.xy]);}
if(document.onselectstart){document.onselectstart=this.oldOnselectstart;}}}
return true;},click:function(evt){return(this.start==this.last);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;activated=true;}
return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");}
return deactivated;},adjustXY:function(evt){var pos=OpenLayers.Util.pagePosition(this.map.div);evt.xy.x-=pos[0];evt.xy.y-=pos[1];},destroyDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents.destroy();this.documentEvents=null;},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{'click':{'in':'click','out':'clickout'},'mousemove':{'in':'over','out':'out'},'dblclick':{'in':'dblclick','out':null},'mousedown':{'in':null,'out':null},'mouseup':{'in':null,'out':null}},feature:null,lastFeature:null,down:null,up:null,clickTolerance:4,geometryTypes:null,stopClick:true,stopDown:true,stopUp:false,initialize:function(control,layer,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,[control,callbacks,options]);this.layer=layer;},mousedown:function(evt){this.down=evt.xy;return this.handle(evt)?!this.stopDown:true;},mouseup:function(evt){this.up=evt.xy;return this.handle(evt)?!this.stopUp:true;},click:function(evt){return this.handle(evt)?!this.stopClick:true;},mousemove:function(evt){if(!this.callbacks['over']&&!this.callbacks['out']){return true;}
this.handle(evt);return true;},dblclick:function(evt){return!this.handle(evt);},geometryTypeMatches:function(feature){return this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1;},handle:function(evt){if(this.feature&&!this.feature.layer){this.feature=null;}
var type=evt.type;var handled=false;var previouslyIn=!!(this.feature);var click=(type=="click"||type=="dblclick");this.feature=this.layer.getFeatureFromEvent(evt);if(this.feature&&!this.feature.layer){this.feature=null;}
if(this.lastFeature&&!this.lastFeature.layer){this.lastFeature=null;}
if(this.feature){var inNew=(this.feature!=this.lastFeature);if(this.geometryTypeMatches(this.feature)){if(previouslyIn&&inNew){if(this.lastFeature){this.triggerCallback(type,'out',[this.lastFeature]);}
this.triggerCallback(type,'in',[this.feature]);}else if(!previouslyIn||click){this.triggerCallback(type,'in',[this.feature]);}
this.lastFeature=this.feature;handled=true;}else{if(this.lastFeature&&(previouslyIn&&inNew||click)){this.triggerCallback(type,'out',[this.lastFeature]);}
this.feature=null;}}else{if(this.lastFeature&&(previouslyIn||click)){this.triggerCallback(type,'out',[this.lastFeature]);}}
return handled;},triggerCallback:function(type,mode,args){var key=this.EVENTMAP[type][mode];if(key){if(type=='click'&&this.up&&this.down){var dpx=Math.sqrt(Math.pow(this.up.x-this.down.x,2)+
Math.pow(this.up.y-this.down.y,2));if(dpx<=this.clickTolerance){this.callback(key,args);}}else{this.callback(key,args);}}},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});activated=true;}
return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.feature=null;this.lastFeature=null;this.down=null;this.up=null;this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});deactivated=true;}
return deactivated;},handleMapEvents:function(evt){if(!evt.property||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},moveLayerBack:function(){var index=this.layer.getZIndex()-1;if(index>=this.map.Z_INDEX_BASE['Feature']){this.layer.setZIndex(index);}else{this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer));}},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.Handler.Hover=OpenLayers.Class(OpenLayers.Handler,{delay:500,pixelTolerance:null,stopMove:false,px:null,timerId:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);},mousemove:function(evt){if(this.passesTolerance(evt.xy)){this.clearTimer();this.callback('move',[evt]);this.px=evt.xy;evt=OpenLayers.Util.extend({},evt);this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,evt),this.delay);}
return!this.stopMove;},mouseout:function(evt){if(OpenLayers.Util.mouseLeft(evt,this.map.div)){this.clearTimer();this.callback('move',[evt]);}
return true;},passesTolerance:function(px){var passes=true;if(this.pixelTolerance&&this.px){var dpx=Math.sqrt(Math.pow(this.px.x-px.x,2)+
Math.pow(this.px.y-px.y,2));if(dpx<this.pixelTolerance){passes=false;}}
return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}},delayedCall:function(evt){this.callback('pause',[evt]);},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();deactivated=true;}
return deactivated;},CLASS_NAME:"OpenLayers.Handler.Hover"});OpenLayers.Handler.Keyboard=OpenLayers.Class(OpenLayers.Handler,{KEY_EVENTS:["keydown","keyup"],eventListener:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.eventListener=OpenLayers.Function.bindAsEventListener(this.handleKeyEvent,this);},destroy:function(){this.deactivate();this.eventListener=null;OpenLayers.Handler.prototype.destroy.apply(this,arguments);},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){for(var i=0,len=this.KEY_EVENTS.length;i<len;i++){OpenLayers.Event.observe(document,this.KEY_EVENTS[i],this.eventListener);}
return true;}else{return false;}},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){for(var i=0,len=this.KEY_EVENTS.length;i<len;i++){OpenLayers.Event.stopObserving(document,this.KEY_EVENTS[i],this.eventListener);}
deactivated=true;}
return deactivated;},handleKeyEvent:function(evt){if(this.checkModifiers(evt)){this.callback(evt.type,[evt]);}},CLASS_NAME:"OpenLayers.Handler.Keyboard"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,interval:0,delta:0,cumulative:true,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this);},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null;},onWheelEvent:function(e){if(!this.map||!this.checkModifiers(e)){return;}
var overScrollableDiv=false;var overLayerDiv=false;var overMapDiv=false;var elem=OpenLayers.Event.element(e);while((elem!=null)&&!overMapDiv&&!overScrollableDiv){if(!overScrollableDiv){try{if(elem.currentStyle){overflow=elem.currentStyle["overflow"];}else{var style=document.defaultView.getComputedStyle(elem,null);var overflow=style.getPropertyValue("overflow");}
overScrollableDiv=(overflow&&(overflow=="auto")||(overflow=="scroll"));}catch(err){}}
if(!overLayerDiv){for(var i=0,len=this.map.layers.length;i<len;i++){if(elem==this.map.layers[i].div||elem==this.map.layers[i].pane){overLayerDiv=true;break;}}}
overMapDiv=(elem==this.map.div);elem=elem.parentNode;}
if(!overScrollableDiv&&overMapDiv){if(overLayerDiv){var delta=0;if(!e){e=window.event;}
if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera&&window.opera.version()<9.2){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
this.delta=this.delta+delta;if(this.interval){window.clearTimeout(this._timeoutId);this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(e);},this),this.interval);}else{this.wheelZoom(e);}}
OpenLayers.Event.stop(e);}},wheelZoom:function(e){var delta=this.delta;this.delta=0;if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
if(delta<0){this.callback("down",[e,this.cumulative?delta:-1]);}else{this.callback("up",[e,this.cumulative?delta:1]);}}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.observe(window,"mousewheel",wheelListener);OpenLayers.Event.observe(document,"mousewheel",wheelListener);return true;}else{return false;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:null,alwaysInRange:null,EVENT_TYPES:["loadstart","loadend","loadcancel","visibilitychanged","move","moveend"],RESOLUTION_PROPERTIES:['scales','resolutions','maxScale','minScale','maxResolution','minResolution','numZoomLevels','maxZoomLevel'],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,imageOffset:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:false,wrapDateLine:false,transitionEffect:null,SUPPORTED_TRANSITIONS:['resize'],metadata:{},initialize:function(name,options){this.addOptions(options);this.name=name;if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.div=OpenLayers.Util.createDiv(this.id);this.div.style.width="100%";this.div.style.height="100%";this.div.dir="ltr";this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}}
if(this.wrapDateLine){this.displayOutsideMaxExtent=true;}},destroy:function(setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
if(this.map!=null){this.map.removeLayer(this,setNewBaseLayer);}
this.projection=null;this.map=null;this.name=null;this.div=null;this.options=null;if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
this.events.destroy();}
this.eventListeners=null;this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.getOptions());}
OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},getOptions:function(){var options={};for(var o in this.options){options[o]=this[o];}
return options;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"name"});}}},addOptions:function(newOptions){if(this.options==null){this.options={};}
OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);if(typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);}
if(this.projection&&this.projection.getUnits()){this.units=this.projection.getUnits();}
if(this.map){var properties=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]);for(var o in newOptions){if(newOptions.hasOwnProperty(o)&&OpenLayers.Util.indexOf(properties,o)>=0){this.initResolutions();break;}}}},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){var zoomChanged=true;this.moveTo(extent,zoomChanged,false);this.events.triggerEvent("moveend",{"zoomChanged":zoomChanged});redrawn=true;}}
return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
this.display(display);},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent=this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);}
this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer){this.inRange=this.calculateInRange();var show=((this.visibility)&&(this.inRange));this.div.style.display=show?"":"none";}
this.setTileSize();}},afterAdd:function(){},removeMap:function(map){},getImageSize:function(bounds){return(this.imageSize||this.tileSize);},setTileSize:function(size){var tileSize=(size)?size:((this.tileSize)?this.tileSize:this.map.getTileSize());this.tileSize=tileSize;if(this.gutter){this.imageOffset=new OpenLayers.Pixel(-this.gutter,-this.gutter);this.imageSize=new OpenLayers.Size(tileSize.w+(2*this.gutter),tileSize.h+(2*this.gutter));}},getVisibility:function(){return this.visibility;},setVisibility:function(visibility){if(visibility!=this.visibility){this.visibility=visibility;this.display(visibility);this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});}
this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display&&this.calculateInRange())?"block":"none";}},calculateInRange:function(){var inRange=false;if(this.alwaysInRange){inRange=true;}else{if(this.map){var resolution=this.map.getResolution();inRange=((resolution>=this.minResolution)&&(resolution<=this.maxResolution));}}
return inRange;},setIsBaseLayer:function(isBaseLayer){if(isBaseLayer!=this.isBaseLayer){this.isBaseLayer=isBaseLayer;if(this.map!=null){this.map.events.triggerEvent("changebaselayer",{layer:this});}}},initResolutions:function(){var i,len;var props={},alwaysInRange=true;for(i=0,len=this.RESOLUTION_PROPERTIES.length;i<len;i++){var p=this.RESOLUTION_PROPERTIES[i];props[p]=this.options[p];if(alwaysInRange&&this.options[p]){alwaysInRange=false;}}
if(this.alwaysInRange==null){this.alwaysInRange=alwaysInRange;}
if(props.resolutions==null){props.resolutions=this.resolutionsFromScales(props.scales);}
if(props.resolutions==null){props.resolutions=this.calculateResolutions(props);}
if(props.resolutions==null){for(i=0,len=this.RESOLUTION_PROPERTIES.length;i<len;i++){var p=this.RESOLUTION_PROPERTIES[i];props[p]=this.options[p]!=null?this.options[p]:this.map[p];}
if(props.resolutions==null){props.resolutions=this.resolutionsFromScales(props.scales);}
if(props.resolutions==null){props.resolutions=this.calculateResolutions(props);}}
var maxResolution;if(this.options.maxResolution&&this.options.maxResolution!=="auto"){maxResolution=this.options.maxResolution;}
if(this.options.minScale){maxResolution=OpenLayers.Util.getResolutionFromScale(this.options.minScale,this.units);}
var minResolution;if(this.options.minResolution&&this.options.minResolution!=="auto"){minResolution=this.options.minResolution;}
if(this.options.maxScale){minResolution=OpenLayers.Util.getResolutionFromScale(this.options.maxScale,this.units);}
if(props.resolutions){props.resolutions.sort(function(a,b){return(b-a);});if(!maxResolution){maxResolution=props.resolutions[0];}
if(!minResolution){var lastIdx=props.resolutions.length-1;minResolution=props.resolutions[lastIdx];}}
this.resolutions=props.resolutions;if(this.resolutions){len=this.resolutions.length;this.scales=new Array(len);for(i=0;i<len;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(this.resolutions[i],this.units);}
this.numZoomLevels=len;}
this.minResolution=minResolution;if(minResolution){this.maxScale=OpenLayers.Util.getScaleFromResolution(minResolution,this.units);}
this.maxResolution=maxResolution;if(maxResolution){this.minScale=OpenLayers.Util.getScaleFromResolution(maxResolution,this.units);}},resolutionsFromScales:function(scales){if(scales==null){return;}
var resolutions,i,len;len=scales.length;resolutions=new Array(len);for(i=0;i<len;i++){resolutions[i]=OpenLayers.Util.getResolutionFromScale(scales[i],this.units);}
return resolutions;},calculateResolutions:function(props){var maxResolution=props.maxResolution;if(props.minScale!=null){maxResolution=OpenLayers.Util.getResolutionFromScale(props.minScale,this.units);}else if(maxResolution=="auto"&&this.maxExtent!=null){var viewSize=this.map.getSize();var wRes=this.maxExtent.getWidth()/viewSize.w;var hRes=this.maxExtent.getHeight()/viewSize.h;maxResolution=Math.max(wRes,hRes);}
var minResolution=props.minResolution;if(props.maxScale!=null){minResolution=OpenLayers.Util.getResolutionFromScale(props.maxScale,this.units);}else if(props.minResolution=="auto"&&this.minExtent!=null){var viewSize=this.map.getSize();var wRes=this.minExtent.getWidth()/viewSize.w;var hRes=this.minExtent.getHeight()/viewSize.h;minResolution=Math.max(wRes,hRes);}
var maxZoomLevel=props.maxZoomLevel;var numZoomLevels=props.numZoomLevels;if(typeof minResolution==="number"&&typeof maxResolution==="number"&&numZoomLevels===undefined){var ratio=maxResolution/minResolution;numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}else if(numZoomLevels===undefined&&maxZoomLevel!=null){numZoomLevels=maxZoomLevel+1;}
if(typeof numZoomLevels!=="number"||numZoomLevels<=0||(typeof maxResolution!=="number"&&typeof minResolution!=="number")){return;}
var resolutions=new Array(numZoomLevels);var base=2;if(typeof minResolution=="number"&&typeof maxResolution=="number"){base=Math.pow((maxResolution/minResolution),(1/(numZoomLevels-1)));}
var i;if(typeof maxResolution==="number"){for(i=0;i<numZoomLevels;i++){resolutions[i]=maxResolution/Math.pow(base,i);}}else{for(i=0;i<numZoomLevels;i++){resolutions[numZoomLevels-1-i]=minResolution*Math.pow(base,i);}}
return resolutions;},getResolution:function(){var zoom=this.map.getZoom();return this.getResolutionForZoom(zoom);},getExtent:function(){return this.map.calculateBounds();},getZoomForExtent:function(extent,closest){var viewSize=this.map.getSize();var idealResolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);return this.getZoomForResolution(idealResolution,closest);},getDataExtent:function(){},getResolutionForZoom:function(zoom){zoom=Math.max(0,Math.min(zoom,this.resolutions.length-1));var resolution;if(this.map.fractionalZoom){var low=Math.floor(zoom);var high=Math.ceil(zoom);resolution=this.resolutions[low]-
((zoom-low)*(this.resolutions[low]-this.resolutions[high]));}else{resolution=this.resolutions[Math.round(zoom)];}
return resolution;},getZoomForResolution:function(resolution,closest){var zoom;if(this.map.fractionalZoom){var lowZoom=0;var highZoom=this.resolutions.length-1;var highRes=this.resolutions[lowZoom];var lowRes=this.resolutions[highZoom];var res;for(var i=0,len=this.resolutions.length;i<len;++i){res=this.resolutions[i];if(res>=resolution){highRes=res;lowZoom=i;}
if(res<=resolution){lowRes=res;highZoom=i;break;}}
var dRes=highRes-lowRes;if(dRes>0){zoom=lowZoom+((highRes-resolution)/dRes);}else{zoom=lowZoom;}}else{var diff;var minDiff=Number.POSITIVE_INFINITY;for(var i=0,len=this.resolutions.length;i<len;i++){if(closest){diff=Math.abs(this.resolutions[i]-resolution);if(diff>minDiff){break;}
minDiff=diff;}else{if(this.resolutions[i]<resolution){break;}}}
zoom=Math.max(0,i-1);}
return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(viewPortPx!=null){var size=this.map.getSize();var center=this.map.getCenter();if(center){var res=this.map.getResolution();var delta_x=viewPortPx.x-(size.w/2);var delta_y=viewPortPx.y-(size.h/2);lonlat=new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}}
return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(lonlat!=null){var resolution=this.map.getResolution();var extent=this.map.getExtent();px=new OpenLayers.Pixel((1/resolution*(lonlat.lon-extent.left)),(1/resolution*(extent.top-lonlat.lat)));}
return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0,len=this.div.childNodes.length;i<len;++i){var element=this.div.childNodes[i].firstChild;OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}
if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"});}}},getZIndex:function(){return this.div.style.zIndex;},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){var mapGutter=this.gutter*this.map.getResolution();bounds=new OpenLayers.Bounds(bounds.left-mapGutter,bounds.bottom-mapGutter,bounds.right+mapGutter,bounds.top+mapGutter);}
if(this.wrapDateLine){var wrappingOptions={'rightTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(bounds,borderColor,borderWidth){this.bounds=bounds;this.div=OpenLayers.Util.createDiv();this.div.style.overflow='hidden';this.events=new OpenLayers.Events(this,this.div,null);this.setBorder(borderColor,borderWidth);},destroy:function(){this.bounds=null;this.div=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments);},setBorder:function(color,width){if(!color){color="red";}
if(!width){width=2;}
this.div.style.border=width+"px solid "+color;},draw:function(px,sz){OpenLayers.Util.modifyDOMElement(this.div,null,px,sz);return this.div;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsBounds(this.bounds,true,true);}
return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});(function(){var oXMLHttpRequest=window.XMLHttpRequest;var bGecko=!!window.controllers,bIE=window.document.all&&!window.opera,bIE7=bIE&&window.navigator.userAgent.match(/MSIE ([\.0-9]+)/)&&RegExp.$1==7;function cXMLHttpRequest(){this._object=oXMLHttpRequest&&!bIE7?new oXMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[];};if(bGecko&&oXMLHttpRequest.wrapped)
cXMLHttpRequest.wrapped=oXMLHttpRequest.wrapped;cXMLHttpRequest.UNSENT=0;cXMLHttpRequest.OPENED=1;cXMLHttpRequest.HEADERS_RECEIVED=2;cXMLHttpRequest.LOADING=3;cXMLHttpRequest.DONE=4;cXMLHttpRequest.prototype.readyState=cXMLHttpRequest.UNSENT;cXMLHttpRequest.prototype.responseText='';cXMLHttpRequest.prototype.responseXML=null;cXMLHttpRequest.prototype.status=0;cXMLHttpRequest.prototype.statusText='';cXMLHttpRequest.prototype.onreadystatechange=null;cXMLHttpRequest.onreadystatechange=null;cXMLHttpRequest.onopen=null;cXMLHttpRequest.onsend=null;cXMLHttpRequest.onabort=null;cXMLHttpRequest.prototype.open=function(sMethod,sUrl,bAsync,sUser,sPassword){delete this._headers;if(arguments.length<3)
bAsync=true;this._async=bAsync;var oRequest=this,nState=this.readyState,fOnUnload;if(bIE&&bAsync){fOnUnload=function(){if(nState!=cXMLHttpRequest.DONE){fCleanTransport(oRequest);oRequest.abort();}};window.attachEvent("onunload",fOnUnload);}
if(cXMLHttpRequest.onopen)
cXMLHttpRequest.onopen.apply(this,arguments);if(arguments.length>4)
this._object.open(sMethod,sUrl,bAsync,sUser,sPassword);else
if(arguments.length>3)
this._object.open(sMethod,sUrl,bAsync,sUser);else
this._object.open(sMethod,sUrl,bAsync);if(!bGecko&&!bIE){this.readyState=cXMLHttpRequest.OPENED;fReadyStateChange(this);}
this._object.onreadystatechange=function(){if(bGecko&&!bAsync)
return;oRequest.readyState=oRequest._object.readyState;fSynchronizeValues(oRequest);if(oRequest._aborted){oRequest.readyState=cXMLHttpRequest.UNSENT;return;}
if(oRequest.readyState==cXMLHttpRequest.DONE){fCleanTransport(oRequest);if(bIE&&bAsync)
window.detachEvent("onunload",fOnUnload);}
if(nState!=oRequest.readyState)
fReadyStateChange(oRequest);nState=oRequest.readyState;}};cXMLHttpRequest.prototype.send=function(vData){if(cXMLHttpRequest.onsend)
cXMLHttpRequest.onsend.apply(this,arguments);if(vData&&vData.nodeType){vData=window.XMLSerializer?new window.XMLSerializer().serializeToString(vData):vData.xml;if(!this._headers["Content-Type"])
this._object.setRequestHeader("Content-Type","application/xml");}
this._object.send(vData);if(bGecko&&!this._async){this.readyState=cXMLHttpRequest.OPENED;fSynchronizeValues(this);while(this.readyState<cXMLHttpRequest.DONE){this.readyState++;fReadyStateChange(this);if(this._aborted)
return;}}};cXMLHttpRequest.prototype.abort=function(){if(cXMLHttpRequest.onabort)
cXMLHttpRequest.onabort.apply(this,arguments);if(this.readyState>cXMLHttpRequest.UNSENT)
this._aborted=true;this._object.abort();fCleanTransport(this);};cXMLHttpRequest.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders();};cXMLHttpRequest.prototype.getResponseHeader=function(sName){return this._object.getResponseHeader(sName);};cXMLHttpRequest.prototype.setRequestHeader=function(sName,sValue){if(!this._headers)
this._headers={};this._headers[sName]=sValue;return this._object.setRequestHeader(sName,sValue);};cXMLHttpRequest.prototype.addEventListener=function(sName,fHandler,bUseCapture){for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
if(oListener[0]==sName&&oListener[1]==fHandler&&oListener[2]==bUseCapture)
return;this._listeners.push([sName,fHandler,bUseCapture]);};cXMLHttpRequest.prototype.removeEventListener=function(sName,fHandler,bUseCapture){for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
if(oListener[0]==sName&&oListener[1]==fHandler&&oListener[2]==bUseCapture)
break;if(oListener)
this._listeners.splice(nIndex,1);};cXMLHttpRequest.prototype.dispatchEvent=function(oEvent){var oEventPseudo={'type':oEvent.type,'target':this,'currentTarget':this,'eventPhase':2,'bubbles':oEvent.bubbles,'cancelable':oEvent.cancelable,'timeStamp':oEvent.timeStamp,'stopPropagation':function(){},'preventDefault':function(){},'initEvent':function(){}};if(oEventPseudo.type=="readystatechange"&&this.onreadystatechange)
(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[oEventPseudo]);for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
if(oListener[0]==oEventPseudo.type&&!oListener[2])
(oListener[1].handleEvent||oListener[1]).apply(this,[oEventPseudo]);};cXMLHttpRequest.prototype.toString=function(){return'['+"object"+' '+"XMLHttpRequest"+']';};cXMLHttpRequest.toString=function(){return'['+"XMLHttpRequest"+']';};function fReadyStateChange(oRequest){if(cXMLHttpRequest.onreadystatechange)
cXMLHttpRequest.onreadystatechange.apply(oRequest);oRequest.dispatchEvent({'type':"readystatechange",'bubbles':false,'cancelable':false,'timeStamp':new Date+0});};function fGetDocument(oRequest){var oDocument=oRequest.responseXML,sResponse=oRequest.responseText;if(bIE&&sResponse&&oDocument&&!oDocument.documentElement&&oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)){oDocument=new window.ActiveXObject("Microsoft.XMLDOM");oDocument.async=false;oDocument.validateOnParse=false;oDocument.loadXML(sResponse);}
if(oDocument)
if((bIE&&oDocument.parseError!=0)||!oDocument.documentElement||(oDocument.documentElement&&oDocument.documentElement.tagName=="parsererror"))
return null;return oDocument;};function fSynchronizeValues(oRequest){try{oRequest.responseText=oRequest._object.responseText;}catch(e){}
try{oRequest.responseXML=fGetDocument(oRequest._object);}catch(e){}
try{oRequest.status=oRequest._object.status;}catch(e){}
try{oRequest.statusText=oRequest._object.statusText;}catch(e){}};function fCleanTransport(oRequest){oRequest._object.onreadystatechange=new window.Function;};if(!window.Function.prototype.apply){window.Function.prototype.apply=function(oRequest,oArguments){if(!oArguments)
oArguments=[];oRequest.__func=this;oRequest.__func(oArguments[0],oArguments[1],oArguments[2],oArguments[3],oArguments[4]);delete oRequest.__func;};};OpenLayers.Request.XMLHttpRequest=cXMLHttpRequest;})();OpenLayers.Tile.Image.IFrame=OpenLayers.Class(OpenLayers.Tile.Image,{initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.Image.prototype.initialize.apply(this,arguments);this.layerAlphaHack=false;},destroy:function(){if(this.imgDiv!=null){OpenLayers.Event.stopObservingElement(this.imgDiv.firstChild);}
OpenLayers.Tile.Image.prototype.destroy.apply(this,arguments);},clear:function(){if(this.imgDiv){var iFrame=this.imgDiv.firstChild;OpenLayers.Event.stopObservingElement(iFrame);this.imgDiv.removeChild(iFrame);}},clone:function(obj){if(obj==null){obj=new OpenLayers.Tile.Image.IFrame(this.layer,this.position,this.bounds,this.url,this.size);}
obj=OpenLayers.Tile.Image.prototype.clone.apply(this,[obj]);return obj;},renderTile:function(){if(OpenLayers.Tile.Image.prototype.renderTile.apply(this,arguments)){var form=this.createRequestForm();this.imgDiv.appendChild(form);form.submit();this.imgDiv.removeChild(form);}},initImgDiv:function(){this.imgDiv=this.createImgDiv();OpenLayers.Util.modifyDOMElement(this.imgDiv,this.id,null,this.layer.getImageSize(),"relative");this.imgDiv.className='olTileImage';this.frame.appendChild(this.imgDiv);this.layer.div.appendChild(this.frame);if(this.layer.opacity!=null){OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,null,null,null,null,this.layer.opacity);}
this.imgDiv.map=this.layer.map;},createImgDiv:function(){var eventPane=document.createElement("div");if(OpenLayers.Util.getBrowserName()=="msie"){eventPane.style.backgroundColor='#FFFFFF';eventPane.style.filter='chroma(color=#FFFFFF)';}
OpenLayers.Util.modifyDOMElement(eventPane,null,new OpenLayers.Pixel(0,0),this.layer.getImageSize(),"absolute");var imgDiv=document.createElement("div");imgDiv.appendChild(eventPane);return imgDiv;},createIFrame:function(){var id=this.id+'_iFrame';var iframe;if(OpenLayers.Util.getBrowserName()=="msie"){iframe=document.createElement('<iframe name="'+id+'">');iframe.style.backgroundColor='#FFFFFF';iframe.style.filter='chroma(color=#FFFFFF)';}
else{iframe=document.createElement('iframe');iframe.style.backgroundColor='transparent';iframe.name=id;}
iframe.id=id;iframe.scrolling='no';iframe.marginWidth='0px';iframe.marginHeight='0px';iframe.frameBorder='0';OpenLayers.Util.modifyDOMElement(iframe,id,new OpenLayers.Pixel(0,0),this.layer.getImageSize(),"absolute");var onload=function(){this.show();if(this.isLoading){this.isLoading=false;this.events.triggerEvent("loadend");}};OpenLayers.Event.observe(iframe,'load',OpenLayers.Function.bind(onload,this));return iframe;},createRequestForm:function(){var form=document.createElement('form');form.method='POST';var cacheId=this.layer.params["_OLSALT"];cacheId=(cacheId?cacheId+"_":"")+this.bounds.toBBOX();form.action=OpenLayers.Util.urlAppend(this.layer.url,cacheId);this.imgDiv.insertBefore(this.createIFrame(),this.imgDiv.firstChild);form.target=this.id+'_iFrame';var imageSize=this.layer.getImageSize();var params=OpenLayers.Util.extend({"BBOX":this.encodeBBOX?this.bounds.toBBOX():this.bounds.toArray(),"WIDTH":imageSize.w,"HEIGHT":imageSize.h},this.layer.params);for(var par in params){var field=document.createElement('input');field.type='hidden';field.name=par;field.value=params[par];form.appendChild(field);}
return form;},CLASS_NAME:"OpenLayers.Tile.Image.IFrame"});OpenLayers.ProxyHost="";OpenLayers.nullHandler=function(request){OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest",{'statusText':request.statusText}));};OpenLayers.loadURL=function(uri,params,caller,onComplete,onFailure){if(typeof params=='string'){params=OpenLayers.Util.getParameters(params);}
var success=(onComplete)?onComplete:OpenLayers.nullHandler;var failure=(onFailure)?onFailure:OpenLayers.nullHandler;return OpenLayers.Request.GET({url:uri,params:params,success:success,failure:failure,scope:caller});};OpenLayers.parseXMLString=function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
var ajaxResponse=OpenLayers.Util.Try(function(){var xmldom=new ActiveXObject('Microsoft.XMLDOM');xmldom.loadXML(text);return xmldom;},function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
req.send(null);return req.responseXML;});return ajaxResponse;};OpenLayers.Ajax={emptyFunction:function(){},getTransport:function(){return OpenLayers.Util.Try(function(){return new XMLHttpRequest();},function(){return new ActiveXObject('Msxml2.XMLHTTP');},function(){return new ActiveXObject('Microsoft.XMLHTTP');})||false;},activeRequestCount:0};OpenLayers.Ajax.Responders={responders:[],register:function(responderToAdd){for(var i=0;i<this.responders.length;i++){if(responderToAdd==this.responders[i]){return;}}
this.responders.push(responderToAdd);},unregister:function(responderToRemove){OpenLayers.Util.removeItem(this.reponders,responderToRemove);},dispatch:function(callback,request,transport){var responder;for(var i=0;i<this.responders.length;i++){responder=this.responders[i];if(responder[callback]&&typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport]);}catch(e){}}}}};OpenLayers.Ajax.Responders.register({onCreate:function(){OpenLayers.Ajax.activeRequestCount++;},onComplete:function(){OpenLayers.Ajax.activeRequestCount--;}});OpenLayers.Ajax.Base=OpenLayers.Class({initialize:function(options){this.options={method:'post',asynchronous:true,contentType:'application/xml',parameters:''};OpenLayers.Util.extend(this.options,options||{});this.options.method=this.options.method.toLowerCase();if(typeof this.options.parameters=='string'){this.options.parameters=OpenLayers.Util.getParameters(this.options.parameters);}}});OpenLayers.Ajax.Request=OpenLayers.Class(OpenLayers.Ajax.Base,{_complete:false,initialize:function(url,options){OpenLayers.Ajax.Base.prototype.initialize.apply(this,[options]);if(OpenLayers.ProxyHost&&OpenLayers.String.startsWith(url,"http")){url=OpenLayers.ProxyHost+encodeURIComponent(url);}
this.transport=OpenLayers.Ajax.getTransport();this.request(url);},request:function(url){this.url=url;this.method=this.options.method;var params=OpenLayers.Util.extend({},this.options.parameters);if(this.method!='get'&&this.method!='post'){params['_method']=this.method;this.method='post';}
this.parameters=params;if(params=OpenLayers.Util.getParameterString(params)){if(this.method=='get'){this.url+=((this.url.indexOf('?')>-1)?'&':'?')+params;}else if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)){params+='&_=';}}
try{var response=new OpenLayers.Ajax.Response(this);if(this.options.onCreate){this.options.onCreate(response);}
OpenLayers.Ajax.Responders.dispatch('onCreate',this,response);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);if(this.options.asynchronous){window.setTimeout(OpenLayers.Function.bind(this.respondToReadyState,this,1),10);}
this.transport.onreadystatechange=OpenLayers.Function.bind(this.onStateChange,this);this.setRequestHeaders();this.body=this.method=='post'?(this.options.postBody||params):null;this.transport.send(this.body);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange();}}catch(e){this.dispatchException(e);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState>1&&!((readyState==4)&&this._complete)){this.respondToReadyState(this.transport.readyState);}},setRequestHeaders:function(){var headers={'X-Requested-With':'XMLHttpRequest','Accept':'text/javascript, text/html, application/xml, text/xml, */*','OpenLayers':true};if(this.method=='post'){headers['Content-type']=this.options.contentType+
(this.options.encoding?'; charset='+this.options.encoding:'');if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005){headers['Connection']='close';}}
if(typeof this.options.requestHeaders=='object'){var extras=this.options.requestHeaders;if(typeof extras.push=='function'){for(var i=0,length=extras.length;i<length;i+=2){headers[extras[i]]=extras[i+1];}}else{for(var i in extras){headers[i]=extras[i];}}}
for(var name in headers){this.transport.setRequestHeader(name,headers[name]);}},success:function(){var status=this.getStatus();return!status||(status>=200&&status<300);},getStatus:function(){try{return this.transport.status||0;}catch(e){return 0;}},respondToReadyState:function(readyState){var state=OpenLayers.Ajax.Request.Events[readyState];var response=new OpenLayers.Ajax.Response(this);if(state=='Complete'){try{this._complete=true;(this.options['on'+response.status]||this.options['on'+(this.success()?'Success':'Failure')]||OpenLayers.Ajax.emptyFunction)(response);}catch(e){this.dispatchException(e);}
var contentType=response.getHeader('Content-type');}
try{(this.options['on'+state]||OpenLayers.Ajax.emptyFunction)(response);OpenLayers.Ajax.Responders.dispatch('on'+state,this,response);}catch(e){this.dispatchException(e);}
if(state=='Complete'){this.transport.onreadystatechange=OpenLayers.Ajax.emptyFunction;}},getHeader:function(name){try{return this.transport.getResponseHeader(name);}catch(e){return null;}},dispatchException:function(exception){var handler=this.options.onException;if(handler){handler(this,exception);OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}else{var listener=false;var responders=OpenLayers.Ajax.Responders.responders;for(var i=0;i<responders.length;i++){if(responders[i].onException){listener=true;break;}}
if(listener){OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}else{throw exception;}}}});OpenLayers.Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];OpenLayers.Ajax.Response=OpenLayers.Class({status:0,statusText:'',initialize:function(request){this.request=request;var transport=this.transport=request.transport,readyState=this.readyState=transport.readyState;if((readyState>2&&!(!!(window.attachEvent&&!window.opera)))||readyState==4){this.status=this.getStatus();this.statusText=this.getStatusText();this.responseText=transport.responseText==null?'':String(transport.responseText);}
if(readyState==4){var xml=transport.responseXML;this.responseXML=xml===undefined?null:xml;}},getStatus:OpenLayers.Ajax.Request.prototype.getStatus,getStatusText:function(){try{return this.transport.statusText||'';}catch(e){return'';}},getHeader:OpenLayers.Ajax.Request.prototype.getHeader,getResponseHeader:function(name){return this.transport.getResponseHeader(name);}});OpenLayers.Ajax.getElementsByTagNameNS=function(parentnode,nsuri,nsprefix,tagname){var elem=null;if(parentnode.getElementsByTagNameNS){elem=parentnode.getElementsByTagNameNS(nsuri,tagname);}else{elem=parentnode.getElementsByTagName(nsprefix+':'+tagname);}
return elem;};OpenLayers.Ajax.serializeXMLToString=function(xmldom){var serializer=new XMLSerializer();var data=serializer.serializeToString(xmldom);return data;};OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(feature,pixel){},onDrag:function(feature,pixel){},onComplete:function(feature,pixel){},documentDrag:false,layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(layer,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.layer=layer;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks),{documentDrag:this.documentDrag}),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})};},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){return(this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=false;this.lastPixel=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over");return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},overFeature:function(feature){if(!this.handlers.drag.dragging){this.feature=feature;this.handlers.drag.activate();this.over=true;OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass+"Over");}else{if(this.feature.id==feature.id){this.over=true;}else{this.over=false;}}},downFeature:function(pixel){this.lastPixel=pixel;this.onStart(this.feature,pixel);},moveFeature:function(pixel){var res=this.map.getResolution();this.feature.geometry.move(res*(pixel.x-this.lastPixel.x),res*(this.lastPixel.y-pixel.y));this.layer.drawFeature(this.feature);this.lastPixel=pixel;this.onDrag(this.feature,pixel);},upFeature:function(pixel){if(!this.over){this.handlers.drag.deactivate();}},doneDragging:function(pixel){this.onComplete(this.feature,pixel);},outFeature:function(feature){if(!this.handlers.drag.dragging){this.over=false;this.handlers.drag.deactivate();OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over");this.feature=null;}else{if(this.feature.id==feature.id){this.over=false;}}},cancel:function(){this.handlers.drag.deactivate();this.over=false;},setMap:function(map){this.handlers.drag.setMap(map);this.handlers.feature.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:25,documentDrag:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone},{interval:this.interval,documentDrag:this.documentDrag});},panMap:function(xy){this.panned=true;this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:this.handler.dragging,animate:false});},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Control.KeyboardDefaults=OpenLayers.Class(OpenLayers.Control,{autoActivate:true,slideFactor:75,initialize:function(){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.handler){this.handler.destroy();}
this.handler=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){this.handler=new OpenLayers.Handler.Keyboard(this,{"keydown":this.defaultKeyPress});},defaultKeyPress:function(evt){switch(evt.keyCode){case OpenLayers.Event.KEY_LEFT:this.map.pan(-this.slideFactor,0);break;case OpenLayers.Event.KEY_RIGHT:this.map.pan(this.slideFactor,0);break;case OpenLayers.Event.KEY_UP:this.map.pan(0,-this.slideFactor);break;case OpenLayers.Event.KEY_DOWN:this.map.pan(0,this.slideFactor);break;case 33:var size=this.map.getSize();this.map.pan(0,-0.75*size.h);break;case 34:var size=this.map.getSize();this.map.pan(0,0.75*size.h);break;case 35:var size=this.map.getSize();this.map.pan(0.75*size.w,0);break;case 36:var size=this.map.getSize();this.map.pan(-0.75*size.w,0);break;case 43:case 61:case 187:case 107:this.map.zoomIn();break;case 45:case 109:case 189:case 95:this.map.zoomOut();break;}},CLASS_NAME:"OpenLayers.Control.KeyboardDefaults"});OpenLayers.Control.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:false,drillDown:false,maxFeatures:10,clickCallback:"click",layers:null,queryVisible:false,url:null,layerUrls:null,infoFormat:'text/html',vendorParams:{},format:null,formatOptions:null,handlerOptions:null,handler:null,hoverRequest:null,EVENT_TYPES:["beforegetfeatureinfo","nogetfeatureinfo","getfeatureinfo"],initialize:function(options){this.EVENT_TYPES=OpenLayers.Control.WMSGetFeatureInfo.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);options=options||{};options.handlerOptions=options.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[options]);if(!this.format){this.format=new OpenLayers.Format.WMSGetFeatureInfo(options.formatOptions);}
if(this.drillDown===true){this.hover=false;}
if(this.hover){this.handler=new OpenLayers.Handler.Hover(this,{'move':this.cancelHover,'pause':this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{'delay':250}));}else{var callbacks={};callbacks[this.clickCallback]=this.getInfoForClick;this.handler=new OpenLayers.Handler.Click(this,callbacks,this.handlerOptions.click||{});}},activate:function(){if(!this.active){this.handler.activate();}
return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},getInfoForClick:function(evt){this.events.triggerEvent("beforegetfeatureinfo",{xy:evt.xy});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");this.request(evt.xy,{});},getInfoForHover:function(evt){this.events.triggerEvent("beforegetfeatureinfo",{xy:evt.xy});this.request(evt.xy,{hover:true});},cancelHover:function(){if(this.hoverRequest){this.hoverRequest.abort();this.hoverRequest=null;}},findLayers:function(){var candidates=this.layers||this.map.layers;var layers=[];var layer,url;for(var i=0,len=candidates.length;i<len;++i){layer=candidates[i];if(layer instanceof OpenLayers.Layer.WMS&&(!this.queryVisible||layer.getVisibility())){url=layer.url instanceof Array?layer.url[0]:layer.url;if(this.drillDown===false&&!this.url){this.url=url;}
if(this.drillDown===true||this.urlMatches(url)){layers.push(layer);}}}
return layers;},urlMatches:function(url){var matches=OpenLayers.Util.isEquivalentUrl(this.url,url);if(!matches&&this.layerUrls){for(var i=0,len=this.layerUrls.length;i<len;++i){if(OpenLayers.Util.isEquivalentUrl(this.layerUrls[i],url)){matches=true;break;}}}
return matches;},buildWMSOptions:function(url,layers,clickPosition,format){var layerNames=[],styleNames=[];for(var i=0,len=layers.length;i<len;i++){layerNames=layerNames.concat(layers[i].params.LAYERS);styleNames=styleNames.concat(this.getStyleNames(layers[i]));}
var params=OpenLayers.Util.extend({service:"WMS",version:layers[0].params.VERSION,request:"GetFeatureInfo",layers:layerNames,query_layers:layerNames,styles:styleNames,bbox:this.map.getExtent().toBBOX(null,layers[0].reverseAxisOrder()),feature_count:this.maxFeatures,height:this.map.getSize().h,width:this.map.getSize().w,format:format,info_format:this.infoFormat},(parseFloat(layers[0].params.VERSION)>=1.3)?{crs:this.map.getProjection(),i:clickPosition.x,j:clickPosition.y}:{srs:this.map.getProjection(),x:clickPosition.x,y:clickPosition.y});OpenLayers.Util.applyDefaults(params,this.vendorParams);return{url:url,params:OpenLayers.Util.upperCaseObject(params),callback:function(request){this.handleResponse(clickPosition,request);},scope:this};},getStyleNames:function(layer){var styleNames;if(layer.params.STYLES){styleNames=layer.params.STYLES;}else{if(layer.params.LAYERS instanceof Array){styleNames=new Array(layer.params.LAYERS.length);}else{styleNames=layer.params.LAYERS.replace(/[^,]/g,"");}}
return styleNames;},request:function(clickPosition,options){var layers=this.findLayers();if(layers.length==0){this.events.triggerEvent("nogetfeatureinfo");OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait");return;}
options=options||{};if(this.drillDown===false){var wmsOptions=this.buildWMSOptions(this.url,layers,clickPosition,layers[0].params.FORMAT);var request=OpenLayers.Request.GET(wmsOptions);if(options.hover===true){this.hoverRequest=request;}}else{this._requestCount=0;this._numRequests=0;this.features=[];var services={},url;for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];var service,found=false;url=layer.url instanceof Array?layer.url[0]:layer.url;if(url in services){services[url].push(layer);}else{this._numRequests++;services[url]=[layer];}}
var layers;for(var url in services){layers=services[url];var wmsOptions=this.buildWMSOptions(url,layers,clickPosition,layers[0].params.FORMAT);OpenLayers.Request.GET(wmsOptions);}}},triggerGetFeatureInfo:function(request,xy,features){this.events.triggerEvent("getfeatureinfo",{text:request.responseText,features:features,request:request,xy:xy});OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait");},handleResponse:function(xy,request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
var features=this.format.read(doc);if(this.drillDown===false){this.triggerGetFeatureInfo(request,xy,features);}else{this._requestCount++;this._features=(this._features||[]).concat(features);if(this._requestCount===this._numRequests){this.triggerGetFeatureInfo(request,xy,this._features.concat());delete this._features;delete this._requestCount;delete this._numRequests;}}},CLASS_NAME:"OpenLayers.Control.WMSGetFeatureInfo"});OpenLayers.Control.WMTSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:false,requestEncoding:"KVP",drillDown:false,maxFeatures:10,clickCallback:"click",layers:null,queryVisible:true,infoFormat:'text/html',vendorParams:{},format:null,formatOptions:null,handlerOptions:null,handler:null,hoverRequest:null,EVENT_TYPES:["beforegetfeatureinfo","getfeatureinfo","exception"],pending:0,initialize:function(options){this.EVENT_TYPES=OpenLayers.Control.WMTSGetFeatureInfo.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);options=options||{};options.handlerOptions=options.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[options]);if(!this.format){this.format=new OpenLayers.Format.WMSGetFeatureInfo(options.formatOptions);}
if(this.drillDown===true){this.hover=false;}
if(this.hover){this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250}));}else{var callbacks={};callbacks[this.clickCallback]=this.getInfoForClick;this.handler=new OpenLayers.Handler.Click(this,callbacks,this.handlerOptions.click||{});}},activate:function(){if(!this.active){this.handler.activate();}
return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},getInfoForClick:function(evt){this.request(evt.xy,{});},getInfoForHover:function(evt){this.request(evt.xy,{hover:true});},cancelHover:function(){if(this.hoverRequest){--this.pending;if(this.pending<=0){OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait");this.pending=0;}
this.hoverRequest.abort();this.hoverRequest=null;}},findLayers:function(){var candidates=this.layers||this.map.layers;var layers=[];var layer;for(var i=candidates.length-1;i>=0;--i){layer=candidates[i];if(layer instanceof OpenLayers.Layer.WMTS&&layer.requestEncoding===this.requestEncoding&&(!this.queryVisible||layer.getVisibility())){layers.push(layer);if(!this.drillDown||this.hover){break;}}}
return layers;},buildRequestOptions:function(layer,xy){var loc=this.map.getLonLatFromPixel(xy);var getTileUrl=layer.getURL(new OpenLayers.Bounds(loc.lon,loc.lat,loc.lon,loc.lat));var params=OpenLayers.Util.getParameters(getTileUrl);var tileInfo=layer.getTileInfo(loc);OpenLayers.Util.extend(params,{service:"WMTS",version:layer.version,request:"GetFeatureInfo",infoFormat:this.infoFormat,i:tileInfo.i,j:tileInfo.j});OpenLayers.Util.applyDefaults(params,this.vendorParams);return{url:layer.url instanceof Array?layer.url[0]:layer.url,params:OpenLayers.Util.upperCaseObject(params),callback:function(request){this.handleResponse(xy,request,layer);},scope:this};},request:function(xy,options){options=options||{};var layers=this.findLayers();if(layers.length>0){var issue,layer;for(var i=0,len=layers.length;i<len;i++){layer=layers[i];issue=this.events.triggerEvent("beforegetfeatureinfo",{xy:xy,layer:layer});if(issue!==false){++this.pending;var requestOptions=this.buildRequestOptions(layer,xy);var request=OpenLayers.Request.GET(requestOptions);if(options.hover===true){this.hoverRequest=request;}}}
if(this.pending>0){OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");}}},handleResponse:function(xy,request,layer){--this.pending;if(this.pending<=0){OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait");this.pending=0;}
if(request.status&&(request.status<200||request.status>=300)){this.events.triggerEvent("exception",{xy:xy,request:request,layer:layer});}else{var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
var features,except;try{features=this.format.read(doc);}catch(error){except=true;this.events.triggerEvent("exception",{xy:xy,request:request,error:error,layer:layer});}
if(!except){this.events.triggerEvent("getfeatureinfo",{text:request.responseText,features:features,request:request,xy:xy,layer:layer});}}},setMap:function(map){this.handler.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.WMTSGetFeatureInfo"});OpenLayers.State={UNKNOWN:'Unknown',INSERT:'Insert',UPDATE:'Update',DELETE:'Delete'};OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",initialize:function(geometry,attributes,style){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,attributes]);this.lonlat=null;this.geometry=geometry?geometry:null;this.state=null;this.attributes={};if(attributes){this.attributes=OpenLayers.Util.extend(this.attributes,attributes);}
this.style=style?style:null;},destroy:function(){if(this.layer){this.layer.removeFeatures(this);this.layer=null;}
this.geometry=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments);},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style);},onScreen:function(boundsOnly){var onScreen=false;if(this.layer&&this.layer.map){var screenBounds=this.layer.map.getExtent();if(boundsOnly){var featureBounds=this.geometry.getBounds();onScreen=screenBounds.intersectsBounds(featureBounds);}else{var screenPoly=screenBounds.toGeometry();onScreen=screenPoly.intersects(this.geometry);}}
return onScreen;},getVisibility:function(){return!(this.style&&this.style.display=='none'||!this.layer||this.layer&&this.layer.styleMap&&this.layer.styleMap.createSymbolizer(this,this.renderIntent).display=='none'||this.layer&&!this.layer.getVisibility());},createMarker:function(){return null;},destroyMarker:function(){},createPopup:function(){return null;},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;if(this.geometry){atPoint=this.geometry.atPoint(lonlat,toleranceLon,toleranceLat);}
return atPoint;},destroyPopup:function(){},move:function(location){if(!this.layer||!this.geometry.move){return;}
var pixel;if(location.CLASS_NAME=="OpenLayers.LonLat"){pixel=this.layer.getViewPortPxFromLonLat(location);}else{pixel=location;}
var lastPixel=this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());var res=this.layer.map.getResolution();this.geometry.move(res*(pixel.x-lastPixel.x),res*(lastPixel.y-pixel.y));this.layer.drawFeature(this);return lastPixel;},toState:function(state){if(state==OpenLayers.State.UPDATE){switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=state;break;case OpenLayers.State.UPDATE:case OpenLayers.State.INSERT:break;}}else if(state==OpenLayers.State.INSERT){switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=state;break;}}else if(state==OpenLayers.State.DELETE){switch(this.state){case OpenLayers.State.INSERT:break;case OpenLayers.State.DELETE:break;case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state=state;break;}}else if(state==OpenLayers.State.UNKNOWN){this.state=state;}},CLASS_NAME:"OpenLayers.Feature.Vector"});OpenLayers.Feature.Vector.style={'default':{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit"},'select':{fillColor:"blue",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer"},'temporary':{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1,strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit"},'delete':{display:"none"}};OpenLayers.Feature.WFS=OpenLayers.Class(OpenLayers.Feature,{initialize:function(layer,xmlNode){var newArguments=arguments;var data=this.processXMLNode(xmlNode);newArguments=new Array(layer,data.lonlat,data);OpenLayers.Feature.prototype.initialize.apply(this,newArguments);this.createMarker();this.layer.addMarker(this.marker);},destroy:function(){if(this.marker!=null){this.layer.removeMarker(this.marker);}
OpenLayers.Feature.prototype.destroy.apply(this,arguments);},processXMLNode:function(xmlNode){var point=OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,"http://www.opengis.net/gml","gml","Point");var text=OpenLayers.Util.getXmlNodeValue(OpenLayers.Ajax.getElementsByTagNameNS(point[0],"http://www.opengis.net/gml","gml","coordinates")[0]);var floats=text.split(",");return{lonlat:new OpenLayers.LonLat(parseFloat(floats[0]),parseFloat(floats[1])),id:null};},CLASS_NAME:"OpenLayers.Feature.WFS"});OpenLayers.Format.OWSCommon.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows/1.0",xlink:"http://www.w3.org/1999/xlink"},readers:{"ows":OpenLayers.Format.OWSCommon.v1.prototype.readers["ows"]},writers:{"ows":OpenLayers.Format.OWSCommon.v1.prototype.writers["ows"]},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_1_0"});OpenLayers.Format.OWSCommon.v1_1_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows/1.1",xlink:"http://www.w3.org/1999/xlink"},readers:{"ows":OpenLayers.Util.applyDefaults({"AllowedValues":function(node,parameter){parameter.allowedValues={};this.readChildNodes(node,parameter.allowedValues);},"AnyValue":function(node,parameter){parameter.anyValue=true;},"Range":function(node,allowedValues){allowedValues.range={};this.readChildNodes(node,allowedValues.range);},"MinimumValue":function(node,range){range.minValue=this.getChildValue(node);},"MaximumValue":function(node,range){range.maxValue=this.getChildValue(node);},"Identifier":function(node,obj){obj.identifier=this.getChildValue(node);},"SupportedCRS":function(node,obj){obj.supportedCRS=this.getChildValue(node);}},OpenLayers.Format.OWSCommon.v1.prototype.readers["ows"])},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_1_0"});OpenLayers.Format.OWSContext=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"0.3.1",getParser:function(version){var v=version||this.version||this.defaultVersion;if(v==="0.3.0"){v=this.defaultVersion;}
if(!this.parser||this.parser.VERSION!=v){var format=OpenLayers.Format.OWSContext["v"+v.replace(/\./g,"_")];if(!format){throw"Can't find a OWSContext parser for version "+v;}
this.parser=new format(this.options);}
return this.parser;},toContext:function(obj){var context={};if(obj.CLASS_NAME=="OpenLayers.Map"){context.bounds=obj.getExtent();context.maxExtent=obj.maxExtent;context.projection=obj.projection;context.size=obj.getSize();context.layers=obj.layers;}
return context;},CLASS_NAME:"OpenLayers.Format.OWSContext"});OpenLayers.Format.WFSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.WFSCapabilities,{initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var capabilities={};var root=data.documentElement;this.runChildNodes(capabilities,root);return capabilities;},runChildNodes:function(obj,node){var children=node.childNodes;var childNode,processor;for(var i=0;i<children.length;++i){childNode=children[i];if(childNode.nodeType==1){processor=this["read_cap_"+childNode.nodeName];if(processor){processor.apply(this,[obj,childNode]);}}}},read_cap_FeatureTypeList:function(request,node){var featureTypeList={featureTypes:[]};this.runChildNodes(featureTypeList,node);request.featureTypeList=featureTypeList;},read_cap_FeatureType:function(featureTypeList,node,parentLayer){var featureType={};this.runChildNodes(featureType,node);featureTypeList.featureTypes.push(featureType);},read_cap_Name:function(obj,node){var name=this.getChildValue(node);if(name){var parts=name.split(":");obj.name=parts.pop();if(parts.length>0){obj.featureNS=this.lookupNamespaceURI(node,parts[0]);}}},read_cap_Title:function(obj,node){var title=this.getChildValue(node);if(title){obj.title=title;}},read_cap_Abstract:function(obj,node){var abst=this.getChildValue(node);if(abst){obj["abstract"]=abst;}},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1"});OpenLayers.Format.WMC=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"1.1.0",getParser:function(version){var v=version||this.version||this.defaultVersion;if(!this.parser||this.parser.VERSION!=v){var format=OpenLayers.Format.WMC["v"+v.replace(/\./g,"_")];if(!format){throw"Can't find a WMC parser for version "+v;}
this.parser=new format(this.options);}
return this.parser;},layerToContext:function(layer){var parser=this.getParser();var layerContext={queryable:layer.queryable,visibility:layer.visibility,name:layer.params["LAYERS"],title:layer.name,metadataURL:layer.metadataURL,version:layer.params["VERSION"],url:layer.url,maxExtent:layer.maxExtent,transparent:layer.params["TRANSPARENT"],numZoomLevels:layer.numZoomLevels,units:layer.units,isBaseLayer:layer.isBaseLayer,opacity:layer.opacity,displayInLayerSwitcher:layer.displayInLayerSwitcher,singleTile:layer.singleTile,tileSize:(layer.singleTile||!layer.tileSize)?undefined:{width:layer.tileSize.w,height:layer.tileSize.h},minScale:(layer.options.resolutions||layer.options.scales||layer.options.maxResolution||layer.options.minScale)?layer.minScale:undefined,maxScale:(layer.options.resolutions||layer.options.scales||layer.options.minResolution||layer.options.maxScale)?layer.maxScale:undefined,formats:[{value:layer.params["FORMAT"],current:true}],styles:[{href:layer.params["SLD"],body:layer.params["SLD_BODY"],name:layer.params["STYLES"]||parser.defaultStyleName,title:parser.defaultStyleTitle,current:true}]};return layerContext;},toContext:function(obj){var context={};var layers=obj.layers;if(obj.CLASS_NAME=="OpenLayers.Map"){context.bounds=obj.getExtent();context.maxExtent=obj.maxExtent;context.projection=obj.projection;context.size=obj.getSize();}
else{OpenLayers.Util.applyDefaults(context,obj);if(context.layers!=undefined){delete(context.layers);}}
if(context.layersContext==undefined){context.layersContext=[];}
if(layers!=undefined&&layers instanceof Array){for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];if(layer instanceof OpenLayers.Layer.WMS){context.layersContext.push(this.layerToContext(layer));}}}
return context;},CLASS_NAME:"OpenLayers.Format.WMC"});OpenLayers.Format.WMSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wms:"http://www.opengis.net/wms",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"wms",initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var capabilities={};this.readNode(data,capabilities);this.postProcessLayers(capabilities);return capabilities;},postProcessLayers:function(capabilities){if(capabilities.capability){capabilities.capability.layers=[];var layers=capabilities.capability.nestedLayers;for(var i=0,len=layers.length;i<len;++i){var layer=layers[i];this.processLayer(capabilities.capability,layer);}}},processLayer:function(capability,layer,parentLayer){if(layer.formats===undefined){layer.formats=capability.request.getmap.formats;}
if(parentLayer){layer.styles=layer.styles.concat(parentLayer.styles);var attributes=["queryable","cascaded","fixedWidth","fixedHeight","opaque","noSubsets","llbbox","minScale","maxScale","attribution"];var complexAttr=["srs","bbox","dimensions","authorityURLs"];var key;for(var j=0;j<attributes.length;j++){key=attributes[j];if(key in parentLayer){if(layer[key]==null){layer[key]=parentLayer[key];}
if(layer[key]==null){var intAttr=["cascaded","fixedWidth","fixedHeight"];var boolAttr=["queryable","opaque","noSubsets"];if(OpenLayers.Util.indexOf(intAttr,key)!=-1){layer[key]=0;}
if(OpenLayers.Util.indexOf(boolAttr,key)!=-1){layer[key]=false;}}}}
for(var j=0;j<complexAttr.length;j++){key=complexAttr[j];layer[key]=OpenLayers.Util.extend(layer[key],parentLayer[key]);}}
for(var i=0,len=layer.nestedLayers.length;i<len;i++){var childLayer=layer.nestedLayers[i];this.processLayer(capability,childLayer,layer);}
if(layer.name){capability.layers.push(layer);}},readers:{"wms":{"Service":function(node,obj){obj.service={};this.readChildNodes(node,obj.service);},"Name":function(node,obj){obj.name=this.getChildValue(node);},"Title":function(node,obj){obj.title=this.getChildValue(node);},"Abstract":function(node,obj){obj["abstract"]=this.getChildValue(node);},"BoundingBox":function(node,obj){var bbox={};bbox.bbox=[parseFloat(node.getAttribute("minx")),parseFloat(node.getAttribute("miny")),parseFloat(node.getAttribute("maxx")),parseFloat(node.getAttribute("maxy"))];var res={x:parseFloat(node.getAttribute("resx")),y:parseFloat(node.getAttribute("resy"))};if(!(isNaN(res.x)&&isNaN(res.y))){bbox.res=res;}
return bbox;},"OnlineResource":function(node,obj){obj.href=this.getAttributeNS(node,this.namespaces.xlink,"href");},"ContactInformation":function(node,obj){obj.contactInformation={};this.readChildNodes(node,obj.contactInformation);},"ContactPersonPrimary":function(node,obj){obj.personPrimary={};this.readChildNodes(node,obj.personPrimary);},"ContactPerson":function(node,obj){obj.person=this.getChildValue(node);},"ContactOrganization":function(node,obj){obj.organization=this.getChildValue(node);},"ContactPosition":function(node,obj){obj.position=this.getChildValue(node);},"ContactAddress":function(node,obj){obj.contactAddress={};this.readChildNodes(node,obj.contactAddress);},"AddressType":function(node,obj){obj.type=this.getChildValue(node);},"Address":function(node,obj){obj.address=this.getChildValue(node);},"City":function(node,obj){obj.city=this.getChildValue(node);},"StateOrProvince":function(node,obj){obj.stateOrProvince=this.getChildValue(node);},"PostCode":function(node,obj){obj.postcode=this.getChildValue(node);},"Country":function(node,obj){obj.country=this.getChildValue(node);},"ContactVoiceTelephone":function(node,obj){obj.phone=this.getChildValue(node);},"ContactFacsimileTelephone":function(node,obj){obj.fax=this.getChildValue(node);},"ContactElectronicMailAddress":function(node,obj){obj.email=this.getChildValue(node);},"Fees":function(node,obj){var fees=this.getChildValue(node);if(fees&&fees.toLowerCase()!="none"){obj.fees=fees;}},"AccessConstraints":function(node,obj){var constraints=this.getChildValue(node);if(constraints&&constraints.toLowerCase()!="none"){obj.accessConstraints=constraints;}},"Capability":function(node,obj){obj.capability={nestedLayers:[]};this.readChildNodes(node,obj.capability);},"Request":function(node,obj){obj.request={};this.readChildNodes(node,obj.request);},"GetCapabilities":function(node,obj){obj.getcapabilities={formats:[]};this.readChildNodes(node,obj.getcapabilities);},"Format":function(node,obj){if(obj.formats instanceof Array){obj.formats.push(this.getChildValue(node));}else{obj.format=this.getChildValue(node);}},"DCPType":function(node,obj){this.readChildNodes(node,obj);},"HTTP":function(node,obj){this.readChildNodes(node,obj);},"Get":function(node,obj){this.readChildNodes(node,obj);},"Post":function(node,obj){this.readChildNodes(node,obj);},"GetMap":function(node,obj){obj.getmap={formats:[]};this.readChildNodes(node,obj.getmap);},"GetFeatureInfo":function(node,obj){obj.getfeatureinfo={formats:[]};this.readChildNodes(node,obj.getfeatureinfo);},"Exception":function(node,obj){obj.exception={formats:[]};this.readChildNodes(node,obj.exception);},"Layer":function(node,obj){var attrNode=node.getAttributeNode("queryable");var queryable=(attrNode&&attrNode.specified)?node.getAttribute("queryable"):null;attrNode=node.getAttributeNode("cascaded");var cascaded=(attrNode&&attrNode.specified)?node.getAttribute("cascaded"):null;attrNode=node.getAttributeNode("opaque");var opaque=(attrNode&&attrNode.specified)?node.getAttribute('opaque'):null;var noSubsets=node.getAttribute('noSubsets');var fixedWidth=node.getAttribute('fixedWidth');var fixedHeight=node.getAttribute('fixedHeight');var layer={nestedLayers:[],styles:[],srs:{},metadataURLs:[],bbox:{},dimensions:{},authorityURLs:{},identifiers:{},keywords:[],queryable:(queryable&&queryable!=="")?(queryable==="1"||queryable==="true"):null,cascaded:(cascaded!==null)?parseInt(cascaded):null,opaque:opaque?(opaque==="1"||opaque==="true"):null,noSubsets:(noSubsets!==null)?(noSubsets==="1"||noSubsets==="true"):null,fixedWidth:(fixedWidth!=null)?parseInt(fixedWidth):null,fixedHeight:(fixedHeight!=null)?parseInt(fixedHeight):null};obj.nestedLayers.push(layer);this.readChildNodes(node,layer);if(layer.name){var parts=layer.name.split(":");if(parts.length>0){layer.prefix=parts[0];}}},"Attribution":function(node,obj){obj.attribution={};this.readChildNodes(node,obj.attribution);},"LogoURL":function(node,obj){obj.logo={width:node.getAttribute("width"),height:node.getAttribute("height")};this.readChildNodes(node,obj.logo);},"Style":function(node,obj){var style={};obj.styles.push(style);this.readChildNodes(node,style);},"LegendURL":function(node,obj){var legend={width:node.getAttribute("width"),height:node.getAttribute("height")};obj.legend=legend;this.readChildNodes(node,legend);},"MetadataURL":function(node,obj){var metadataURL={type:node.getAttribute("type")};obj.metadataURLs.push(metadataURL);this.readChildNodes(node,metadataURL);},"DataURL":function(node,obj){obj.dataURL={};this.readChildNodes(node,obj.dataURL);},"FeatureListURL":function(node,obj){obj.featureListURL={};this.readChildNodes(node,obj.featureListURL);},"AuthorityURL":function(node,obj){var name=node.getAttribute("name");var authority={};this.readChildNodes(node,authority);obj.authorityURLs[name]=authority.href;},"Identifier":function(node,obj){var authority=node.getAttribute("authority");obj.identifiers[authority]=this.getChildValue(node);},"KeywordList":function(node,obj){this.readChildNodes(node,obj);},"SRS":function(node,obj){obj.srs[this.getChildValue(node)]=true;}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1"});OpenLayers.Format.WMSDescribeLayer.v1_1=OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer,{initialize:function(options){OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var children=root.childNodes;var describelayer=[];var childNode,nodeName;for(var i=0;i<children.length;++i){childNode=children[i];nodeName=childNode.nodeName;if(nodeName=='LayerDescription'){var layerName=childNode.getAttribute('name');var owsType='';var owsURL='';var typeName='';if(childNode.getAttribute('owsType')){owsType=childNode.getAttribute('owsType');owsURL=childNode.getAttribute('owsURL');}else{if(childNode.getAttribute('wfs')!=''){owsType='WFS';owsURL=childNode.getAttribute('wfs');}else if(childNode.getAttribute('wcs')!=''){owsType='WCS';owsURL=childNode.getAttribute('wcs');}}
var query=childNode.getElementsByTagName('Query');if(query.length>0){typeName=query[0].getAttribute('typeName');if(!typeName){typeName=query[0].getAttribute('typename');}}
describelayer.push({layerName:layerName,owsType:owsType,owsURL:owsURL,typeName:typeName});}}
return describelayer;},CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer.v1_1"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',boxCharacteristics:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);var callbacks={"down":this.startBox,"move":this.moveBox,"out":this.removeBox,"up":this.endBox};this.dragHandler=new OpenLayers.Handler.Drag(this,callbacks,{keyMask:this.keyMask});},destroy:function(){if(this.dragHandler){this.dragHandler.destroy();this.dragHandler=null;}
OpenLayers.Handler.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.dragHandler.start);this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox");},moveBox:function(xy){var startX=this.dragHandler.start.x;var startY=this.dragHandler.start.y;var deltaX=Math.abs(startX-xy.x);var deltaY=Math.abs(startY-xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";this.zoomBox.style.left=xy.x<startX?xy.x+"px":startX+"px";this.zoomBox.style.top=xy.y<startY?xy.y+"px":startY+"px";var box=this.getBoxCharacteristics();if(box.newBoxModel){if(xy.x>startX){this.zoomBox.style.width=Math.max(1,deltaX-box.xOffset)+"px";}
if(xy.y>startY){this.zoomBox.style.height=Math.max(1,deltaY-box.yOffset)+"px";}}},endBox:function(end){var result;if(Math.abs(this.dragHandler.start.x-end.x)>5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
this.removeBox();this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;this.boxCharacteristics=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox");},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragHandler.deactivate();return true;}else{return false;}},getBoxCharacteristics:function(){if(!this.boxCharacteristics){var xOffset=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"))+parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width"))+1;var yOffset=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width"))+parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"))+1;var newBoxModel=OpenLayers.Util.getBrowserName()=="msie"?document.compatMode!="BackCompat":true;this.boxCharacteristics={xOffset:xOffset,yOffset:yOffset,newBoxModel:newBoxModel};}
return this.boxCharacteristics;},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:'shiftKey',layerOptions:null,persist:false,irregular:false,angle:null,fixedRadius:false,feature:null,layer:null,origin:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
OpenLayers.Handler.prototype.initialize.apply(this,[control,callbacks,options]);this.options=(options)?options:{};},setOptions:function(newOptions){OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);activated=true;}
return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)){if(this.dragging){this.cancel();}
if(this.layer.map!=null){this.layer.destroy(false);if(this.feature){this.feature.destroy();}}
this.layer=null;this.feature=null;deactivated=true;}
return deactivated;},down:function(evt){this.fixedRadius=!!(this.radius);var maploc=this.map.getLonLatFromPixel(evt.xy);this.origin=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(!this.fixedRadius||this.irregular){this.radius=this.map.getResolution();}
if(this.persist){this.clear();}
this.feature=new OpenLayers.Feature.Vector();this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],{silent:true});this.layer.drawFeature(this.feature,this.style);},move:function(evt){var maploc=this.map.getLonLatFromPixel(evt.xy);var point=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(this.irregular){var ry=Math.sqrt(2)*Math.abs(point.y-this.origin.y)/2;this.radius=Math.max(this.map.getResolution()/2,ry);}else if(this.fixedRadius){this.origin=point;}else{this.calculateAngle(point,evt);this.radius=Math.max(this.map.getResolution()/2,point.distanceTo(this.origin));}
this.modifyGeometry();if(this.irregular){var dx=point.x-this.origin.x;var dy=point.y-this.origin.y;var ratio;if(dy==0){ratio=dx/(this.radius*Math.sqrt(2));}else{ratio=dx/dy;}
this.feature.geometry.resize(1,this.origin,ratio);this.feature.geometry.move(dx/2,dy/2);}
this.layer.drawFeature(this.feature,this.style);},up:function(evt){this.finalize();if(this.start==this.last){this.callback("done",[evt.xy]);}},out:function(evt){this.finalize();},createGeometry:function(){this.angle=Math.PI*((1/this.sides)-(1/2));if(this.snapAngle){this.angle+=this.snapAngle*(Math.PI/180);}
this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,this.sides,this.snapAngle);},modifyGeometry:function(){var angle,point;var ring=this.feature.geometry.components[0];if(ring.components.length!=(this.sides+1)){this.createGeometry();ring=this.feature.geometry.components[0];}
for(var i=0;i<this.sides;++i){point=ring.components[i];angle=this.angle+(i*2*Math.PI/this.sides);point.x=this.origin.x+(this.radius*Math.cos(angle));point.y=this.origin.y+(this.radius*Math.sin(angle));point.clearBounds();}},calculateAngle:function(point,evt){var alpha=Math.atan2(point.y-this.origin.y,point.x-this.origin.x);if(this.snapAngle&&(this.snapToggle&&!evt[this.snapToggle])){var snapAngleRad=(Math.PI/180)*this.snapAngle;this.angle=Math.round(alpha/snapAngleRad)*snapAngleRad;}else{this.angle=alpha;}},cancel:function(){this.callback("cancel",null);this.finalize();},finalize:function(){this.origin=null;this.radius=this.options.radius;},clear:function(){if(this.layer){this.layer.renderer.clear();this.layer.destroyFeatures();}},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,[this.feature.geometry.clone()]);}
if(!this.persist&&(name=="done"||name=="cancel")){this.clear();}},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Layer.EventPane=OpenLayers.Class(OpenLayers.Layer,{smoothDragPan:true,isBaseLayer:true,isFixed:true,pane:null,mapObject:null,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(this.pane==null){this.pane=OpenLayers.Util.createDiv(this.div.id+"_EventPane");}},destroy:function(){this.mapObject=null;this.pane=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Layer.prototype.setMap.apply(this,arguments);this.pane.style.zIndex=parseInt(this.div.style.zIndex)+1;this.pane.style.display=this.div.style.display;this.pane.style.width="100%";this.pane.style.height="100%";if(OpenLayers.Util.getBrowserName()=="msie"){this.pane.style.background="url("+OpenLayers.Util.getImagesLocation()+"blank.gif)";}
if(this.isFixed){this.map.viewPortDiv.appendChild(this.pane);}else{this.map.layerContainerDiv.appendChild(this.pane);}
this.loadMapObject();if(this.mapObject==null){this.loadWarningMessage();}},removeMap:function(map){if(this.pane&&this.pane.parentNode){this.pane.parentNode.removeChild(this.pane);}
OpenLayers.Layer.prototype.removeMap.apply(this,arguments);},loadWarningMessage:function(){this.div.style.backgroundColor="darkblue";var viewSize=this.map.getSize();var msgW=Math.min(viewSize.w,300);var msgH=Math.min(viewSize.h,200);var size=new OpenLayers.Size(msgW,msgH);var centerPx=new OpenLayers.Pixel(viewSize.w/2,viewSize.h/2);var topLeft=centerPx.add(-size.w/2,-size.h/2);var div=OpenLayers.Util.createDiv(this.name+"_warning",topLeft,size,null,null,null,"auto");div.style.padding="7px";div.style.backgroundColor="yellow";div.innerHTML=this.getWarningHTML();this.div.appendChild(div);},getWarningHTML:function(){return"";},display:function(display){OpenLayers.Layer.prototype.display.apply(this,arguments);this.pane.style.display=this.div.style.display;},setZIndex:function(zIndex){OpenLayers.Layer.prototype.setZIndex.apply(this,arguments);this.pane.style.zIndex=parseInt(this.div.style.zIndex)+1;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);if(this.mapObject!=null){var newCenter=this.map.getCenter();var newZoom=this.map.getZoom();if(newCenter!=null){var moOldCenter=this.getMapObjectCenter();var oldCenter=this.getOLLonLatFromMapObjectLonLat(moOldCenter);var moOldZoom=this.getMapObjectZoom();var oldZoom=this.getOLZoomFromMapObjectZoom(moOldZoom);if(!(newCenter.equals(oldCenter))||!(newZoom==oldZoom)){if(dragging&&this.dragPanMapObject&&this.smoothDragPan){var oldPx=this.map.getViewPortPxFromLonLat(oldCenter);var newPx=this.map.getViewPortPxFromLonLat(newCenter);this.dragPanMapObject(newPx.x-oldPx.x,oldPx.y-newPx.y);}else{var center=this.getMapObjectLonLatFromOLLonLat(newCenter);var zoom=this.getMapObjectZoomFromOLZoom(newZoom);this.setMapObjectCenter(center,zoom,dragging);}}}}},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if((this.mapObject!=null)&&(this.getMapObjectCenter()!=null)){var moPixel=this.getMapObjectPixelFromOLPixel(viewPortPx);var moLonLat=this.getMapObjectLonLatFromMapObjectPixel(moPixel);lonlat=this.getOLLonLatFromMapObjectLonLat(moLonLat);}
return lonlat;},getViewPortPxFromLonLat:function(lonlat){var viewPortPx=null;if((this.mapObject!=null)&&(this.getMapObjectCenter()!=null)){var moLonLat=this.getMapObjectLonLatFromOLLonLat(lonlat);var moPixel=this.getMapObjectPixelFromMapObjectLonLat(moLonLat);viewPortPx=this.getOLPixelFromMapObjectPixel(moPixel);}
return viewPortPx;},getOLLonLatFromMapObjectLonLat:function(moLonLat){var olLonLat=null;if(moLonLat!=null){var lon=this.getLongitudeFromMapObjectLonLat(moLonLat);var lat=this.getLatitudeFromMapObjectLonLat(moLonLat);olLonLat=new OpenLayers.LonLat(lon,lat);}
return olLonLat;},getMapObjectLonLatFromOLLonLat:function(olLonLat){var moLatLng=null;if(olLonLat!=null){moLatLng=this.getMapObjectLonLatFromLonLat(olLonLat.lon,olLonLat.lat);}
return moLatLng;},getOLPixelFromMapObjectPixel:function(moPixel){var olPixel=null;if(moPixel!=null){var x=this.getXFromMapObjectPixel(moPixel);var y=this.getYFromMapObjectPixel(moPixel);olPixel=new OpenLayers.Pixel(x,y);}
return olPixel;},getMapObjectPixelFromOLPixel:function(olPixel){var moPixel=null;if(olPixel!=null){moPixel=this.getMapObjectPixelFromXY(olPixel.x,olPixel.y);}
return moPixel;},CLASS_NAME:"OpenLayers.Layer.EventPane"});OpenLayers.Layer.FixedZoomLevels=OpenLayers.Class({initialize:function(){},initResolutions:function(){var props=new Array('minZoomLevel','maxZoomLevel','numZoomLevels');for(var i=0,len=props.length;i<len;i++){var property=props[i];this[property]=(this.options[property]!=null)?this.options[property]:this.map[property];}
if((this.minZoomLevel==null)||(this.minZoomLevel<this.MIN_ZOOM_LEVEL)){this.minZoomLevel=this.MIN_ZOOM_LEVEL;}
var desiredZoomLevels;var limitZoomLevels=this.MAX_ZOOM_LEVEL-this.minZoomLevel+1;if(((this.options.numZoomLevels==null)&&(this.options.maxZoomLevel!=null))||((this.numZoomLevels==null)&&(this.maxZoomLevel!=null))){desiredZoomLevels=this.maxZoomLevel-this.minZoomLevel+1;}else{desiredZoomLevels=this.numZoomLevels;}
if(desiredZoomLevels!=null){this.numZoomLevels=Math.min(desiredZoomLevels,limitZoomLevels);}else{this.numZoomLevels=limitZoomLevels;}
this.maxZoomLevel=this.minZoomLevel+this.numZoomLevels-1;if(this.RESOLUTIONS!=null){var resolutionsIndex=0;this.resolutions=[];for(var i=this.minZoomLevel;i<=this.maxZoomLevel;i++){this.resolutions[resolutionsIndex++]=this.RESOLUTIONS[i];}
this.maxResolution=this.resolutions[0];this.minResolution=this.resolutions[this.resolutions.length-1];}},getResolution:function(){if(this.resolutions!=null){return OpenLayers.Layer.prototype.getResolution.apply(this,arguments);}else{var resolution=null;var viewSize=this.map.getSize();var extent=this.getExtent();if((viewSize!=null)&&(extent!=null)){resolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);}
return resolution;}},getExtent:function(){var extent=null;var size=this.map.getSize();var tlPx=new OpenLayers.Pixel(0,0);var tlLL=this.getLonLatFromViewPortPx(tlPx);var brPx=new OpenLayers.Pixel(size.w,size.h);var brLL=this.getLonLatFromViewPortPx(brPx);if((tlLL!=null)&&(brLL!=null)){extent=new OpenLayers.Bounds(tlLL.lon,brLL.lat,brLL.lon,tlLL.lat);}
return extent;},getZoomForResolution:function(resolution){if(this.resolutions!=null){return OpenLayers.Layer.prototype.getZoomForResolution.apply(this,arguments);}else{var extent=OpenLayers.Layer.prototype.getExtent.apply(this,[]);return this.getZoomForExtent(extent);}},getOLZoomFromMapObjectZoom:function(moZoom){var zoom=null;if(moZoom!=null){zoom=moZoom-this.minZoomLevel;}
return zoom;},getMapObjectZoomFromOLZoom:function(olZoom){var zoom=null;if(olZoom!=null){zoom=olZoom+this.minZoomLevel;}
return zoom;},CLASS_NAME:"OpenLayers.Layer.FixedZoomLevels"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){var newArguments=arguments;newArguments=[name,options];OpenLayers.Layer.prototype.initialize.apply(this,newArguments);this.url=url;this.params=OpenLayers.Util.extend({},params);},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);var ret=this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"params"});}
return ret;},redraw:function(force){if(force){return this.mergeNewParams({"_olSalt":Math.random()});}else{return OpenLayers.Layer.prototype.redraw.apply(this,[]);}},selectUrl:function(paramString,urls){var product=1;for(var i=0,len=paramString.length;i<len;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
paramsString=OpenLayers.Util.getParameterString(allParams);return OpenLayers.Util.urlAppend(url,paramsString);},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Layer.Image=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:true,url:null,extent:null,size:null,tile:null,aspectRatio:null,initialize:function(name,url,extent,size,options){this.url=url;this.extent=extent;this.maxExtent=extent;this.size=size;OpenLayers.Layer.prototype.initialize.apply(this,[name,options]);this.aspectRatio=(this.extent.getHeight()/this.size.h)/(this.extent.getWidth()/this.size.w);},destroy:function(){if(this.tile){this.removeTileMonitoringHooks(this.tile);this.tile.destroy();this.tile=null;}
OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Image(this.name,this.url,this.extent,this.size,this.getOptions());}
obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setMap:function(map){if(this.options.maxResolution==null){this.options.maxResolution=this.aspectRatio*this.extent.getWidth()/this.size.w;}
OpenLayers.Layer.prototype.setMap.apply(this,arguments);},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var firstRendering=(this.tile==null);if(zoomChanged||firstRendering){this.setTileSize();var ul=new OpenLayers.LonLat(this.extent.left,this.extent.top);var ulPx=this.map.getLayerPxFromLonLat(ul);if(firstRendering){this.tile=new OpenLayers.Tile.Image(this,ulPx,this.extent,null,this.tileSize);this.addTileMonitoringHooks(this.tile);}else{this.tile.size=this.tileSize.clone();this.tile.position=ulPx.clone();}
this.tile.draw();}},setTileSize:function(){var tileWidth=this.extent.getWidth()/this.map.getResolution();var tileHeight=this.extent.getHeight()/this.map.getResolution();this.tileSize=new OpenLayers.Size(tileWidth,tileHeight);},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){this.events.triggerEvent("loadstart");};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.events.triggerEvent("loadend");};tile.events.register("loadend",this,tile.onLoadEnd);tile.events.register("unload",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,scope:this});},setUrl:function(newUrl){this.url=newUrl;this.tile.draw();},getURL:function(bounds){return this.url;},CLASS_NAME:"OpenLayers.Layer.Image"});OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,markers:null,drawn:false,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[];},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0,len=this.markers.length;i<len;i++){this.markers[i].setOpacity(this.opacity);}}},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);if(zoomChanged||!this.drawn){for(var i=0,len=this.markers.length;i<len;i++){this.drawMarker(this.markers[i]);}
this.drawn=true;}},addMarker:function(marker){this.markers.push(marker);if(this.opacity!=null){marker.setOpacity(this.opacity);}
if(this.map&&this.map.getExtent()){marker.map=this.map;this.drawMarker(marker);}},removeMarker:function(marker){if(this.markers&&this.markers.length){OpenLayers.Util.removeItem(this.markers,marker);marker.erase();}},clearMarkers:function(){if(this.markers!=null){while(this.markers.length>0){this.removeMarker(this.markers[0]);}}},drawMarker:function(marker){var px=this.map.getLayerPxFromLonLat(marker.lonlat);if(px==null){marker.display(false);}else{if(!marker.isDrawn()){var markerImg=marker.draw(px);this.div.appendChild(markerImg);}else if(marker.icon){marker.icon.moveTo(px);}}},getDataExtent:function(){var maxExtent=null;if(this.markers&&(this.markers.length>0)){var maxExtent=new OpenLayers.Bounds();for(var i=0,len=this.markers.length;i<len;i++){var marker=this.markers[i];maxExtent.extend(marker.lonlat);}}
return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Layer.SphericalMercator={getExtent:function(){var extent=null;if(this.sphericalMercator){extent=this.map.calculateBounds();}else{extent=OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);}
return extent;},getLonLatFromViewPortPx:function(viewPortPx){return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this,arguments);},getViewPortPxFromLonLat:function(lonlat){return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this,arguments);},initMercatorParameters:function(){this.RESOLUTIONS=[];var maxResolution=156543.0339;for(var zoom=0;zoom<=this.MAX_ZOOM_LEVEL;++zoom){this.RESOLUTIONS[zoom]=maxResolution/Math.pow(2,zoom);}
this.units="m";this.projection=this.projection||"EPSG:900913";},forwardMercator:function(lon,lat){var x=lon*20037508.34/180;var y=Math.log(Math.tan((90+lat)*Math.PI/360))/(Math.PI/180);y=y*20037508.34/180;return new OpenLayers.LonLat(x,y);},inverseMercator:function(x,y){var lon=(x/20037508.34)*180;var lat=(y/20037508.34)*180;lat=180/Math.PI*(2*Math.atan(Math.exp(lat*Math.PI/180))-Math.PI/2);return new OpenLayers.LonLat(lon,lat);},projectForward:function(point){var lonlat=OpenLayers.Layer.SphericalMercator.forwardMercator(point.x,point.y);point.x=lonlat.lon;point.y=lonlat.lat;return point;},projectInverse:function(point){var lonlat=OpenLayers.Layer.SphericalMercator.inverseMercator(point.x,point.y);point.x=lonlat.lon;point.y=lonlat.lat;return point;}};OpenLayers.Projection.addTransform("EPSG:4326","EPSG:900913",OpenLayers.Layer.SphericalMercator.projectForward);OpenLayers.Projection.addTransform("EPSG:900913","EPSG:4326",OpenLayers.Layer.SphericalMercator.projectInverse);OpenLayers.Tile.WFS=OpenLayers.Class(OpenLayers.Tile,{features:null,url:null,request:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.features=[];},destroy:function(){OpenLayers.Tile.prototype.destroy.apply(this,arguments);this.destroyAllFeatures();this.features=null;this.url=null;if(this.request){this.request.abort();this.request=null;}},clear:function(){this.destroyAllFeatures();},draw:function(){if(OpenLayers.Tile.prototype.draw.apply(this,arguments)){if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
this.loadFeaturesForRegion(this.requestSuccess);}},loadFeaturesForRegion:function(success,failure){if(this.request){this.request.abort();}
this.request=OpenLayers.Request.GET({url:this.url,success:success,failure:failure,scope:this});},requestSuccess:function(request){if(this.features){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
if(this.layer.vectorMode){this.layer.addFeatures(this.layer.formatObject.read(doc));}else{var xml=new OpenLayers.Format.XML();if(typeof doc=="string"){doc=xml.read(doc);}
var resultFeatures=xml.getElementsByTagNameNS(doc,"http://www.opengis.net/gml","featureMember");this.addResults(resultFeatures);}}
if(this.events){this.events.triggerEvent("loadend");}
this.request=null;},addResults:function(results){for(var i=0;i<results.length;i++){var feature=new this.layer.featureClass(this.layer,results[i]);this.features.push(feature);}},destroyAllFeatures:function(){while(this.features.length>0){var feature=this.features.shift();feature.destroy();}},CLASS_NAME:"OpenLayers.Tile.WFS"});OpenLayers.Control.DrawFeature=OpenLayers.Class(OpenLayers.Control,{layer:null,callbacks:null,EVENT_TYPES:["featureadded"],multi:false,featureAdded:function(){},handlerOptions:null,initialize:function(layer,handler,options){this.EVENT_TYPES=OpenLayers.Control.DrawFeature.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);this.callbacks=OpenLayers.Util.extend({done:this.drawFeature,modify:function(vertex,feature){this.layer.events.triggerEvent("sketchmodified",{vertex:vertex,feature:feature});},create:function(vertex,feature){this.layer.events.triggerEvent("sketchstarted",{vertex:vertex,feature:feature});}},this.callbacks);this.layer=layer;this.handlerOptions=this.handlerOptions||{};if(!("multi"in this.handlerOptions)){this.handlerOptions.multi=this.multi;}
var sketchStyle=this.layer.styleMap&&this.layer.styleMap.styles.temporary;if(sketchStyle){this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":sketchStyle})});}
this.handler=new handler(this,this.callbacks,this.handlerOptions);},drawFeature:function(geometry){var feature=new OpenLayers.Feature.Vector(geometry);var proceed=this.layer.events.triggerEvent("sketchcomplete",{feature:feature});if(proceed!==false){feature.state=OpenLayers.State.INSERT;this.layer.addFeatures([feature]);this.featureAdded(feature);this.events.triggerEvent("featureadded",{feature:feature});}},CLASS_NAME:"OpenLayers.Control.DrawFeature"});OpenLayers.Control.Measure=OpenLayers.Class(OpenLayers.Control,{EVENT_TYPES:['measure','measurepartial'],handlerOptions:null,callbacks:null,displaySystem:'metric',geodesic:false,displaySystemUnits:{geographic:['dd'],english:['mi','ft','in'],metric:['km','m']},partialDelay:300,delayedTrigger:null,persist:false,initialize:function(handler,options){this.EVENT_TYPES=OpenLayers.Control.Measure.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);this.callbacks=OpenLayers.Util.extend({done:this.measureComplete,point:this.measurePartial},this.callbacks);this.handlerOptions=OpenLayers.Util.extend({persist:this.persist},this.handlerOptions);this.handler=new handler(this,this.callbacks,this.handlerOptions);},cancel:function(){this.handler.cancel();},updateHandler:function(handler,options){var active=this.active;if(active){this.deactivate();}
this.handler=new handler(this,this.callbacks,options);if(active){this.activate();}},measureComplete:function(geometry){if(this.delayedTrigger){window.clearTimeout(this.delayedTrigger);}
this.measure(geometry,"measure");},measurePartial:function(point,geometry){if(geometry.getLength()>0){geometry=geometry.clone();this.delayedTrigger=window.setTimeout(OpenLayers.Function.bind(function(){this.measure(geometry,"measurepartial");},this),this.partialDelay);}},measure:function(geometry,eventType){var stat,order;if(geometry.CLASS_NAME.indexOf('LineString')>-1){stat=this.getBestLength(geometry);order=1;}else{stat=this.getBestArea(geometry);order=2;}
this.events.triggerEvent(eventType,{measure:stat[0],units:stat[1],order:order,geometry:geometry});},getBestArea:function(geometry){var units=this.displaySystemUnits[this.displaySystem];var unit,area;for(var i=0,len=units.length;i<len;++i){unit=units[i];area=this.getArea(geometry,unit);if(area>1){break;}}
return[area,unit];},getArea:function(geometry,units){var area,geomUnits;if(this.geodesic){area=geometry.getGeodesicArea(this.map.getProjectionObject());geomUnits="m";}else{area=geometry.getArea();geomUnits=this.map.getUnits();}
var inPerDisplayUnit=OpenLayers.INCHES_PER_UNIT[units];if(inPerDisplayUnit){var inPerMapUnit=OpenLayers.INCHES_PER_UNIT[geomUnits];area*=Math.pow((inPerMapUnit/inPerDisplayUnit),2);}
return area;},getBestLength:function(geometry){var units=this.displaySystemUnits[this.displaySystem];var unit,length;for(var i=0,len=units.length;i<len;++i){unit=units[i];length=this.getLength(geometry,unit);if(length>1){break;}}
return[length,unit];},getLength:function(geometry,units){var length,geomUnits;if(this.geodesic){length=geometry.getGeodesicLength(this.map.getProjectionObject());geomUnits="m";}else{length=geometry.getLength();geomUnits=this.map.getUnits();}
var inPerDisplayUnit=OpenLayers.INCHES_PER_UNIT[units];if(inPerDisplayUnit){var inPerMapUnit=OpenLayers.INCHES_PER_UNIT[geomUnits];length*=(inPerMapUnit/inPerDisplayUnit);}
return length;},CLASS_NAME:"OpenLayers.Control.Measure"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,alwaysZoom:false,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var bounds;if(!this.out){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);}else{var pixWidth=Math.abs(position.right-position.left);var pixHeight=Math.abs(position.top-position.bottom);var zoomFactor=Math.min((this.map.size.h/pixHeight),(this.map.size.w/pixWidth));var extent=this.map.getExtent();var center=this.map.getLonLatFromPixel(position.getCenterPixel());var xmin=center.lon-(extent.getWidth()/2)*zoomFactor;var xmax=center.lon+(extent.getWidth()/2)*zoomFactor;var ymin=center.lat-(extent.getHeight()/2)*zoomFactor;var ymax=center.lat+(extent.getHeight()/2)*zoomFactor;bounds=new OpenLayers.Bounds(xmin,ymin,xmax,ymax);}
var lastZoom=this.map.getZoom();this.map.zoomToExtent(bounds);if(lastZoom==this.map.getZoom()&&this.alwaysZoom==true){this.map.zoomTo(lastZoom+(this.out?-1:1));}}else{if(!this.out){this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()+1);}else{this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()-1);}}},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Format.WFSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{initialize:function(options){OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(this,[options]);},read_cap_Service:function(capabilities,node){var service={};this.runChildNodes(service,node);capabilities.service=service;},read_cap_Fees:function(service,node){var fees=this.getChildValue(node);if(fees&&fees.toLowerCase()!="none"){service.fees=fees;}},read_cap_AccessConstraints:function(service,node){var constraints=this.getChildValue(node);if(constraints&&constraints.toLowerCase()!="none"){service.accessConstraints=constraints;}},read_cap_OnlineResource:function(service,node){var onlineResource=this.getChildValue(node);if(onlineResource&&onlineResource.toLowerCase()!="none"){service.onlineResource=onlineResource;}},read_cap_Keywords:function(service,node){var keywords=this.getChildValue(node);if(keywords&&keywords.toLowerCase()!="none"){service.keywords=keywords.split(', ');}},read_cap_Capability:function(capabilities,node){var capability={};this.runChildNodes(capability,node);capabilities.capability=capability;},read_cap_Request:function(obj,node){var request={};this.runChildNodes(request,node);obj.request=request;},read_cap_GetFeature:function(request,node){var getfeature={href:{},formats:[]};this.runChildNodes(getfeature,node);request.getfeature=getfeature;},read_cap_ResultFormat:function(obj,node){var children=node.childNodes;var childNode;for(var i=0;i<children.length;i++){childNode=children[i];if(childNode.nodeType==1){obj.formats.push(childNode.nodeName);}}},read_cap_DCPType:function(obj,node){this.runChildNodes(obj,node);},read_cap_HTTP:function(obj,node){this.runChildNodes(obj.href,node);},read_cap_Get:function(obj,node){obj.get=node.getAttribute("onlineResource");},read_cap_Post:function(obj,node){obj.post=node.getAttribute("onlineResource");},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_0_0"});OpenLayers.Format.WFSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{initialize:function(options){OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(this,[options]);},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_1_0"});OpenLayers.Format.WKT=OpenLayers.Class(OpenLayers.Format,{initialize:function(options){this.regExes={'typeStr':/^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,'spaces':/\s+/,'parenComma':/\)\s*,\s*\(/,'doubleParenComma':/\)\s*\)\s*,\s*\(\s*\(/,'trimParens':/^\s*\(?(.*?)\)?\s*$/};OpenLayers.Format.prototype.initialize.apply(this,[options]);},read:function(wkt){var features,type,str;var matches=this.regExes.typeStr.exec(wkt);if(matches){type=matches[1].toLowerCase();str=matches[2];if(this.parse[type]){features=this.parse[type].apply(this,[str]);}
if(this.internalProjection&&this.externalProjection){if(features&&features.CLASS_NAME=="OpenLayers.Feature.Vector"){features.geometry.transform(this.externalProjection,this.internalProjection);}else if(features&&type!="geometrycollection"&&typeof features=="object"){for(var i=0,len=features.length;i<len;i++){var component=features[i];component.geometry.transform(this.externalProjection,this.internalProjection);}}}}
return features;},write:function(features){var collection,geometry,type,data,isCollection;if(features.constructor==Array){collection=features;isCollection=true;}else{collection=[features];isCollection=false;}
var pieces=[];if(isCollection){pieces.push('GEOMETRYCOLLECTION(');}
for(var i=0,len=collection.length;i<len;++i){if(isCollection&&i>0){pieces.push(',');}
geometry=collection[i].geometry;type=geometry.CLASS_NAME.split('.')[2].toLowerCase();if(!this.extract[type]){return null;}
if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
data=this.extract[type].apply(this,[geometry]);pieces.push(type.toUpperCase()+'('+data+')');}
if(isCollection){pieces.push(')');}
return pieces.join('');},extract:{'point':function(point){return point.x+' '+point.y;},'multipoint':function(multipoint){var array=[];for(var i=0,len=multipoint.components.length;i<len;++i){array.push('('+
this.extract.point.apply(this,[multipoint.components[i]])+')');}
return array.join(',');},'linestring':function(linestring){var array=[];for(var i=0,len=linestring.components.length;i<len;++i){array.push(this.extract.point.apply(this,[linestring.components[i]]));}
return array.join(',');},'multilinestring':function(multilinestring){var array=[];for(var i=0,len=multilinestring.components.length;i<len;++i){array.push('('+
this.extract.linestring.apply(this,[multilinestring.components[i]])+')');}
return array.join(',');},'polygon':function(polygon){var array=[];for(var i=0,len=polygon.components.length;i<len;++i){array.push('('+
this.extract.linestring.apply(this,[polygon.components[i]])+')');}
return array.join(',');},'multipolygon':function(multipolygon){var array=[];for(var i=0,len=multipolygon.components.length;i<len;++i){array.push('('+
this.extract.polygon.apply(this,[multipolygon.components[i]])+')');}
return array.join(',');}},parse:{'point':function(str){var coords=OpenLayers.String.trim(str).split(this.regExes.spaces);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(coords[0],coords[1]));},'multipoint':function(str){var point;var points=OpenLayers.String.trim(str).split(this.regExes.parenComma);var components=[];for(var i=0,len=points.length;i<len;++i){point=points[i].replace(this.regExes.trimParens,'$1');components.push(this.parse.point.apply(this,[point]).geometry);}
return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPoint(components));},'linestring':function(str){var points=OpenLayers.String.trim(str).split(',');var components=[];for(var i=0,len=points.length;i<len;++i){components.push(this.parse.point.apply(this,[points[i]]).geometry);}
return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(components));},'multilinestring':function(str){var line;var lines=OpenLayers.String.trim(str).split(this.regExes.parenComma);var components=[];for(var i=0,len=lines.length;i<len;++i){line=lines[i].replace(this.regExes.trimParens,'$1');components.push(this.parse.linestring.apply(this,[line]).geometry);}
return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiLineString(components));},'polygon':function(str){var ring,linestring,linearring;var rings=OpenLayers.String.trim(str).split(this.regExes.parenComma);var components=[];for(var i=0,len=rings.length;i<len;++i){ring=rings[i].replace(this.regExes.trimParens,'$1');linestring=this.parse.linestring.apply(this,[ring]).geometry;linearring=new OpenLayers.Geometry.LinearRing(linestring.components);components.push(linearring);}
return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon(components));},'multipolygon':function(str){var polygon;var polygons=OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);var components=[];for(var i=0,len=polygons.length;i<len;++i){polygon=polygons[i].replace(this.regExes.trimParens,'$1');components.push(this.parse.polygon.apply(this,[polygon]).geometry);}
return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPolygon(components));},'geometrycollection':function(str){str=str.replace(/,\s*([A-Za-z])/g,'|$1');var wktArray=OpenLayers.String.trim(str).split('|');var components=[];for(var i=0,len=wktArray.length;i<len;++i){components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));}
return components;}},CLASS_NAME:"OpenLayers.Format.WKT"});OpenLayers.Format.WMC.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ol:"http://openlayers.org/context",wmc:"http://www.opengis.net/context",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"",getNamespacePrefix:function(uri){var prefix=null;if(uri==null){prefix=this.namespaces[this.defaultPrefix];}else{for(prefix in this.namespaces){if(this.namespaces[prefix]==uri){break;}}}
return prefix;},defaultPrefix:"wmc",rootPrefix:null,defaultStyleName:"",defaultStyleTitle:"Default",initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;this.rootPrefix=root.prefix;var context={version:root.getAttribute("version")};this.runChildNodes(context,root);return context;},runChildNodes:function(obj,node){var children=node.childNodes;var childNode,processor,prefix,local;for(var i=0,len=children.length;i<len;++i){childNode=children[i];if(childNode.nodeType==1){prefix=this.getNamespacePrefix(childNode.namespaceURI);local=childNode.nodeName.split(":").pop();processor=this["read_"+prefix+"_"+local];if(processor){processor.apply(this,[obj,childNode]);}}}},read_wmc_General:function(context,node){this.runChildNodes(context,node);},read_wmc_BoundingBox:function(context,node){context.projection=node.getAttribute("SRS");context.bounds=new OpenLayers.Bounds(parseFloat(node.getAttribute("minx")),parseFloat(node.getAttribute("miny")),parseFloat(node.getAttribute("maxx")),parseFloat(node.getAttribute("maxy")));},read_wmc_LayerList:function(context,node){context.layersContext=[];this.runChildNodes(context,node);},read_wmc_Layer:function(context,node){var layerContext={visibility:(node.getAttribute("hidden")!="1"),queryable:(node.getAttribute("queryable")=="1"),formats:[],styles:[]};this.runChildNodes(layerContext,node);context.layersContext.push(layerContext);},read_wmc_Extension:function(obj,node){this.runChildNodes(obj,node);},read_ol_units:function(layerContext,node){layerContext.units=this.getChildValue(node);},read_ol_maxExtent:function(obj,node){var bounds=new OpenLayers.Bounds(node.getAttribute("minx"),node.getAttribute("miny"),node.getAttribute("maxx"),node.getAttribute("maxy"));obj.maxExtent=bounds;},read_ol_transparent:function(layerContext,node){layerContext.transparent=this.getChildValue(node);},read_ol_numZoomLevels:function(layerContext,node){layerContext.numZoomLevels=parseInt(this.getChildValue(node));},read_ol_opacity:function(layerContext,node){layerContext.opacity=parseFloat(this.getChildValue(node));},read_ol_singleTile:function(layerContext,node){layerContext.singleTile=(this.getChildValue(node)=="true");},read_ol_tileSize:function(layerContext,node){var obj={"width":node.getAttribute("width"),"height":node.getAttribute("height")};layerContext.tileSize=obj;},read_ol_isBaseLayer:function(layerContext,node){layerContext.isBaseLayer=(this.getChildValue(node)=="true");},read_ol_displayInLayerSwitcher:function(layerContext,node){layerContext.displayInLayerSwitcher=(this.getChildValue(node)=="true");},read_wmc_Server:function(layerContext,node){layerContext.version=node.getAttribute("version");var server={};var links=node.getElementsByTagName("OnlineResource");if(links.length>0){this.read_wmc_OnlineResource(server,links[0]);}
layerContext.url=server.href;},read_wmc_FormatList:function(layerContext,node){this.runChildNodes(layerContext,node);},read_wmc_Format:function(layerContext,node){var format={value:this.getChildValue(node)};if(node.getAttribute("current")=="1"){format.current=true;}
layerContext.formats.push(format);},read_wmc_StyleList:function(layerContext,node){this.runChildNodes(layerContext,node);},read_wmc_Style:function(layerContext,node){var style={};this.runChildNodes(style,node);if(node.getAttribute("current")=="1"){style.current=true;}
layerContext.styles.push(style);},read_wmc_SLD:function(style,node){this.runChildNodes(style,node);},read_sld_StyledLayerDescriptor:function(sld,node){var xml=OpenLayers.Format.XML.prototype.write.apply(this,[node]);sld.body=xml;},read_wmc_OnlineResource:function(obj,node){obj.href=this.getAttributeNS(node,this.namespaces.xlink,"href");},read_wmc_Name:function(obj,node){var name=this.getChildValue(node);if(name){obj.name=name;}},read_wmc_Title:function(obj,node){var title=this.getChildValue(node);if(title){obj.title=title;}},read_wmc_MetadataURL:function(layerContext,node){var metadataURL={};var links=node.getElementsByTagName("OnlineResource");if(links.length>0){this.read_wmc_OnlineResource(metadataURL,links[0]);}
layerContext.metadataURL=metadataURL.href;},read_wmc_Abstract:function(obj,node){var abst=this.getChildValue(node);if(abst){obj["abstract"]=abst;}},read_wmc_LegendURL:function(style,node){var legend={width:node.getAttribute('width'),height:node.getAttribute('height')};var links=node.getElementsByTagName("OnlineResource");if(links.length>0){this.read_wmc_OnlineResource(legend,links[0]);}
style.legend=legend;},write:function(context,options){var root=this.createElementDefaultNS("ViewContext");this.setAttributes(root,{version:this.VERSION,id:(options&&typeof options.id=="string")?options.id:OpenLayers.Util.createUniqueID("OpenLayers_Context_")});this.setAttributeNS(root,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);root.appendChild(this.write_wmc_General(context));root.appendChild(this.write_wmc_LayerList(context));return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},createElementDefaultNS:function(name,childValue,attributes){var node=this.createElementNS(this.namespaces[this.defaultPrefix],name);if(childValue){node.appendChild(this.createTextNode(childValue));}
if(attributes){this.setAttributes(node,attributes);}
return node;},setAttributes:function(node,obj){var value;for(var name in obj){value=obj[name].toString();if(value.match(/[A-Z]/)){this.setAttributeNS(node,null,name,value);}else{node.setAttribute(name,value);}}},write_wmc_General:function(context){var node=this.createElementDefaultNS("General");if(context.size){node.appendChild(this.createElementDefaultNS("Window",null,{width:context.size.w,height:context.size.h}));}
var bounds=context.bounds;node.appendChild(this.createElementDefaultNS("BoundingBox",null,{minx:bounds.left.toPrecision(18),miny:bounds.bottom.toPrecision(18),maxx:bounds.right.toPrecision(18),maxy:bounds.top.toPrecision(18),SRS:context.projection}));node.appendChild(this.createElementDefaultNS("Title",context.title));node.appendChild(this.write_ol_MapExtension(context));return node;},write_ol_MapExtension:function(context){var node=this.createElementDefaultNS("Extension");var bounds=context.maxExtent;if(bounds){var maxExtent=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(maxExtent,{minx:bounds.left.toPrecision(18),miny:bounds.bottom.toPrecision(18),maxx:bounds.right.toPrecision(18),maxy:bounds.top.toPrecision(18)});node.appendChild(maxExtent);}
return node;},write_wmc_LayerList:function(context){var list=this.createElementDefaultNS("LayerList");for(var i=0,len=context.layersContext.length;i<len;++i){list.appendChild(this.write_wmc_Layer(context.layersContext[i]));}
return list;},write_wmc_Layer:function(context){var node=this.createElementDefaultNS("Layer",null,{queryable:context.queryable?"1":"0",hidden:context.visibility?"0":"1"});node.appendChild(this.write_wmc_Server(context));node.appendChild(this.createElementDefaultNS("Name",context.name));node.appendChild(this.createElementDefaultNS("Title",context.title));if(context.metadataURL){node.appendChild(this.write_wmc_MetadataURL(context.metadataURL));}
return node;},write_wmc_LayerExtension:function(context){var node=this.createElementDefaultNS("Extension");var bounds=context.maxExtent;var maxExtent=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(maxExtent,{minx:bounds.left.toPrecision(18),miny:bounds.bottom.toPrecision(18),maxx:bounds.right.toPrecision(18),maxy:bounds.top.toPrecision(18)});node.appendChild(maxExtent);if(context.tileSize&&!context.singleTile){var size=this.createElementNS(this.namespaces.ol,"ol:tileSize");this.setAttributes(size,context.tileSize);node.appendChild(size);}
var properties=["transparent","numZoomLevels","units","isBaseLayer","opacity","displayInLayerSwitcher","singleTile"];var child;for(var i=0,len=properties.length;i<len;++i){child=this.createOLPropertyNode(context,properties[i]);if(child){node.appendChild(child);}}
return node;},createOLPropertyNode:function(obj,prop){var node=null;if(obj[prop]!=null){node=this.createElementNS(this.namespaces.ol,"ol:"+prop);node.appendChild(this.createTextNode(obj[prop].toString()));}
return node;},write_wmc_Server:function(context){var node=this.createElementDefaultNS("Server");this.setAttributes(node,{service:"OGC:WMS",version:context.version});node.appendChild(this.write_wmc_OnlineResource(context.url));return node;},write_wmc_MetadataURL:function(metadataURL){var node=this.createElementDefaultNS("MetadataURL");node.appendChild(this.write_wmc_OnlineResource(metadataURL));return node;},write_wmc_FormatList:function(context){var node=this.createElementDefaultNS("FormatList");for(var i=0,len=context.formats.length;i<len;i++){var format=context.formats[i];node.appendChild(this.createElementDefaultNS("Format",format.value,(format.current&&format.current==true)?{current:"1"}:null));}
return node;},write_wmc_StyleList:function(layer){var node=this.createElementDefaultNS("StyleList");var styles=layer.styles;if(styles&&styles instanceof Array){var sld;for(var i=0,len=styles.length;i<len;i++){var s=styles[i];var style=this.createElementDefaultNS("Style",null,(s.current&&s.current==true)?{current:"1"}:null);if(s.href){sld=this.createElementDefaultNS("SLD");var link=this.write_wmc_OnlineResource(s.href);sld.appendChild(link);sld.appendChild(this.createElementDefaultNS("Name",s.name));if(s.title){sld.appendChild(this.createElementDefaultNS("Title",s.title));}
style.appendChild(sld);}else if(s.body){sld=this.createElementDefaultNS("SLD");var doc=OpenLayers.Format.XML.prototype.read.apply(this,[s.body]);var imported=doc.documentElement;if(sld.ownerDocument&&sld.ownerDocument.importNode){imported=sld.ownerDocument.importNode(imported,true);}
sld.appendChild(imported);sld.appendChild(this.createElementDefaultNS("Name",s.name));if(s.title){sld.appendChild(this.createElementDefaultNS("Title",s.title));}
style.appendChild(sld);}else{style.appendChild(this.createElementDefaultNS("Name",s.name));style.appendChild(this.createElementDefaultNS("Title",s.title));if(s['abstract']){style.appendChild(this.createElementDefaultNS("Abstract",s['abstract']));}}
node.appendChild(style);}}
return node;},write_wmc_OnlineResource:function(href){var node=this.createElementDefaultNS("OnlineResource");this.setAttributeNS(node,this.namespaces.xlink,"xlink:type","simple");this.setAttributeNS(node,this.namespaces.xlink,"xlink:href",href);return node;},CLASS_NAME:"OpenLayers.Format.WMC.v1"});OpenLayers.Format.WMSCapabilities.v1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{"wms":OpenLayers.Util.applyDefaults({"WMT_MS_Capabilities":function(node,obj){this.readChildNodes(node,obj);},"Keyword":function(node,obj){if(obj.keywords){obj.keywords.push(this.getChildValue(node));}},"DescribeLayer":function(node,obj){obj.describelayer={formats:[]};this.readChildNodes(node,obj.describelayer);},"GetLegendGraphic":function(node,obj){obj.getlegendgraphic={formats:[]};this.readChildNodes(node,obj.getlegendgraphic);},"GetStyles":function(node,obj){obj.getstyles={formats:[]};this.readChildNodes(node,obj.getstyles);},"PutStyles":function(node,obj){obj.putstyles={formats:[]};this.readChildNodes(node,obj.putstyles);},"UserDefinedSymbolization":function(node,obj){var userSymbols={supportSLD:parseInt(node.getAttribute("SupportSLD"))==1,userLayer:parseInt(node.getAttribute("UserLayer"))==1,userStyle:parseInt(node.getAttribute("UserStyle"))==1,remoteWFS:parseInt(node.getAttribute("RemoteWFS"))==1};obj.userSymbols=userSymbols;},"LatLonBoundingBox":function(node,obj){obj.llbbox=[parseFloat(node.getAttribute("minx")),parseFloat(node.getAttribute("miny")),parseFloat(node.getAttribute("maxx")),parseFloat(node.getAttribute("maxy"))];},"BoundingBox":function(node,obj){var bbox=OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this,[node,obj]);bbox.srs=node.getAttribute("SRS");obj.bbox[bbox.srs]=bbox;},"ScaleHint":function(node,obj){var min=node.getAttribute("min");var max=node.getAttribute("max");var rad2=Math.pow(2,0.5);var ipm=OpenLayers.INCHES_PER_UNIT["m"];obj.maxScale=parseFloat(((min/rad2)*ipm*OpenLayers.DOTS_PER_INCH).toPrecision(13));obj.minScale=parseFloat(((max/rad2)*ipm*OpenLayers.DOTS_PER_INCH).toPrecision(13));},"Dimension":function(node,obj){var name=node.getAttribute("name").toLowerCase();var dim={name:name,units:node.getAttribute("units"),unitsymbol:node.getAttribute("unitSymbol")};obj.dimensions[dim.name]=dim;},"Extent":function(node,obj){var name=node.getAttribute("name").toLowerCase();if(name in obj["dimensions"]){var extent=obj.dimensions[name];extent.nearestVal=node.getAttribute("nearestValue")==="1";extent.multipleVal=node.getAttribute("multipleValues")==="1";extent.current=node.getAttribute("current")==="1";extent["default"]=node.getAttribute("default")||"";var values=this.getChildValue(node);extent.values=values.split(",");}}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"])},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1"});OpenLayers.Format.WMSCapabilities.v1_3=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{"wms":OpenLayers.Util.applyDefaults({"WMS_Capabilities":function(node,obj){this.readChildNodes(node,obj);},"LayerLimit":function(node,obj){obj.layerLimit=parseInt(this.getChildValue(node));},"MaxWidth":function(node,obj){obj.maxWidth=parseInt(this.getChildValue(node));},"MaxHeight":function(node,obj){obj.maxHeight=parseInt(this.getChildValue(node));},"BoundingBox":function(node,obj){var bbox=OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this,[node,obj]);bbox.srs=node.getAttribute("CRS");obj.bbox[bbox.srs]=bbox;},"CRS":function(node,obj){this.readers.wms.SRS.apply(this,[node,obj]);},"EX_GeographicBoundingBox":function(node,obj){obj.llbbox=[];this.readChildNodes(node,obj.llbbox);},"westBoundLongitude":function(node,obj){obj[0]=this.getChildValue(node);},"eastBoundLongitude":function(node,obj){obj[2]=this.getChildValue(node);},"southBoundLatitude":function(node,obj){obj[1]=this.getChildValue(node);},"northBoundLatitude":function(node,obj){obj[3]=this.getChildValue(node);},"MinScaleDenominator":function(node,obj){obj.maxScale=parseFloat(this.getChildValue(node)).toPrecision(16);},"MaxScaleDenominator":function(node,obj){obj.minScale=parseFloat(this.getChildValue(node)).toPrecision(16);},"Dimension":function(node,obj){var name=node.getAttribute("name").toLowerCase();var dim={name:name,units:node.getAttribute("units"),unitsymbol:node.getAttribute("unitSymbol"),nearestVal:node.getAttribute("nearestValue")==="1",multipleVal:node.getAttribute("multipleValues")==="1","default":node.getAttribute("default")||"",current:node.getAttribute("current")==="1",values:this.getChildValue(node).split(",")};obj.dimensions[dim.name]=dim;},"Keyword":function(node,obj){var keyword={value:this.getChildValue(node),vocabulary:node.getAttribute("vocabulary")};if(obj.keywords){obj.keywords.push(keyword);}}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]),"sld":{"UserDefinedSymbolization":function(node,obj){this.readers.wms.UserDefinedSymbolization.apply(this,[node,obj]);obj.userSymbols.inlineFeature=parseInt(node.getAttribute("InlineFeature"))==1;obj.userSymbols.remoteWCS=parseInt(node.getAttribute("RemoteWCS"))==1;},"DescribeLayer":function(node,obj){this.readers.wms.DescribeLayer.apply(this,[node,obj]);},"GetLegendGraphic":function(node,obj){this.readers.wms.GetLegendGraphic.apply(this,[node,obj]);}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3"});OpenLayers.Format.WMTSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0,{version:"1.0.0",namespaces:{ows:"http://www.opengis.net/ows/1.1",wmts:"http://www.opengis.net/wmts/1.0",xlink:"http://www.w3.org/1999/xlink"},yx:null,defaultPrefix:"wmts",initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;var yx=OpenLayers.Util.extend({},OpenLayers.Format.WMTSCapabilities.prototype.yx);this.yx=OpenLayers.Util.extend(yx,this.yx);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var capabilities={};this.readNode(data,capabilities);capabilities.version=this.version;return capabilities;},readers:{"wmts":{"Capabilities":function(node,obj){this.readChildNodes(node,obj);},"Contents":function(node,obj){obj.contents={};obj.contents.layers=[];obj.contents.tileMatrixSets={};this.readChildNodes(node,obj.contents);},"Layer":function(node,obj){var layer={styles:[],formats:[],tileMatrixSetLinks:[]};layer.layers=[];this.readChildNodes(node,layer);obj.layers.push(layer);},"Style":function(node,obj){var style={};style.isDefault=(node.getAttribute("isDefault")==="true");this.readChildNodes(node,style);obj.styles.push(style);},"Format":function(node,obj){obj.formats.push(this.getChildValue(node));},"TileMatrixSetLink":function(node,obj){var tileMatrixSetLink={};this.readChildNodes(node,tileMatrixSetLink);obj.tileMatrixSetLinks.push(tileMatrixSetLink);},"TileMatrixSet":function(node,obj){if(obj.layers){var tileMatrixSet={matrixIds:[]};this.readChildNodes(node,tileMatrixSet);obj.tileMatrixSets[tileMatrixSet.identifier]=tileMatrixSet;}else{obj.tileMatrixSet=this.getChildValue(node);}},"TileMatrix":function(node,obj){var tileMatrix={supportedCRS:obj.supportedCRS};this.readChildNodes(node,tileMatrix);obj.matrixIds.push(tileMatrix);},"ScaleDenominator":function(node,obj){obj.scaleDenominator=parseFloat(this.getChildValue(node));},"TopLeftCorner":function(node,obj){var topLeftCorner=this.getChildValue(node);var coords=topLeftCorner.split(" ");var yx;if(obj.supportedCRS){var crs=obj.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/,"urn:ogc:def:crs:$1::$2");yx=!!this.yx[crs];}
if(yx){obj.topLeftCorner=new OpenLayers.LonLat(coords[1],coords[0]);}else{obj.topLeftCorner=new OpenLayers.LonLat(coords[0],coords[1]);}},"TileWidth":function(node,obj){obj.tileWidth=parseInt(this.getChildValue(node));},"TileHeight":function(node,obj){obj.tileHeight=parseInt(this.getChildValue(node));},"MatrixWidth":function(node,obj){obj.matrixWidth=parseInt(this.getChildValue(node));},"MatrixHeight":function(node,obj){obj.matrixHeight=parseInt(this.getChildValue(node));},"WSDL":function(node,obj){obj.wsdl={};obj.wsdl.href=node.getAttribute("xlink:href");},"ServiceMetadataURL":function(node,obj){obj.serviceMetadataUrl={};obj.serviceMetadataUrl.href=node.getAttribute("xlink:href");}},"ows":OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"]},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities.v1_0_0"});OpenLayers.Layer.Boxes=OpenLayers.Class(OpenLayers.Layer.Markers,{initialize:function(name,options){OpenLayers.Layer.Markers.prototype.initialize.apply(this,arguments);},drawMarker:function(marker){var bounds=marker.bounds;var topleft=this.map.getLayerPxFromLonLat(new OpenLayers.LonLat(bounds.left,bounds.top));var botright=this.map.getLayerPxFromLonLat(new OpenLayers.LonLat(bounds.right,bounds.bottom));if(botright==null||topleft==null){marker.display(false);}else{var sz=new OpenLayers.Size(Math.max(1,botright.x-topleft.x),Math.max(1,botright.y-topleft.y));var markerDiv=marker.draw(topleft,sz);if(!marker.drawn){this.div.appendChild(markerDiv);marker.drawn=true;}}},removeMarker:function(marker){OpenLayers.Util.removeItem(this.markers,marker);if((marker.div!=null)&&(marker.div.parentNode==this.div)){this.div.removeChild(marker.div);}},CLASS_NAME:"OpenLayers.Layer.Boxes"});OpenLayers.Layer.GeoRSS=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,icon:null,popupSize:null,useFeedTitle:true,initialize:function(name,location,options){OpenLayers.Layer.Markers.prototype.initialize.apply(this,[name,options]);this.location=location;this.features=[];},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null;},loadRSS:function(){if(!this.loaded){this.events.triggerEvent("loadstart");OpenLayers.Request.GET({url:this.location,success:this.parseData,scope:this});this.loaded=true;}},moveTo:function(bounds,zoomChanged,minor){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);if(this.visibility&&!this.loaded){this.loadRSS();}},parseData:function(ajaxRequest){var doc=ajaxRequest.responseXML;if(!doc||!doc.documentElement){doc=OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText);}
if(this.useFeedTitle){var name=null;try{name=doc.getElementsByTagNameNS('*','title')[0].firstChild.nodeValue;}
catch(e){name=doc.getElementsByTagName('title')[0].firstChild.nodeValue;}
if(name){this.setName(name);}}
var options={};OpenLayers.Util.extend(options,this.formatOptions);if(this.map&&!this.projection.equals(this.map.getProjectionObject())){options.externalProjection=this.projection;options.internalProjection=this.map.getProjectionObject();}
var format=new OpenLayers.Format.GeoRSS(options);var features=format.read(doc);for(var i=0,len=features.length;i<len;i++){var data={};var feature=features[i];if(!feature.geometry){continue;}
var title=feature.attributes.title?feature.attributes.title:"Untitled";var description=feature.attributes.description?feature.attributes.description:"No description.";var link=feature.attributes.link?feature.attributes.link:"";var location=feature.geometry.getBounds().getCenterLonLat();data.icon=this.icon==null?OpenLayers.Marker.defaultIcon():this.icon.clone();data.popupSize=this.popupSize?this.popupSize.clone():new OpenLayers.Size(250,120);if(title||description){data.title=title;data.description=description;var contentHTML='<div class="olLayerGeoRSSClose">[x]</div>';contentHTML+='<div class="olLayerGeoRSSTitle">';if(link){contentHTML+='<a class="link" href="'+link+'" target="_blank">';}
contentHTML+=title;if(link){contentHTML+='</a>';}
contentHTML+='</div>';contentHTML+='<div style="" class="olLayerGeoRSSDescription">';contentHTML+=description;contentHTML+='</div>';data['popupContentHTML']=contentHTML;}
var feature=new OpenLayers.Feature(this,location,data);this.features.push(feature);var marker=feature.createMarker();marker.events.register('click',feature,this.markerClick);this.addMarker(marker);}
this.events.triggerEvent("loadend");},markerClick:function(evt){var sameMarkerClicked=(this==this.layer.selectedFeature);this.layer.selectedFeature=(!sameMarkerClicked)?this:null;for(var i=0,len=this.layer.map.popups.length;i<len;i++){this.layer.map.removePopup(this.layer.map.popups[i]);}
if(!sameMarkerClicked){var popup=this.createPopup();OpenLayers.Event.observe(popup.div,"click",OpenLayers.Function.bind(function(){for(var i=0,len=this.layer.map.popups.length;i<len;i++){this.layer.map.removePopup(this.layer.map.popups[i]);}},this));this.layer.map.addPopup(popup);}
OpenLayers.Event.stop(evt);},clearFeatures:function(){if(this.features!=null){while(this.features.length>0){var feature=this.features[0];OpenLayers.Util.removeItem(this.features,feature);feature.destroy();}}},CLASS_NAME:"OpenLayers.Layer.GeoRSS"});OpenLayers.Layer.Google=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:0,MAX_ZOOM_LEVEL:21,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,0.0006866455078125,0.00034332275390625,0.000171661376953125,0.0000858306884765625,0.00004291534423828125,0.00002145767211914062,0.00001072883605957031,0.00000536441802978515,0.00000268220901489257,0.0000013411045074462891,0.00000067055225372314453],type:null,wrapDateLine:true,sphericalMercator:false,version:null,initialize:function(name,options){options=options||{};if(!options.version){options.version=typeof GMap2==="function"?"2":"3";}
var mixin=OpenLayers.Layer.Google["v"+
options.version.replace(/\./g,"_")];if(mixin){OpenLayers.Util.applyDefaults(options,mixin);}else{throw"Unsupported Google Maps API version: "+options.version;}
OpenLayers.Util.applyDefaults(options,mixin.DEFAULTS);if(options.maxExtent){options.maxExtent=options.maxExtent.clone();}
OpenLayers.Layer.EventPane.prototype.initialize.apply(this,[name,options]);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,[name,options]);if(this.sphericalMercator){OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator);this.initMercatorParameters();}},clone:function(){return new OpenLayers.Layer.Google(this.name,this.getOptions());},setVisibility:function(visible){var opacity=this.opacity==null?1:this.opacity;OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this,arguments);this.setOpacity(opacity);},display:function(visible){if(!this._dragging){this.setGMapVisibility(visible);}
OpenLayers.Layer.EventPane.prototype.display.apply(this,arguments);},moveTo:function(bounds,zoomChanged,dragging){this._dragging=dragging;OpenLayers.Layer.EventPane.prototype.moveTo.apply(this,arguments);delete this._dragging;},setOpacity:function(opacity){if(opacity!==this.opacity){if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"});}
this.opacity=opacity;}
if(this.getVisibility()){var container=this.getMapContainer();OpenLayers.Util.modifyDOMElement(container,null,null,null,null,null,null,opacity);}},destroy:function(){if(this.map){this.setGMapVisibility(false);var cache=OpenLayers.Layer.Google.cache[this.map.id];if(cache&&cache.count<=1){this.removeGMapElements();}}
OpenLayers.Layer.EventPane.prototype.destroy.apply(this,arguments);},removeGMapElements:function(){var cache=OpenLayers.Layer.Google.cache[this.map.id];if(cache){var container=this.mapObject&&this.getMapContainer();if(container&&container.parentNode){container.parentNode.removeChild(container);}
var termsOfUse=cache.termsOfUse;if(termsOfUse&&termsOfUse.parentNode){termsOfUse.parentNode.removeChild(termsOfUse);}
var poweredBy=cache.poweredBy;if(poweredBy&&poweredBy.parentNode){poweredBy.parentNode.removeChild(poweredBy);}}},removeMap:function(map){if(this.visibility&&this.mapObject){this.setGMapVisibility(false);}
var cache=OpenLayers.Layer.Google.cache[map.id];if(cache){if(cache.count<=1){this.removeGMapElements();delete OpenLayers.Layer.Google.cache[map.id];}else{--cache.count;}}
delete this.termsOfUse;delete this.poweredBy;delete this.mapObject;delete this.dragObject;OpenLayers.Layer.EventPane.prototype.removeMap.apply(this,arguments);},getOLBoundsFromMapObjectBounds:function(moBounds){var olBounds=null;if(moBounds!=null){var sw=moBounds.getSouthWest();var ne=moBounds.getNorthEast();if(this.sphericalMercator){sw=this.forwardMercator(sw.lng(),sw.lat());ne=this.forwardMercator(ne.lng(),ne.lat());}else{sw=new OpenLayers.LonLat(sw.lng(),sw.lat());ne=new OpenLayers.LonLat(ne.lng(),ne.lat());}
olBounds=new OpenLayers.Bounds(sw.lon,sw.lat,ne.lon,ne.lat);}
return olBounds;},getWarningHTML:function(){return OpenLayers.i18n("googleWarning");},getMapObjectCenter:function(){return this.mapObject.getCenter();},getMapObjectZoom:function(){return this.mapObject.getZoom();},getLongitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.lng(),moLonLat.lat()).lon:moLonLat.lng();},getLatitudeFromMapObjectLonLat:function(moLonLat){var lat=this.sphericalMercator?this.forwardMercator(moLonLat.lng(),moLonLat.lat()).lat:moLonLat.lat();return lat;},getXFromMapObjectPixel:function(moPixel){return moPixel.x;},getYFromMapObjectPixel:function(moPixel){return moPixel.y;},CLASS_NAME:"OpenLayers.Layer.Google"});OpenLayers.Layer.Google.cache={};OpenLayers.Layer.Google.v2={termsOfUse:null,poweredBy:null,dragObject:null,loadMapObject:function(){if(!this.type){this.type=G_NORMAL_MAP;}
var mapObject,termsOfUse,poweredBy;var cache=OpenLayers.Layer.Google.cache[this.map.id];if(cache){mapObject=cache.mapObject;termsOfUse=cache.termsOfUse;poweredBy=cache.poweredBy;++cache.count;}else{var container=this.map.viewPortDiv;var div=document.createElement("div");div.id=this.map.id+"_GMap2Container";div.style.position="absolute";div.style.width="100%";div.style.height="100%";container.appendChild(div);try{mapObject=new GMap2(div);termsOfUse=div.lastChild;container.appendChild(termsOfUse);termsOfUse.style.zIndex="1100";termsOfUse.style.right="";termsOfUse.style.bottom="";termsOfUse.className="olLayerGoogleCopyright";poweredBy=div.lastChild;container.appendChild(poweredBy);poweredBy.style.zIndex="1100";poweredBy.style.right="";poweredBy.style.bottom="";poweredBy.className="olLayerGooglePoweredBy gmnoprint";}catch(e){throw(e);}
OpenLayers.Layer.Google.cache[this.map.id]={mapObject:mapObject,termsOfUse:termsOfUse,poweredBy:poweredBy,count:1};}
this.mapObject=mapObject;this.termsOfUse=termsOfUse;this.poweredBy=poweredBy;if(OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),this.type)===-1){this.mapObject.addMapType(this.type);}
if(typeof mapObject.getDragObject=="function"){this.dragObject=mapObject.getDragObject();}else{this.dragPanMapObject=null;}
if(this.isBaseLayer===false){this.setGMapVisibility(this.div.style.display!=="none");}},onMapResize:function(){if(this.visibility&&this.mapObject.isLoaded()){this.mapObject.checkResize();}else{if(!this._resized){var layer=this;var handle=GEvent.addListener(this.mapObject,"load",function(){GEvent.removeListener(handle);delete layer._resized;layer.mapObject.checkResize();layer.moveTo(layer.map.getCenter(),layer.map.getZoom());});}
this._resized=true;}},setGMapVisibility:function(visible){var cache=OpenLayers.Layer.Google.cache[this.map.id];if(cache){var container=this.mapObject.getContainer();if(visible===true){this.mapObject.setMapType(this.type);container.style.display="";this.termsOfUse.style.left="";this.termsOfUse.style.display="";this.poweredBy.style.display="";cache.displayed=this.id;}else{if(cache.displayed===this.id){delete cache.displayed;}
if(!cache.displayed){container.style.display="none";this.termsOfUse.style.display="none";this.termsOfUse.style.left="-9999px";this.poweredBy.style.display="none";}}}},getMapContainer:function(){return this.mapObject.getContainer();},getMapObjectBoundsFromOLBounds:function(olBounds){var moBounds=null;if(olBounds!=null){var sw=this.sphericalMercator?this.inverseMercator(olBounds.bottom,olBounds.left):new OpenLayers.LonLat(olBounds.bottom,olBounds.left);var ne=this.sphericalMercator?this.inverseMercator(olBounds.top,olBounds.right):new OpenLayers.LonLat(olBounds.top,olBounds.right);moBounds=new GLatLngBounds(new GLatLng(sw.lat,sw.lon),new GLatLng(ne.lat,ne.lon));}
return moBounds;},setMapObjectCenter:function(center,zoom){this.mapObject.setCenter(center,zoom);},dragPanMapObject:function(dX,dY){this.dragObject.moveBy(new GSize(-dX,dY));},getMapObjectLonLatFromMapObjectPixel:function(moPixel){return this.mapObject.fromContainerPixelToLatLng(moPixel);},getMapObjectPixelFromMapObjectLonLat:function(moLonLat){return this.mapObject.fromLatLngToContainerPixel(moLonLat);},getMapObjectZoomFromMapObjectBounds:function(moBounds){return this.mapObject.getBoundsZoomLevel(moBounds);},getMapObjectLonLatFromLonLat:function(lon,lat){var gLatLng;if(this.sphericalMercator){var lonlat=this.inverseMercator(lon,lat);gLatLng=new GLatLng(lonlat.lat,lonlat.lon);}else{gLatLng=new GLatLng(lat,lon);}
return gLatLng;},getMapObjectPixelFromXY:function(x,y){return new GPoint(x,y);}};OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,grid:null,singleTile:false,ratio:1.5,buffer:2,numLoadingTiles:0,initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.events.addEventType("tileloaded");this.grid=[];},destroy:function(){this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){if(this.grid){for(var iRow=0,len=this.grid.length;iRow<len;iRow++){var row=this.grid[iRow];for(var iCol=0,clen=row.length;iCol<clen;iCol++){var tile=row[iCol];this.removeTileMonitoringHooks(tile);tile.destroy();}}
this.grid=[];}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
obj.grid=[];return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){this.initSingleTile(bounds);}}else{if(forceReTile||!tilesBounds.containsBounds(bounds,true)){this.initGriddedTiles(bounds);}else{this.moveGriddedTiles(bounds);}}}},setTileSize:function(size){if(this.singleTile){size=this.map.getSize();size.h=parseInt(size.h*this.ratio);size.w=parseInt(size.w*this.ratio);}
OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getGridBounds:function(){var msg="The getGridBounds() function is deprecated. It will be "+"removed in 3.0. Please use getTilesBounds() instead.";OpenLayers.Console.warn(msg);return this.getTilesBounds();},getTilesBounds:function(){var bounds=null;if(this.grid.length){var bottom=this.grid.length-1;var bottomLeftTile=this.grid[bottom][0];var right=this.grid[0].length-1;var topRightTile=this.grid[0][right];bounds=new OpenLayers.Bounds(bottomLeftTile.bounds.left,bottomLeftTile.bounds.bottom,topRightTile.bounds.right,topRightTile.bounds.top);}
return bounds;},initSingleTile:function(bounds){var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var ul=new OpenLayers.LonLat(tileBounds.left,tileBounds.top);var px=this.map.getLayerPxFromLonLat(ul);if(!this.grid.length){this.grid[0]=[];}
var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
this.removeExcessTiles(1,1);},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=bounds.top-(extent.bottom+tilelat);var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-tilerowremain*this.tileSize.h;var tileoffsetlat=extent.bottom+tilerow*tilelat;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
Math.max(1,2*this.buffer);var minCols=Math.ceil(viewSize.w/this.tileSize.w)+
Math.max(1,2*this.buffer);var extent=this.getMaxExtent();var resolution=this.map.getResolution();var tileLayout=this.calculateGridLayout(bounds,extent,resolution);var tileoffsetx=Math.round(tileLayout.tileoffsetx);var tileoffsety=Math.round(tileLayout.tileoffsety);var tileoffsetlon=tileLayout.tileoffsetlon;var tileoffsetlat=tileLayout.tileoffsetlat;var tilelon=tileLayout.tilelon;var tilelat=tileLayout.tilelat;this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;var layerContainerDivLeft=parseInt(this.map.layerContainerDiv.style.left);var layerContainerDivTop=parseInt(this.map.layerContainerDiv.style.top);do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=layerContainerDivLeft;var y=tileoffsety;y-=layerContainerDivTop;var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols);tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows);this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},getMaxExtent:function(){return this.maxExtent;},spiralTileLoad:function(){var tileQueue=[];var directions=["right","down","left","up"];var iRow=0;var iCell=-1;var direction=OpenLayers.Util.indexOf(directions,"right");var directionsTried=0;while(directionsTried<directions.length){var testRow=iRow;var testCell=iCell;switch(directions[direction]){case"right":testCell++;break;case"down":testRow++;break;case"left":testCell--;break;case"up":testRow--;break;}
var tile=null;if((testRow<this.grid.length)&&(testRow>=0)&&(testCell<this.grid[0].length)&&(testCell>=0)){tile=this.grid[testRow][testCell];}
if((tile!=null)&&(!tile.queued)){tileQueue.unshift(tile);tile.queued=true;directionsTried=0;iRow=testRow;iCell=testCell;}else{direction=(direction+1)%4;directionsTried++;}}
for(var i=0,len=tileQueue.length;i<len;i++){var tile=tileQueue[i];tile.draw();tile.queued=false;}},addTile:function(bounds,position){},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.numLoadingTiles==0){this.events.triggerEvent("loadstart");}
this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);tile.events.register("unload",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,scope:this});},moveGriddedTiles:function(bounds){var buffer=this.buffer||1;while(true){var tlLayer=this.grid[0][0].position;var tlViewPort=this.map.getViewPortPxFromLayerPx(tlLayer);if(tlViewPort.x>-this.tileSize.w*(buffer-1)){this.shiftColumn(true);}else if(tlViewPort.x<-this.tileSize.w*buffer){this.shiftColumn(false);}else if(tlViewPort.y>-this.tileSize.h*(buffer-1)){this.shiftRow(true);}else if(tlViewPort.y<-this.tileSize.h*buffer){this.shiftRow(false);}else{break;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var grid=this.grid;var modelRow=grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?grid.pop():grid.shift();for(var i=0,len=modelRow.length;i<len;i++){var modelTile=modelRow[i];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.bottom=bounds.bottom+deltaLat;bounds.top=bounds.top+deltaLat;position.y=position.y+deltaY;row[i].moveTo(bounds,position);}
if(prepend){grid.unshift(row);}else{grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.map.getResolution();var deltaLon=resolution*deltaX;for(var i=0,len=this.grid.length;i<len;i++){var row=this.grid[i];var modelTileIndex=(prepend)?0:(row.length-1);var modelTile=row[modelTileIndex];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.left=bounds.left+deltaLon;bounds.right=bounds.right+deltaLon;position.x=position.x+deltaX;var tile=prepend?this.grid[i].pop():this.grid[i].shift();tile.moveTo(bounds,position);if(prepend){row.unshift(tile);}else{row.push(tile);}}},removeExcessTiles:function(rows,columns){while(this.grid.length>rows){var row=this.grid.pop();for(var i=0,l=row.length;i<l;i++){var tile=row[i];this.removeTileMonitoringHooks(tile);tile.destroy();}}
while(this.grid[0].length>columns){for(var i=0,l=this.grid.length;i<l;i++){var row=this.grid[i];var tile=row.pop();this.removeTileMonitoringHooks(tile);tile.destroy();}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();}},getTileBounds:function(viewPortPx){var maxExtent=this.maxExtent;var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=maxExtent.left+(tileMapWidth*Math.floor((mapPoint.lon-
maxExtent.left)/tileMapWidth));var tileBottom=maxExtent.bottom+(tileMapHeight*Math.floor((mapPoint.lat-
maxExtent.bottom)/tileMapHeight));return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Layer.MultiMap=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:1,MAX_ZOOM_LEVEL:17,RESOLUTIONS:[9,1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,0.0006866455078125,0.00034332275390625,0.000171661376953125,0.0000858306884765625,0.00004291534423828125],type:null,initialize:function(name,options){OpenLayers.Layer.EventPane.prototype.initialize.apply(this,arguments);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,arguments);if(this.sphericalMercator){OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator);this.initMercatorParameters();this.RESOLUTIONS.unshift(10);}},loadMapObject:function(){try{this.mapObject=new MultimapViewer(this.div);}catch(e){}},getWarningHTML:function(){return OpenLayers.i18n("getLayerWarning",{'layerType':"MM",'layerLib':"MultiMap"});},setMapObjectCenter:function(center,zoom){this.mapObject.goToPosition(center,zoom);},getMapObjectCenter:function(){return this.mapObject.getCurrentPosition();},getMapObjectZoom:function(){return this.mapObject.getZoomFactor();},getMapObjectLonLatFromMapObjectPixel:function(moPixel){moPixel.x=moPixel.x-(this.map.getSize().w/2);moPixel.y=moPixel.y-(this.map.getSize().h/2);return this.mapObject.getMapPositionAt(moPixel);},getMapObjectPixelFromMapObjectLonLat:function(moLonLat){return this.mapObject.geoPosToContainerPixels(moLonLat);},getLongitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.lon,moLonLat.lat).lon:moLonLat.lon;},getLatitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.lon,moLonLat.lat).lat:moLonLat.lat;},getMapObjectLonLatFromLonLat:function(lon,lat){var mmLatLon;if(this.sphericalMercator){var lonlat=this.inverseMercator(lon,lat);mmLatLon=new MMLatLon(lonlat.lat,lonlat.lon);}else{mmLatLon=new MMLatLon(lat,lon);}
return mmLatLon;},getXFromMapObjectPixel:function(moPixel){return moPixel.x;},getYFromMapObjectPixel:function(moPixel){return moPixel.y;},getMapObjectPixelFromXY:function(x,y){return new MMPoint(x,y);},CLASS_NAME:"OpenLayers.Layer.MultiMap"});OpenLayers.Layer.VirtualEarth=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:1,MAX_ZOOM_LEVEL:19,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,0.0006866455078125,0.00034332275390625,0.000171661376953125,0.0000858306884765625,0.00004291534423828125,0.00002145767211914062,0.00001072883605957031,0.00000536441802978515],type:null,wrapDateLine:true,sphericalMercator:false,animationEnabled:true,initialize:function(name,options){OpenLayers.Layer.EventPane.prototype.initialize.apply(this,arguments);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,arguments);if(this.sphericalMercator){OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator);this.initMercatorParameters();}},loadMapObject:function(){var veDiv=OpenLayers.Util.createDiv(this.name);var sz=this.map.getSize();veDiv.style.width=sz.w+"px";veDiv.style.height=sz.h+"px";this.div.appendChild(veDiv);try{this.mapObject=new VEMap(this.name);}catch(e){}
if(this.mapObject!=null){try{this.mapObject.LoadMap(null,null,this.type,true);this.mapObject.AttachEvent("onmousedown",OpenLayers.Function.True);}catch(e){}
this.mapObject.HideDashboard();if(typeof this.mapObject.SetAnimationEnabled=="function"){this.mapObject.SetAnimationEnabled(this.animationEnabled);}}
if(!this.mapObject||!this.mapObject.vemapcontrol||!this.mapObject.vemapcontrol.PanMap||(typeof this.mapObject.vemapcontrol.PanMap!="function")){this.dragPanMapObject=null;}},onMapResize:function(){this.mapObject.Resize(this.map.size.w,this.map.size.h);},getWarningHTML:function(){return OpenLayers.i18n("getLayerWarning",{'layerType':'VE','layerLib':'VirtualEarth'});},setMapObjectCenter:function(center,zoom){this.mapObject.SetCenterAndZoom(center,zoom);},getMapObjectCenter:function(){return this.mapObject.GetCenter();},dragPanMapObject:function(dX,dY){this.mapObject.vemapcontrol.PanMap(dX,-dY);},getMapObjectZoom:function(){return this.mapObject.GetZoomLevel();},getMapObjectLonLatFromMapObjectPixel:function(moPixel){return(typeof VEPixel!='undefined')?this.mapObject.PixelToLatLong(moPixel):this.mapObject.PixelToLatLong(moPixel.x,moPixel.y);},getMapObjectPixelFromMapObjectLonLat:function(moLonLat){return this.mapObject.LatLongToPixel(moLonLat);},getLongitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.Longitude,moLonLat.Latitude).lon:moLonLat.Longitude;},getLatitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.Longitude,moLonLat.Latitude).lat:moLonLat.Latitude;},getMapObjectLonLatFromLonLat:function(lon,lat){var veLatLong;if(this.sphericalMercator){var lonlat=this.inverseMercator(lon,lat);veLatLong=new VELatLong(lonlat.lat,lonlat.lon);}else{veLatLong=new VELatLong(lat,lon);}
return veLatLong;},getXFromMapObjectPixel:function(moPixel){return moPixel.x;},getYFromMapObjectPixel:function(moPixel){return moPixel.y;},getMapObjectPixelFromXY:function(x,y){return(typeof VEPixel!='undefined')?new VEPixel(x,y):new Msn.VE.Pixel(x,y);},CLASS_NAME:"OpenLayers.Layer.VirtualEarth"});OpenLayers.Layer.Yahoo=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:0,MAX_ZOOM_LEVEL:17,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,0.0006866455078125,0.00034332275390625,0.000171661376953125,0.0000858306884765625,0.00004291534423828125,0.00002145767211914062,0.00001072883605957031],type:null,wrapDateLine:true,sphericalMercator:false,initialize:function(name,options){OpenLayers.Layer.EventPane.prototype.initialize.apply(this,arguments);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,arguments);if(this.sphericalMercator){OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator);this.initMercatorParameters();}},loadMapObject:function(){try{var size=this.getMapObjectSizeFromOLSize(this.map.getSize());this.mapObject=new YMap(this.div,this.type,size);this.mapObject.disableKeyControls();this.mapObject.disableDragMap();if(!this.mapObject.moveByXY||(typeof this.mapObject.moveByXY!="function")){this.dragPanMapObject=null;}}catch(e){}},onMapResize:function(){try{var size=this.getMapObjectSizeFromOLSize(this.map.getSize());this.mapObject.resizeTo(size);}catch(e){}},setMap:function(map){OpenLayers.Layer.EventPane.prototype.setMap.apply(this,arguments);this.map.events.register("moveend",this,this.fixYahooEventPane);},fixYahooEventPane:function(){var yahooEventPane=OpenLayers.Util.getElement("ygddfdiv");if(yahooEventPane!=null){if(yahooEventPane.parentNode!=null){yahooEventPane.parentNode.removeChild(yahooEventPane);}
this.map.events.unregister("moveend",this,this.fixYahooEventPane);}},getWarningHTML:function(){return OpenLayers.i18n("getLayerWarning",{'layerType':'Yahoo','layerLib':'Yahoo'});},getOLZoomFromMapObjectZoom:function(moZoom){var zoom=null;if(moZoom!=null){zoom=OpenLayers.Layer.FixedZoomLevels.prototype.getOLZoomFromMapObjectZoom.apply(this,[moZoom]);zoom=18-zoom;}
return zoom;},getMapObjectZoomFromOLZoom:function(olZoom){var zoom=null;if(olZoom!=null){zoom=OpenLayers.Layer.FixedZoomLevels.prototype.getMapObjectZoomFromOLZoom.apply(this,[olZoom]);zoom=18-zoom;}
return zoom;},setMapObjectCenter:function(center,zoom){this.mapObject.drawZoomAndCenter(center,zoom);},getMapObjectCenter:function(){return this.mapObject.getCenterLatLon();},dragPanMapObject:function(dX,dY){this.mapObject.moveByXY({'x':-dX,'y':dY});},getMapObjectZoom:function(){return this.mapObject.getZoomLevel();},getMapObjectLonLatFromMapObjectPixel:function(moPixel){return this.mapObject.convertXYLatLon(moPixel);},getMapObjectPixelFromMapObjectLonLat:function(moLonLat){return this.mapObject.convertLatLonXY(moLonLat);},getLongitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.Lon,moLonLat.Lat).lon:moLonLat.Lon;},getLatitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.Lon,moLonLat.Lat).lat:moLonLat.Lat;},getMapObjectLonLatFromLonLat:function(lon,lat){var yLatLong;if(this.sphericalMercator){var lonlat=this.inverseMercator(lon,lat);yLatLong=new YGeoPoint(lonlat.lat,lonlat.lon);}else{yLatLong=new YGeoPoint(lat,lon);}
return yLatLong;},getXFromMapObjectPixel:function(moPixel){return moPixel.x;},getYFromMapObjectPixel:function(moPixel){return moPixel.y;},getMapObjectPixelFromXY:function(x,y){return new YCoordPoint(x,y);},getMapObjectSizeFromOLSize:function(olSize){return new YSize(olSize.w,olSize.h);},CLASS_NAME:"OpenLayers.Layer.Yahoo"});OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:false,propertyStyles:null,initialize:function(style,options){OpenLayers.Util.extend(this,options);this.rules=[];if(options&&options.rules){this.addRules(options.rules);}
this.setDefaultStyle(style||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i=0,len=this.rules.length;i<len;i++){this.rules[i].destroy();this.rules[i]=null;}
this.rules=null;this.defaultStyle=null;},createSymbolizer:function(feature){var style=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),feature);var rules=this.rules;var rule,context;var elseRules=[];var appliedRules=false;for(var i=0,len=rules.length;i<len;i++){rule=rules[i];var applies=rule.evaluate(feature);if(applies){if(rule instanceof OpenLayers.Rule&&rule.elseFilter){elseRules.push(rule);}else{appliedRules=true;this.applySymbolizer(rule,style,feature);}}}
if(appliedRules==false&&elseRules.length>0){appliedRules=true;for(var i=0,len=elseRules.length;i<len;i++){this.applySymbolizer(elseRules[i],style,feature);}}
if(rules.length>0&&appliedRules==false){style.display="none";}
return style;},applySymbolizer:function(rule,style,feature){var symbolizerPrefix=feature.geometry?this.getSymbolizerPrefix(feature.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];var symbolizer=rule.symbolizer[symbolizerPrefix]||rule.symbolizer;if(this.defaultsPerSymbolizer===true){var defaults=this.defaultStyle;OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:defaults.pointRadius});if(symbolizer.stroke===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{strokeWidth:defaults.strokeWidth,strokeColor:defaults.strokeColor,strokeOpacity:defaults.strokeOpacity,strokeDashstyle:defaults.strokeDashstyle,strokeLinecap:defaults.strokeLinecap});}
if(symbolizer.fill===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{fillColor:defaults.fillColor,fillOpacity:defaults.fillOpacity});}
if(symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset});}}
return this.createLiterals(OpenLayers.Util.extend(style,symbolizer),feature);},createLiterals:function(style,feature){var context=OpenLayers.Util.extend({},feature.attributes||feature.data);OpenLayers.Util.extend(context,this.context);for(var i in this.propertyStyles){style[i]=OpenLayers.Style.createLiteral(style[i],context,feature,i);}
return style;},findPropertyStyles:function(){var propertyStyles={};var style=this.defaultStyle;this.addPropertyStyles(propertyStyles,style);var rules=this.rules;var symbolizer,value;for(var i=0,len=rules.length;i<len;i++){symbolizer=rules[i].symbolizer;for(var key in symbolizer){value=symbolizer[key];if(typeof value=="object"){this.addPropertyStyles(propertyStyles,value);}else{this.addPropertyStyles(propertyStyles,symbolizer);break;}}}
return propertyStyles;},addPropertyStyles:function(propertyStyles,symbolizer){var property;for(var key in symbolizer){property=symbolizer[key];if(typeof property=="string"&&property.match(/\$\{\w+\}/)){propertyStyles[key]=true;}}
return propertyStyles;},addRules:function(rules){Array.prototype.push.apply(this.rules,rules);this.propertyStyles=this.findPropertyStyles();},setDefaultStyle:function(style){this.defaultStyle=style;this.propertyStyles=this.findPropertyStyles();},getSymbolizerPrefix:function(geometry){var prefixes=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var i=0,len=prefixes.length;i<len;i++){if(geometry.CLASS_NAME.indexOf(prefixes[i])!=-1){return prefixes[i];}}},clone:function(){var options=OpenLayers.Util.extend({},this);if(this.rules){options.rules=[];for(var i=0,len=this.rules.length;i<len;++i){options.rules.push(this.rules[i].clone());}}
options.context=this.context&&OpenLayers.Util.extend({},this.context);var defaultStyle=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(defaultStyle,options);},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(value,context,feature,property){if(typeof value=="string"&&value.indexOf("${")!=-1){value=OpenLayers.String.format(value,context,[feature,property]);value=(isNaN(value)||!value)?value:parseFloat(value);}
return value;};OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon','Text','Raster'];OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,documentDrag:false,zoomBox:null,zoomBoxEnabled:true,zoomWheelEnabled:true,mouseWheelOptions:null,handleRightClicks:false,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:true,initialize:function(options){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();if(this.dragPan){this.dragPan.destroy();}
this.dragPan=null;if(this.zoomBox){this.zoomBox.destroy();}
this.zoomBox=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){this.dragPan.activate();if(this.zoomWheelEnabled){this.handlers.wheel.activate();}
this.handlers.click.activate();if(this.zoomBoxEnabled){this.zoomBox.activate();}
return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},draw:function(){if(this.handleRightClicks){this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False;}
var clickCallbacks={'dblclick':this.defaultDblClick,'dblrightclick':this.defaultDblRightClick};var clickOptions={'double':true,'stopDouble':true};this.handlers.click=new OpenLayers.Handler.Click(this,clickCallbacks,clickOptions);this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,documentDrag:this.documentDrag},this.dragPanOptions));this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:this.zoomBoxKeyMask});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown},this.mouseWheelOptions);},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);},defaultDblRightClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom-1);},wheelChange:function(evt,deltaZ){var currentZoom=this.map.getZoom();var newZoom=this.map.getZoom()+Math.round(deltaZ);newZoom=Math.max(newZoom,0);newZoom=Math.min(newZoom,this.map.getNumZoomLevels());if(newZoom===currentZoom){return;}
var size=this.map.getSize();var deltaX=size.w/2-evt.xy.x;var deltaY=evt.xy.y-size.h/2;var newRes=this.map.baseLayer.getResolutionForZoom(newZoom);var zoomPoint=this.map.getLonLatFromPixel(evt.xy);var newCenter=new OpenLayers.LonLat(zoomPoint.lon+deltaX*newRes,zoomPoint.lat+deltaY*newRes);this.map.setCenter(newCenter,newZoom);},wheelUp:function(evt,delta){this.wheelChange(evt,delta||1);},wheelDown:function(evt,delta){this.wheelChange(evt,delta||-1);},disableZoomBox:function(){this.zoomBoxEnabled=false;this.zoomBox.deactivate();},enableZoomBox:function(){this.zoomBoxEnabled=true;if(this.active){this.zoomBox.activate();}},disableZoomWheel:function(){this.zoomWheelEnabled=false;this.handlers.wheel.deactivate();},enableZoomWheel:function(){this.zoomWheelEnabled=true;if(this.active){this.handlers.wheel.activate();}},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Filter=OpenLayers.Class({initialize:function(options){OpenLayers.Util.extend(this,options);},destroy:function(){},evaluate:function(context){return true;},clone:function(){return null;},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Format.WMC.v1_0_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd",initialize:function(options){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[options]);},write_wmc_Layer:function(context){var node=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,[context]);node.appendChild(this.write_wmc_FormatList(context));node.appendChild(this.write_wmc_StyleList(context));node.appendChild(this.write_wmc_LayerExtension(context));},CLASS_NAME:"OpenLayers.Format.WMC.v1_0_0"});OpenLayers.Format.WMC.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd",initialize:function(options){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[options]);},read_sld_MinScaleDenominator:function(layerContext,node){var minScaleDenominator=parseFloat(this.getChildValue(node));if(minScaleDenominator>0){layerContext.maxScale=minScaleDenominator;}},read_sld_MaxScaleDenominator:function(layerContext,node){layerContext.minScale=parseFloat(this.getChildValue(node));},write_wmc_Layer:function(context){var node=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,[context]);if(context.maxScale){var minSD=this.createElementNS(this.namespaces.sld,"sld:MinScaleDenominator");minSD.appendChild(this.createTextNode(context.maxScale.toPrecision(16)));node.appendChild(minSD);}
if(context.minScale){var maxSD=this.createElementNS(this.namespaces.sld,"sld:MaxScaleDenominator");maxSD.appendChild(this.createTextNode(context.minScale.toPrecision(16)));node.appendChild(maxSD);}
node.appendChild(this.write_wmc_FormatList(context));node.appendChild(this.write_wmc_StyleList(context));node.appendChild(this.write_wmc_LayerExtension(context));return node;},CLASS_NAME:"OpenLayers.Format.WMC.v1_1_0"});OpenLayers.Format.WMSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.0",initialize:function(options){OpenLayers.Format.WMSCapabilities.v1_1.prototype.initialize.apply(this,[options]);},readers:{"wms":OpenLayers.Util.applyDefaults({"SRS":function(node,obj){var srs=this.getChildValue(node);var values=srs.split(/ +/);for(var i=0,len=values.length;i<len;i++){obj.srs[values[i]]=true;}}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"])},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_0"});OpenLayers.Format.WMSCapabilities.v1_1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.1",initialize:function(options){OpenLayers.Format.WMSCapabilities.v1_1.prototype.initialize.apply(this,[options]);},readers:{"wms":OpenLayers.Util.applyDefaults({"SRS":function(node,obj){obj.srs[this.getChildValue(node)]=true;}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"])},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1"});OpenLayers.Format.WMSCapabilities.v1_3_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3,{version:"1.3.0",CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3_0"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){this.id=null;this.bounds=null;},clone:function(){return new OpenLayers.Geometry();},setBounds:function(bounds){if(bounds){this.bounds=bounds.clone();}},clearBounds:function(){this.bounds=null;if(this.parent){this.parent.clearBounds();}},extendBounds:function(newBounds){var bounds=this.getBounds();if(!bounds){this.setBounds(newBounds);}else{this.bounds.extend(newBounds);}},getBounds:function(){if(this.bounds==null){this.calculateBounds();}
return this.bounds;},calculateBounds:function(){},distanceTo:function(geometry,options){},getVertices:function(nodes){},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;var bounds=this.getBounds();if((bounds!=null)&&(lonlat!=null)){var dX=(toleranceLon!=null)?toleranceLon:0;var dY=(toleranceLat!=null)?toleranceLat:0;var toleranceBounds=new OpenLayers.Bounds(this.bounds.left-dX,this.bounds.bottom-dY,this.bounds.right+dX,this.bounds.top+dY);atPoint=toleranceBounds.containsLonLat(lonlat);}
return atPoint;},getLength:function(){return 0.0;},getArea:function(){return 0.0;},getCentroid:function(){return null;},toString:function(){return OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this));},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(wkt){var format=arguments.callee.format;if(!format){format=new OpenLayers.Format.WKT();arguments.callee.format=format;}
var geom;var result=format.read(wkt);if(result instanceof OpenLayers.Feature.Vector){geom=result.geometry;}else if(result instanceof Array){var len=result.length;var components=new Array(len);for(var i=0;i<len;++i){components[i]=result[i].geometry;}
geom=new OpenLayers.Geometry.Collection(components);}
return geom;};OpenLayers.Geometry.segmentsIntersect=function(seg1,seg2,options){var point=options&&options.point;var tolerance=options&&options.tolerance;var intersection=false;var x11_21=seg1.x1-seg2.x1;var y11_21=seg1.y1-seg2.y1;var x12_11=seg1.x2-seg1.x1;var y12_11=seg1.y2-seg1.y1;var y22_21=seg2.y2-seg2.y1;var x22_21=seg2.x2-seg2.x1;var d=(y22_21*x12_11)-(x22_21*y12_11);var n1=(x22_21*y11_21)-(y22_21*x11_21);var n2=(x12_11*y11_21)-(y12_11*x11_21);if(d==0){if(n1==0&&n2==0){intersection=true;}}else{var along1=n1/d;var along2=n2/d;if(along1>=0&&along1<=1&&along2>=0&&along2<=1){if(!point){intersection=true;}else{var x=seg1.x1+(along1*x12_11);var y=seg1.y1+(along1*y12_11);intersection=new OpenLayers.Geometry.Point(x,y);}}}
if(tolerance){var dist;if(intersection){if(point){var segs=[seg1,seg2];var seg,x,y;outer:for(var i=0;i<2;++i){seg=segs[i];for(var j=1;j<3;++j){x=seg["x"+j];y=seg["y"+j];dist=Math.sqrt(Math.pow(x-intersection.x,2)+
Math.pow(y-intersection.y,2));if(dist<tolerance){intersection.x=x;intersection.y=y;break outer;}}}}}else{var segs=[seg1,seg2];var source,target,x,y,p,result;outer:for(var i=0;i<2;++i){source=segs[i];target=segs[(i+1)%2];for(var j=1;j<3;++j){p={x:source["x"+j],y:source["y"+j]};result=OpenLayers.Geometry.distanceToSegment(p,target);if(result.distance<tolerance){if(point){intersection=new OpenLayers.Geometry.Point(p.x,p.y);}else{intersection=true;}
break outer;}}}}}
return intersection;};OpenLayers.Geometry.distanceToSegment=function(point,segment){var x0=point.x;var y0=point.y;var x1=segment.x1;var y1=segment.y1;var x2=segment.x2;var y2=segment.y2;var dx=x2-x1;var dy=y2-y1;var along=((dx*(x0-x1))+(dy*(y0-y1)))/(Math.pow(dx,2)+Math.pow(dy,2));var x,y;if(along<=0.0){x=x1;y=y1;}else if(along>=1.0){x=x2;y=y2;}else{x=x1+along*dx;y=y1+along*dy;}
return{distance:Math.sqrt(Math.pow(x-x0,2)+Math.pow(y-y0,2)),x:x,y:y};};OpenLayers.Layer.ArcGIS93Rest=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{format:"png"},isBaseLayer:true,initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;}
if(this.params.FORMAT=="jpg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"gif":"png";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.ArcGIS93Rest(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var projWords=this.projection.getCode().split(":");var srid=projWords[projWords.length-1];var imageSize=this.getImageSize();var newParams={'BBOX':bounds.toBBOX(),'SIZE':imageSize.w+","+imageSize.h,'F':"image",'BBOXSR':srid,'IMAGESR':srid};if(this.layerDefs){var layerDefStrList=[];var layerID;for(layerID in this.layerDefs){if(this.layerDefs.hasOwnProperty(layerID)){if(this.layerDefs[layerID]){layerDefStrList.push(layerID);layerDefStrList.push(":");layerDefStrList.push(this.layerDefs[layerID]);layerDefStrList.push(";");}}}
if(layerDefStrList.length>0){newParams['LAYERDEFS']=layerDefStrList.join("");}}
var requestString=this.getFullRequestString(newParams);return requestString;},setLayerFilter:function(id,queryDef){if(!this.layerDefs){this.layerDefs={};}
if(queryDef){this.layerDefs[id]=queryDef;}else{delete this.layerDefs[id];}},clearLayerFilter:function(id){if(id){delete this.layerDefs[id];}else{delete this.layerDefs;}},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},CLASS_NAME:"OpenLayers.Layer.ArcGIS93Rest"});OpenLayers.Layer.Google.v3={DEFAULTS:{maxExtent:new OpenLayers.Bounds(-128*156543.0339,-128*156543.0339,128*156543.0339,128*156543.0339),sphericalMercator:true,maxResolution:156543.0339,units:"m",projection:"EPSG:900913"},loadMapObject:function(){if(!this.type){this.type=google.maps.MapTypeId.ROADMAP;}
var mapObject;var cache=OpenLayers.Layer.Google.cache[this.map.id];if(cache){mapObject=cache.mapObject;++cache.count;}else{var container=this.map.viewPortDiv;var div=document.createElement("div");div.id=this.map.id+"_GMapContainer";div.style.position="absolute";div.style.width="100%";div.style.height="100%";container.appendChild(div);var center=this.map.getCenter();mapObject=new google.maps.Map(div,{center:center?new google.maps.LatLng(center.lat,center.lon):new google.maps.LatLng(0,0),zoom:this.map.getZoom()||0,mapTypeId:this.type,disableDefaultUI:true,keyboardShortcuts:false,draggable:false,disableDoubleClickZoom:true,scrollwheel:false});cache={mapObject:mapObject,count:1};OpenLayers.Layer.Google.cache[this.map.id]=cache;this.repositionListener=google.maps.event.addListenerOnce(mapObject,"center_changed",OpenLayers.Function.bind(this.repositionMapElements,this));}
this.mapObject=mapObject;this.setGMapVisibility(this.visibility);},repositionMapElements:function(){google.maps.event.trigger(this.mapObject,"resize");var div=this.mapObject.getDiv().firstChild;if(!div||div.childNodes.length<3){this.repositionTimer=window.setTimeout(OpenLayers.Function.bind(this.repositionMapElements,this),250);return false;}
var cache=OpenLayers.Layer.Google.cache[this.map.id];var container=this.map.viewPortDiv;var termsOfUse=div.lastChild;container.appendChild(termsOfUse);termsOfUse.style.zIndex="1100";termsOfUse.style.bottom="";termsOfUse.className="olLayerGoogleCopyright olLayerGoogleV3";termsOfUse.style.display="";cache.termsOfUse=termsOfUse;var poweredBy=div.lastChild;container.appendChild(poweredBy);poweredBy.style.zIndex="1100";poweredBy.style.bottom="";poweredBy.className="olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint";poweredBy.style.display="";cache.poweredBy=poweredBy;this.setGMapVisibility(this.visibility);},onMapResize:function(){if(this.visibility){google.maps.event.trigger(this.mapObject,"resize");}else{if(!this._resized){var layer=this;google.maps.event.addListenerOnce(this.mapObject,"tilesloaded",function(){delete layer._resized;google.maps.event.trigger(layer.mapObject,"resize");layer.moveTo(layer.map.getCenter(),layer.map.getZoom());});}
this._resized=true;}},setGMapVisibility:function(visible){var cache=OpenLayers.Layer.Google.cache[this.map.id];if(cache){var type=this.type;var layers=this.map.layers;var layer;for(var i=layers.length-1;i>=0;--i){layer=layers[i];if(layer instanceof OpenLayers.Layer.Google&&layer.visibility===true&&layer.inRange===true){type=layer.type;visible=true;break;}}
var container=this.mapObject.getDiv();if(visible===true){this.mapObject.setMapTypeId(type);container.style.left="";if(cache.termsOfUse&&cache.termsOfUse.style){cache.termsOfUse.style.left="";cache.termsOfUse.style.display="";cache.poweredBy.style.display="";}
cache.displayed=this.id;}else{delete cache.displayed;container.style.left="-9999px";if(cache.termsOfUse&&cache.termsOfUse.style){cache.termsOfUse.style.display="none";cache.termsOfUse.style.left="-9999px";cache.poweredBy.style.display="none";}}}},getMapContainer:function(){return this.mapObject.getDiv();},getMapObjectBoundsFromOLBounds:function(olBounds){var moBounds=null;if(olBounds!=null){var sw=this.sphericalMercator?this.inverseMercator(olBounds.bottom,olBounds.left):new OpenLayers.LonLat(olBounds.bottom,olBounds.left);var ne=this.sphericalMercator?this.inverseMercator(olBounds.top,olBounds.right):new OpenLayers.LonLat(olBounds.top,olBounds.right);moBounds=new google.maps.LatLngBounds(new google.maps.LatLng(sw.lat,sw.lon),new google.maps.LatLng(ne.lat,ne.lon));}
return moBounds;},getMapObjectLonLatFromMapObjectPixel:function(moPixel){var size=this.map.getSize();var lon=this.getLongitudeFromMapObjectLonLat(this.mapObject.center);var lat=this.getLatitudeFromMapObjectLonLat(this.mapObject.center);var res=this.map.getResolution();var delta_x=moPixel.x-(size.w/2);var delta_y=moPixel.y-(size.h/2);var lonlat=new OpenLayers.LonLat(lon+delta_x*res,lat-delta_y*res);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}
return this.getMapObjectLonLatFromLonLat(lonlat.lon,lonlat.lat);},getMapObjectPixelFromMapObjectLonLat:function(moLonLat){var lon=this.getLongitudeFromMapObjectLonLat(moLonLat);var lat=this.getLatitudeFromMapObjectLonLat(moLonLat);var res=this.map.getResolution();var extent=this.map.getExtent();var px=new OpenLayers.Pixel((1/res*(lon-extent.left)),(1/res*(extent.top-lat)));return this.getMapObjectPixelFromXY(px.x,px.y);},setMapObjectCenter:function(center,zoom){this.mapObject.setOptions({center:center,zoom:zoom});},getMapObjectZoomFromMapObjectBounds:function(moBounds){return this.mapObject.getBoundsZoomLevel(moBounds);},getMapObjectLonLatFromLonLat:function(lon,lat){var gLatLng;if(this.sphericalMercator){var lonlat=this.inverseMercator(lon,lat);gLatLng=new google.maps.LatLng(lonlat.lat,lonlat.lon);}else{gLatLng=new google.maps.LatLng(lat,lon);}
return gLatLng;},getMapObjectPixelFromXY:function(x,y){return new google.maps.Point(x,y);},destroy:function(){if(this.repositionListener){google.maps.event.removeListener(this.repositionListener);}
if(this.repositionTimer){window.clearTimeout(this.repositionTimer);}
OpenLayers.Layer.Google.prototype.destroy.apply(this,arguments);}};OpenLayers.Layer.KaMap=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,units:null,resolution:OpenLayers.DOTS_PER_INCH,DEFAULT_PARAMS:{i:'jpeg',map:''},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var mapRes=this.map.getResolution();var scale=Math.round((this.map.getScale()*10000))/10000;var pX=Math.round(bounds.left/mapRes);var pY=-Math.round(bounds.top/mapRes);return this.getFullRequestString({t:pY,l:pX,s:scale});},addTile:function(bounds,position){var url=this.getURL(bounds);return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=tilecol*tilelon;var offsetlat=bounds.top;var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-(tilerowremain+1)*this.tileSize.h;var tileoffsetlat=tilerow*tilelat;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.KaMap(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
obj.grid=[];return obj;},getTileBounds:function(viewPortPx){var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=tileMapWidth*Math.floor(mapPoint.lon/tileMapWidth);var tileBottom=tileMapHeight*Math.floor(mapPoint.lat/tileMapHeight);return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.KaMap"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,useHttpTile:false,singleTile:false,useOverlay:false,useAsyncOverlay:true,TILE_PARAMS:{operation:'GETTILEIMAGE',version:'1.2.0'},SINGLE_TILE_PARAMS:{operation:'GETMAPIMAGE',format:'PNG',locale:'en',clip:'1',version:'1.0.0'},OVERLAY_PARAMS:{operation:'GETDYNAMICMAPOVERLAYIMAGE',format:'PNG',locale:'en',clip:'1',version:'2.0.0'},FOLDER_PARAMS:{tileColumnsPerFolder:30,tileRowsPerFolder:30,format:'png',querystring:null},defaultSize:new OpenLayers.Size(300,300),initialize:function(name,url,params,options){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.transparent!="true")&&(this.transparent!=true));}
if(options&&options.useOverlay!=null){this.useOverlay=options.useOverlay;}
if(this.singleTile){if(this.useOverlay){OpenLayers.Util.applyDefaults(this.params,this.OVERLAY_PARAMS);if(!this.useAsyncOverlay){this.params.version="1.0.0";}}else{OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS);}}else{if(this.useHttpTile){OpenLayers.Util.applyDefaults(this.params,this.FOLDER_PARAMS);}else{OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS);}
this.setTileSize(this.defaultSize);}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){var url;var center=bounds.getCenterLonLat();var mapSize=this.map.getSize();if(this.singleTile){var params={setdisplaydpi:OpenLayers.DOTS_PER_INCH,setdisplayheight:mapSize.h*this.ratio,setdisplaywidth:mapSize.w*this.ratio,setviewcenterx:center.lon,setviewcentery:center.lat,setviewscale:this.map.getScale()};if(this.useOverlay&&!this.useAsyncOverlay){var getVisParams={};getVisParams=OpenLayers.Util.extend(getVisParams,params);getVisParams.operation="GETVISIBLEMAPEXTENT";getVisParams.version="1.0.0";getVisParams.session=this.params.session;getVisParams.mapName=this.params.mapName;getVisParams.format='text/xml';url=this.getFullRequestString(getVisParams);OpenLayers.Request.GET({url:url,async:false});}
url=this.getFullRequestString(params);}else{var currentRes=this.map.getResolution();var colidx=Math.floor((bounds.left-this.maxExtent.left)/currentRes);colidx=Math.round(colidx/this.tileSize.w);var rowidx=Math.floor((this.maxExtent.top-bounds.top)/currentRes);rowidx=Math.round(rowidx/this.tileSize.h);if(this.useHttpTile){url=this.getImageFilePath({tilecol:colidx,tilerow:rowidx,scaleindex:this.resolutions.length-this.map.zoom-1});}else{url=this.getFullRequestString({tilecol:colidx,tilerow:rowidx,scaleindex:this.resolutions.length-this.map.zoom-1});}}
return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
return requestString;},getImageFilePath:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
var requestString=url;var tileRowGroup="";var tileColGroup="";if(newParams.tilerow<0){tileRowGroup='-';}
if(newParams.tilerow==0){tileRowGroup+='0';}else{tileRowGroup+=Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder))*this.params.tileRowsPerFolder;}
if(newParams.tilecol<0){tileColGroup='-';}
if(newParams.tilecol==0){tileColGroup+='0';}else{tileColGroup+=Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder))*this.params.tileColumnsPerFolder;}
var tilePath='/S'+Math.floor(newParams.scaleindex)
+'/'+this.params.basemaplayergroupname
+'/R'+tileRowGroup
+'/C'+tileColGroup
+'/'+(newParams.tilerow%this.params.tileRowsPerFolder)
+'_'+(newParams.tilecol%this.params.tileColumnsPerFolder)
+'.'+this.params.format;if(this.params.querystring){tilePath+="?"+this.params.querystring;}
requestString+=tilePath;return requestString;},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var extent=[bounds.left,bounds.bottom,bounds.right,bounds.top];var imageSize=this.getImageSize();var url=this.getFullRequestString({mapext:extent,imgext:extent,map_size:[imageSize.w,imageSize.h],imgx:imageSize.w/2,imgy:imageSize.h/2,imgxy:[imageSize.w,imageSize.h]});return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
paramsString=OpenLayers.Util.getParameterString(allParams);var requestString=url;paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
return requestString;},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Layer.TMS=OpenLayers.Class(OpenLayers.Layer.Grid,{serviceVersion:"1.0.0",isBaseLayer:true,tileOrigin:null,serverResolutions:null,zoomOffset:0,initialize:function(name,url,options){var newArguments=[];newArguments.push(name,url,{},options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.TMS(this.name,this.url,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var res=this.map.getResolution();var x=Math.round((bounds.left-this.tileOrigin.lon)/(res*this.tileSize.w));var y=Math.round((bounds.bottom-this.tileOrigin.lat)/(res*this.tileSize.h));var z=this.serverResolutions!=null?OpenLayers.Util.indexOf(this.serverResolutions,res):this.map.getZoom()+this.zoomOffset;var path=this.serviceVersion+"/"+this.layername+"/"+z+"/"+x+"/"+y+"."+this.type;var url=this.url;if(url instanceof Array){url=this.selectUrl(path,url);}
return url+path;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},setMap:function(map){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);if(!this.tileOrigin){this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.bottom);}},CLASS_NAME:"OpenLayers.Layer.TMS"});OpenLayers.Layer.TileCache=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,format:'image/png',serverResolutions:null,initialize:function(name,url,layername,options){this.layername=layername;OpenLayers.Layer.Grid.prototype.initialize.apply(this,[name,url,{},options]);this.extension=this.format.split('/')[1].toLowerCase();this.extension=(this.extension=='jpg')?'jpeg':this.extension;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.TileCache(this.name,this.url,this.layername,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){var res=this.map.getResolution();var bbox=this.maxExtent;var size=this.tileSize;var tileX=Math.round((bounds.left-bbox.left)/(res*size.w));var tileY=Math.round((bounds.bottom-bbox.bottom)/(res*size.h));var tileZ=this.serverResolutions!=null?OpenLayers.Util.indexOf(this.serverResolutions,res):this.map.getZoom();function zeroPad(number,length){number=String(number);var zeros=[];for(var i=0;i<length;++i){zeros.push('0');}
return zeros.join('').substring(0,length-number.length)+number;}
var components=[this.layername,zeroPad(tileZ,2),zeroPad(parseInt(tileX/1000000),3),zeroPad((parseInt(tileX/1000)%1000),3),zeroPad((parseInt(tileX)%1000),3),zeroPad(parseInt(tileY/1000000),3),zeroPad((parseInt(tileY/1000)%1000),3),zeroPad((parseInt(tileY)%1000),3)+'.'+this.extension];var path=components.join('/');var url=this.url;if(url instanceof Array){url=this.selectUrl(path,url);}
url=(url.charAt(url.length-1)=='/')?url:url+'/';return url+path;},addTile:function(bounds,position){var url=this.getURL(bounds);return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},CLASS_NAME:"OpenLayers.Layer.TileCache"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",exceptions:"application/vnd.ogc.se_inimage",format:"image/jpeg"},reproject:false,isBaseLayer:true,encodeBBOX:false,noMagic:false,yx:{'EPSG:4326':true},initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);if(parseFloat(params.VERSION)>=1.3&&!params.EXCEPTIONS){params.EXCEPTIONS="INIMAGE";}
newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;}
if(this.params.FORMAT=="image/jpeg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},reverseAxisOrder:function(){return(parseFloat(this.params.VERSION)>=1.3&&!!this.yx[this.map.getProjectionObject().getCode()]);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();var newParams={};var reverseAxisOrder=this.reverseAxisOrder();newParams.BBOX=this.encodeBBOX?bounds.toBBOX(null,reverseAxisOrder):bounds.toArray(reverseAxisOrder);newParams.WIDTH=imageSize.w;newParams.HEIGHT=imageSize.h;var requestString=this.getFullRequestString(newParams);return requestString;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams,altUrl){var projectionCode=this.map.getProjection();var value=(projectionCode=="none")?null:projectionCode
if(parseFloat(this.params.VERSION)>=1.3){this.params.CRS=value;}else{this.params.SRS=value;}
return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.WMTS=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,version:"1.0.0",requestEncoding:"KVP",url:null,layer:null,matrixSet:null,style:null,format:"image/jpeg",tileOrigin:null,tileFullExtent:null,formatSuffix:null,matrixIds:null,dimensions:null,params:null,zoomOffset:0,formatSuffixMap:{"image/png":"png","image/png8":"png","image/png24":"png","image/png32":"png","png":"png","image/jpeg":"jpg","image/jpg":"jpg","jpeg":"jpg","jpg":"jpg"},matrix:null,initialize:function(config){var required={url:true,layer:true,style:true,matrixSet:true};for(var prop in required){if(!(prop in config)){throw new Error("Missing property '"+prop+"' in layer configuration.");}}
config.params=OpenLayers.Util.upperCaseObject(config.params);var args=[config.name,config.url,config.params,config];OpenLayers.Layer.Grid.prototype.initialize.apply(this,args);if(!this.formatSuffix){this.formatSuffix=this.formatSuffixMap[this.format]||this.format.split("/").pop();}
if(this.matrixIds){var len=this.matrixIds.length;if(len&&typeof this.matrixIds[0]==="string"){var ids=this.matrixIds;this.matrixIds=new Array(len);for(var i=0;i<len;++i){this.matrixIds[i]={identifier:ids[i]};}}}},setMap:function(){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.updateMatrixProperties();},updateMatrixProperties:function(){this.matrix=this.getMatrix();if(this.matrix){if(this.matrix.topLeftCorner){this.tileOrigin=this.matrix.topLeftCorner;}
if(this.matrix.tileWidth&&this.matrix.tileHeight){this.tileSize=new OpenLayers.Size(this.matrix.tileWidth,this.matrix.tileHeight);}
if(!this.tileOrigin){this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.top);}
if(!this.tileFullExtent){this.tileFullExtent=this.maxExtent;}}},moveTo:function(bounds,zoomChanged,dragging){if(zoomChanged||!this.matrix){this.updateMatrixProperties();}
return OpenLayers.Layer.Grid.prototype.moveTo.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMTS(this.options);}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getMatrix:function(){var matrix;if(!this.matrixIds||this.matrixIds.length===0){matrix={identifier:this.map.getZoom()+this.zoomOffset};}else{if("scaleDenominator"in this.matrixIds[0]){var denom=OpenLayers.METERS_PER_INCH*OpenLayers.INCHES_PER_UNIT[this.units]*this.map.getResolution()/0.28E-3;var diff=Number.POSITIVE_INFINITY;var delta;for(var i=0,ii=this.matrixIds.length;i<ii;++i){delta=Math.abs(1-(this.matrixIds[i].scaleDenominator/denom));if(delta<diff){diff=delta;matrix=this.matrixIds[i];}}}else{matrix=this.matrixIds[this.map.getZoom()+this.zoomOffset];}}
return matrix;},getTileInfo:function(loc){var res=this.map.getResolution();var fx=(loc.lon-this.tileOrigin.lon)/(res*this.tileSize.w);var fy=(this.tileOrigin.lat-loc.lat)/(res*this.tileSize.h);var col=Math.floor(fx);var row=Math.floor(fy);return{col:col,row:row,i:Math.floor((fx-col)*this.tileSize.w),j:Math.floor((fy-row)*this.tileSize.h)};},getURL:function(bounds){bounds=this.adjustBounds(bounds);var url="";if(!this.tileFullExtent||this.tileFullExtent.intersectsBounds(bounds)){var center=bounds.getCenterLonLat();var info=this.getTileInfo(center);var matrixId=this.matrix.identifier;if(this.requestEncoding.toUpperCase()==="REST"){var path=this.version+"/"+this.layer+"/"+this.style+"/";if(this.dimensions){for(var i=0;i<this.dimensions.length;i++){if(this.params[this.dimensions[i]]){path=path+this.params[this.dimensions[i]]+"/";}}}
path=path+this.matrixSet+"/"+this.matrix.identifier+"/"+info.row+"/"+info.col+"."+this.formatSuffix;if(this.url instanceof Array){url=this.selectUrl(path,this.url);}else{url=this.url;}
if(!url.match(/\/$/)){url=url+"/";}
url=url+path;}else if(this.requestEncoding.toUpperCase()==="KVP"){var params={SERVICE:"WMTS",REQUEST:"GetTile",VERSION:this.version,LAYER:this.layer,STYLE:this.style,TILEMATRIXSET:this.matrixSet,TILEMATRIX:this.matrix.identifier,TILEROW:info.row,TILECOL:info.col,FORMAT:this.format};url=OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,[params]);}}
return url;},mergeNewParams:function(newParams){if(this.requestEncoding.toUpperCase()==="KVP"){return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,[OpenLayers.Util.upperCaseObject(newParams)]);}},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},CLASS_NAME:"OpenLayers.Layer.WMTS"});OpenLayers.Layer.WorldWind=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{},isBaseLayer:true,lzd:null,zoomLevels:null,initialize:function(name,url,lzd,zoomLevels,params,options){this.lzd=lzd;this.zoomLevels=zoomLevels;var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getZoom:function(){var zoom=this.map.getZoom();var extent=this.map.getMaxExtent();zoom=zoom-Math.log(this.maxResolution/(this.lzd/512))/Math.log(2);return zoom;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var zoom=this.getZoom();var extent=this.map.getMaxExtent();var deg=this.lzd/Math.pow(2,this.getZoom());var x=Math.floor((bounds.left-extent.left)/deg);var y=Math.floor((bounds.bottom-extent.bottom)/deg);if(this.map.getResolution()<=(this.lzd/512)&&this.getZoom()<=this.zoomLevels){return this.getFullRequestString({L:zoom,X:x,Y:y});}else{return OpenLayers.Util.getImagesLocation()+"blank.gif";}},CLASS_NAME:"OpenLayers.Layer.WorldWind"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,sphericalMercator:false,zoomOffset:0,initialize:function(name,url,options){if(options&&options.sphericalMercator||this.sphericalMercator){options=OpenLayers.Util.extend({maxExtent:new OpenLayers.Bounds(-128*156543.0339,-128*156543.0339,128*156543.0339,128*156543.0339),maxResolution:156543.0339,numZoomLevels:19,units:"m",projection:"EPSG:900913"},options);}
url=url||this.url;name=name||this.name;var newArguments=[name,url,{},options];OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){var res=this.map.getResolution();var x=Math.round((bounds.left-this.maxExtent.left)/(res*this.tileSize.w));var y=Math.round((this.maxExtent.top-bounds.top)/(res*this.tileSize.h));var z=this.map.getZoom()+this.zoomOffset;var url=this.url;var s=''+x+y+z;if(url instanceof Array)
{url=this.selectUrl(s,url);}
var path=OpenLayers.String.format(url,{'x':x,'y':y,'z':z});return path;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},setMap:function(map){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);if(!this.tileOrigin){this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.bottom);}},CLASS_NAME:"OpenLayers.Layer.XYZ"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",attribution:"Data CC-By-SA by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",sphericalMercator:true,url:'http://tile.openstreetmap.org/${z}/${x}/${y}.png',clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions());}
obj=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[obj]);return obj;},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Layer.Zoomify=OpenLayers.Class(OpenLayers.Layer.Grid,{url:null,size:null,isBaseLayer:true,standardTileSize:256,numberOfTiers:0,tileCountUpToTier:new Array(),tierSizeInTiles:new Array(),tierImageSize:new Array(),initialize:function(name,url,size,options){this.initializeZoomify(size);var newArguments=[];newArguments.push(name,url,size,{},options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);},initializeZoomify:function(size){var imageSize=size.clone()
var tiles=new OpenLayers.Size(Math.ceil(imageSize.w/this.standardTileSize),Math.ceil(imageSize.h/this.standardTileSize));this.tierSizeInTiles.push(tiles);this.tierImageSize.push(imageSize);while(imageSize.w>this.standardTileSize||imageSize.h>this.standardTileSize){imageSize=new OpenLayers.Size(Math.floor(imageSize.w/2),Math.floor(imageSize.h/2));tiles=new OpenLayers.Size(Math.ceil(imageSize.w/this.standardTileSize),Math.ceil(imageSize.h/this.standardTileSize));this.tierSizeInTiles.push(tiles);this.tierImageSize.push(imageSize);}
this.tierSizeInTiles.reverse();this.tierImageSize.reverse();this.numberOfTiers=this.tierSizeInTiles.length;this.tileCountUpToTier[0]=0;for(var i=1;i<this.numberOfTiers;i++){this.tileCountUpToTier.push(this.tierSizeInTiles[i-1].w*this.tierSizeInTiles[i-1].h+
this.tileCountUpToTier[i-1]);}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);this.tileCountUpToTier.length=0
this.tierSizeInTiles.length=0
this.tierImageSize.length=0},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Zoomify(this.name,this.url,this.size,this.options);}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var res=this.map.getResolution();var x=Math.round((bounds.left-this.tileOrigin.lon)/(res*this.tileSize.w));var y=Math.round((this.tileOrigin.lat-bounds.top)/(res*this.tileSize.h));var z=this.map.getZoom();var tileIndex=x+y*this.tierSizeInTiles[z].w+this.tileCountUpToTier[z];var path="TileGroup"+Math.floor((tileIndex)/256)+"/"+z+"-"+x+"-"+y+".jpg";var url=this.url;if(url instanceof Array){url=this.selectUrl(path,url);}
return url+path;},getImageSize:function(){if(arguments.length>0){bounds=this.adjustBounds(arguments[0]);var res=this.map.getResolution();var x=Math.round((bounds.left-this.tileOrigin.lon)/(res*this.tileSize.w));var y=Math.round((this.tileOrigin.lat-bounds.top)/(res*this.tileSize.h));var z=this.map.getZoom();var w=this.standardTileSize;var h=this.standardTileSize;if(x==this.tierSizeInTiles[z].w-1){var w=this.tierImageSize[z].w%this.standardTileSize;};if(y==this.tierSizeInTiles[z].h-1){var h=this.tierImageSize[z].h%this.standardTileSize;};return(new OpenLayers.Size(w,h));}else{return this.tileSize;}},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},setMap:function(map){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.top);},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},CLASS_NAME:"OpenLayers.Layer.Zoomify"});OpenLayers.Protocol.SQL.Gears=OpenLayers.Class(OpenLayers.Protocol.SQL,{FID_PREFIX:'__gears_fid__',NULL_GEOMETRY:'__gears_null_geometry__',NULL_FEATURE_STATE:'__gears_null_feature_state__',jsonParser:null,wktParser:null,fidRegExp:null,saveFeatureState:true,typeOfFid:"string",db:null,initialize:function(options){if(!this.supported()){return;}
OpenLayers.Protocol.SQL.prototype.initialize.apply(this,[options]);this.jsonParser=new OpenLayers.Format.JSON();this.wktParser=new OpenLayers.Format.WKT();this.fidRegExp=new RegExp('^'+this.FID_PREFIX);this.initializeDatabase();},initializeDatabase:function(){this.db=google.gears.factory.create('beta.database');this.db.open(this.databaseName);this.db.execute("CREATE TABLE IF NOT EXISTS "+this.tableName+" (fid TEXT UNIQUE, geometry TEXT, properties TEXT,"+"  state TEXT)");},destroy:function(){this.db.close();this.db=null;this.jsonParser=null;this.wktParser=null;OpenLayers.Protocol.SQL.prototype.destroy.apply(this);},supported:function(){return!!(window.google&&google.gears);},read:function(options){OpenLayers.Protocol.prototype.read.apply(this,arguments);options=OpenLayers.Util.applyDefaults(options,this.options);var feature,features=[];var rs=this.db.execute("SELECT * FROM "+this.tableName);while(rs.isValidRow()){feature=this.unfreezeFeature(rs);if(this.evaluateFilter(feature,options.filter)){if(!options.noFeatureStateReset){feature.state=null;}
features.push(feature);}
rs.next();}
rs.close();var resp=new OpenLayers.Protocol.Response({code:OpenLayers.Protocol.Response.SUCCESS,requestType:"read",features:features});if(options&&options.callback){options.callback.call(options.scope,resp);}
return resp;},unfreezeFeature:function(row){var feature;var wkt=row.fieldByName('geometry');if(wkt==this.NULL_GEOMETRY){feature=new OpenLayers.Feature.Vector();}else{feature=this.wktParser.read(wkt);}
feature.attributes=this.jsonParser.read(row.fieldByName('properties'));feature.fid=this.extractFidFromField(row.fieldByName('fid'));var state=row.fieldByName('state');if(state==this.NULL_FEATURE_STATE){state=null;}
feature.state=state;return feature;},extractFidFromField:function(field){if(!field.match(this.fidRegExp)&&this.typeOfFid=="number"){field=parseFloat(field);}
return field;},create:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=this.createOrUpdate(features);resp.requestType="create";if(options&&options.callback){options.callback.call(options.scope,resp);}
return resp;},update:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=this.createOrUpdate(features);resp.requestType="update";if(options&&options.callback){options.callback.call(options.scope,resp);}
return resp;},createOrUpdate:function(features){if(!(features instanceof Array)){features=[features];}
var i,len=features.length,feature;var insertedFeatures=new Array(len);for(i=0;i<len;i++){feature=features[i];var params=this.freezeFeature(feature);this.db.execute("REPLACE INTO "+this.tableName+" (fid, geometry, properties, state)"+" VALUES (?, ?, ?, ?)",params);var clone=feature.clone();clone.fid=this.extractFidFromField(params[0]);insertedFeatures[i]=clone;}
return new OpenLayers.Protocol.Response({code:OpenLayers.Protocol.Response.SUCCESS,features:insertedFeatures,reqFeatures:features});},freezeFeature:function(feature){feature.fid=feature.fid!=null?""+feature.fid:OpenLayers.Util.createUniqueID(this.FID_PREFIX);var geometry=feature.geometry!=null?feature.geometry.toString():this.NULL_GEOMETRY;var properties=this.jsonParser.write(feature.attributes);var state=this.getFeatureStateForFreeze(feature);return[feature.fid,geometry,properties,state];},getFeatureStateForFreeze:function(feature){var state;if(!this.saveFeatureState){state=this.NULL_FEATURE_STATE;}else if(this.createdOffline(feature)){state=OpenLayers.State.INSERT;}else{state=feature.state;}
return state;},"delete":function(features,options){if(!(features instanceof Array)){features=[features];}
options=OpenLayers.Util.applyDefaults(options,this.options);var i,len,feature;for(i=0,len=features.length;i<len;i++){feature=features[i];if(this.saveFeatureState&&!this.createdOffline(feature)){var toDelete=feature.clone();toDelete.fid=feature.fid;if(toDelete.geometry){toDelete.geometry.destroy();toDelete.geometry=null;}
toDelete.state=feature.state;this.createOrUpdate(toDelete);}else{this.db.execute("DELETE FROM "+this.tableName+" WHERE fid = ?",[feature.fid]);}}
var resp=new OpenLayers.Protocol.Response({code:OpenLayers.Protocol.Response.SUCCESS,requestType:"delete",reqFeatures:features});if(options&&options.callback){options.callback.call(options.scope,resp);}
return resp;},createdOffline:function(feature){return(typeof feature.fid=="string"&&!!(feature.fid.match(this.fidRegExp)));},commit:function(features,options){var opt,resp=[],nRequests=0,nResponses=0;function callback(resp){if(++nResponses<nRequests){resp.last=false;}
this.callUserCallback(options,resp);}
var feature,toCreate=[],toUpdate=[],toDelete=[];for(var i=features.length-1;i>=0;i--){feature=features[i];switch(feature.state){case OpenLayers.State.INSERT:toCreate.push(feature);break;case OpenLayers.State.UPDATE:toUpdate.push(feature);break;case OpenLayers.State.DELETE:toDelete.push(feature);break;}}
if(toCreate.length>0){nRequests++;opt=OpenLayers.Util.applyDefaults({"callback":callback,"scope":this},options.create);resp.push(this.create(toCreate,opt));}
if(toUpdate.length>0){nRequests++;opt=OpenLayers.Util.applyDefaults({"callback":callback,"scope":this},options.update);resp.push(this.update(toUpdate,opt));}
if(toDelete.length>0){nRequests++;opt=OpenLayers.Util.applyDefaults({"callback":callback,"scope":this},options["delete"]);resp.push(this["delete"](toDelete,opt));}
return resp;},clear:function(){this.db.execute("DELETE FROM "+this.tableName);},callUserCallback:function(options,resp){var opt=options[resp.requestType];if(opt&&opt.callback){opt.callback.call(opt.scope,resp);}
if(resp.last&&options.callback){options.callback.call(options.scope);}},CLASS_NAME:"OpenLayers.Protocol.SQL.Gears"});OpenLayers.Rule=OpenLayers.Class({id:null,name:null,title:null,description:null,context:null,filter:null,elseFilter:false,symbolizer:null,symbolizers:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(options){this.symbolizer={};OpenLayers.Util.extend(this,options);if(this.symbolizers){delete this.symbolizer;}
this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i in this.symbolizer){this.symbolizer[i]=null;}
this.symbolizer=null;delete this.symbolizers;},evaluate:function(feature){var context=this.getContext(feature);var applies=true;if(this.minScaleDenominator||this.maxScaleDenominator){var scale=feature.layer.map.getScale();}
if(this.minScaleDenominator){applies=scale>=OpenLayers.Style.createLiteral(this.minScaleDenominator,context);}
if(applies&&this.maxScaleDenominator){applies=scale<OpenLayers.Style.createLiteral(this.maxScaleDenominator,context);}
if(applies&&this.filter){if(this.filter.CLASS_NAME=="OpenLayers.Filter.FeatureId"){applies=this.filter.evaluate(feature);}else{applies=this.filter.evaluate(context);}}
return applies;},getContext:function(feature){var context=this.context;if(!context){context=feature.attributes||feature.data;}
if(typeof this.context=="function"){context=this.context(feature);}
return context;},clone:function(){var options=OpenLayers.Util.extend({},this);if(this.symbolizers){var len=this.symbolizers.length;options.symbolizers=new Array(len);for(var i=0;i<len;++i){options.symbolizers[i]=this.symbolizers[i].clone();}}else{options.symbolizer={};var value,type;for(var key in this.symbolizer){value=this.symbolizer[key];type=typeof value;if(type==="object"){options.symbolizer[key]=OpenLayers.Util.extend({},value);}else if(type==="string"){options.symbolizer[key]=value;}}}
options.filter=this.filter&&this.filter.clone();options.context=this.context&&OpenLayers.Util.extend({},this.context);return new OpenLayers.Rule(options);},CLASS_NAME:"OpenLayers.Rule"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(style,options){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),"select":new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]),"temporary":new OpenLayers.Style(OpenLayers.Feature.Vector.style["temporary"]),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(style instanceof OpenLayers.Style){this.styles["default"]=style;this.styles["select"]=style;this.styles["temporary"]=style;this.styles["delete"]=style;}else if(typeof style=="object"){for(var key in style){if(style[key]instanceof OpenLayers.Style){this.styles[key]=style[key];}else if(typeof style[key]=="object"){this.styles[key]=new OpenLayers.Style(style[key]);}else{this.styles["default"]=new OpenLayers.Style(style);this.styles["select"]=new OpenLayers.Style(style);this.styles["temporary"]=new OpenLayers.Style(style);this.styles["delete"]=new OpenLayers.Style(style);break;}}}
OpenLayers.Util.extend(this,options);},destroy:function(){for(var key in this.styles){this.styles[key].destroy();}
this.styles=null;},createSymbolizer:function(feature,intent){if(!feature){feature=new OpenLayers.Feature.Vector();}
if(!this.styles[intent]){intent="default";}
feature.renderIntent=intent;var defaultSymbolizer={};if(this.extendDefault&&intent!="default"){defaultSymbolizer=this.styles["default"].createSymbolizer(feature);}
return OpenLayers.Util.extend(defaultSymbolizer,this.styles[intent].createSymbolizer(feature));},addUniqueValueRules:function(renderIntent,property,symbolizers,context){var rules=[];for(var value in symbolizers){rules.push(new OpenLayers.Rule({symbolizer:symbolizers[value],context:context,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:property,value:value})}));}
this.styles[renderIntent].addRules(rules);},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Control.NavToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(options){OpenLayers.Control.Panel.prototype.initialize.apply(this,[options]);this.addControls([new OpenLayers.Control.Navigation(),new OpenLayers.Control.ZoomBox()]);},draw:function(){var div=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);this.activateControl(this.controls[0]);return div;},CLASS_NAME:"OpenLayers.Control.NavToolbar"});OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:true,lowerBoundary:null,upperBoundary:null,initialize:function(options){OpenLayers.Filter.prototype.initialize.apply(this,[options]);},evaluate:function(context){if(context instanceof OpenLayers.Feature.Vector){context=context.attributes;}
var result=false;var got=context[this.property];switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:var exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()==exp.toUpperCase());}else{result=(got==exp);}
break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:var exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()!=exp.toUpperCase());}else{result=(got!=exp);}
break;case OpenLayers.Filter.Comparison.LESS_THAN:result=got<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:result=got>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:result=got<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:result=got>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:result=(got>=this.lowerBoundary)&&(got<=this.upperBoundary);break;case OpenLayers.Filter.Comparison.LIKE:var regexp=new RegExp(this.value,"gi");result=regexp.test(got);break;}
return result;},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){var msg="'.' is an unsupported wildCard character for "+"OpenLayers.Filter.Comparison";OpenLayers.Console.error(msg);return null;}
wildCard=wildCard?wildCard:"*";singleChar=singleChar?singleChar:".";escapeChar=escapeChar?escapeChar:"!";this.value=this.value.replace(new RegExp("\\"+escapeChar+"(.|$)","g"),"\\$1");this.value=this.value.replace(new RegExp("\\"+singleChar,"g"),".");this.value=this.value.replace(new RegExp("\\"+wildCard,"g"),".*");this.value=this.value.replace(new RegExp("\\\\.\\*","g"),"\\"+wildCard);this.value=this.value.replace(new RegExp("\\\\\\.","g"),"\\"+singleChar);return this.value;},regex2value:function(){var value=this.value;value=value.replace(/!/g,"!!");value=value.replace(/(\\)?\\\./g,function($0,$1){return $1?$0:"!.";});value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"!*";});value=value.replace(/\\\\/g,"\\");value=value.replace(/\.\*/g,"*");return value;},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(),this);},CLASS_NAME:"OpenLayers.Filter.Comparison"});OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Filter.FeatureId=OpenLayers.Class(OpenLayers.Filter,{fids:null,initialize:function(options){this.fids=[];OpenLayers.Filter.prototype.initialize.apply(this,[options]);},evaluate:function(feature){for(var i=0,len=this.fids.length;i<len;i++){var fid=feature.fid||feature.id;if(fid==this.fids[i]){return true;}}
return false;},clone:function(){var filter=new OpenLayers.Filter.FeatureId();OpenLayers.Util.extend(filter,this);filter.fids=this.fids.slice();return filter;},CLASS_NAME:"OpenLayers.Filter.FeatureId"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(options){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[options]);},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this);},evaluate:function(context){switch(this.type){case OpenLayers.Filter.Logical.AND:for(var i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==false){return false;}}
return true;case OpenLayers.Filter.Logical.OR:for(var i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==true){return true;}}
return false;case OpenLayers.Filter.Logical.NOT:return(!this.filters[0].evaluate(context));}},clone:function(){var filters=[];for(var i=0,len=this.filters.length;i<len;++i){filters.push(this.filters[i].clone());}
return new OpenLayers.Filter.Logical({type:this.type,filters:filters});},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,initialize:function(options){OpenLayers.Filter.prototype.initialize.apply(this,[options]);},evaluate:function(feature){var intersect=false;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(feature.geometry){var geom=this.value;if(this.value.CLASS_NAME=="OpenLayers.Bounds"){geom=this.value.toGeometry();}
if(feature.geometry.intersects(geom)){intersect=true;}}
break;default:OpenLayers.Console.error(OpenLayers.i18n("filterEvaluateNotImplemented"));break;}
return intersect;},clone:function(){var options=OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(options);},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(components){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];if(components!=null){this.addComponents(components);}},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments);},clone:function(){var geometry=eval("new "+this.CLASS_NAME+"()");for(var i=0,len=this.components.length;i<len;i++){geometry.addComponent(this.components[i].clone());}
OpenLayers.Util.applyDefaults(geometry,this);return geometry;},getComponentsString:function(){var strings=[];for(var i=0,len=this.components.length;i<len;i++){strings.push(this.components[i].toShortString());}
return strings.join(",");},calculateBounds:function(){this.bounds=null;if(this.components&&this.components.length>0){this.setBounds(this.components[0].getBounds());for(var i=1,len=this.components.length;i<len;i++){this.extendBounds(this.components[i].getBounds());}}},addComponents:function(components){if(!(components instanceof Array)){components=[components];}
for(var i=0,len=components.length;i<len;i++){this.addComponent(components[i]);}},addComponent:function(component,index){var added=false;if(component){if(this.componentTypes==null||(OpenLayers.Util.indexOf(this.componentTypes,component.CLASS_NAME)>-1)){if(index!=null&&(index<this.components.length)){var components1=this.components.slice(0,index);var components2=this.components.slice(index,this.components.length);components1.push(component);this.components=components1.concat(components2);}else{this.components.push(component);}
component.parent=this;this.clearBounds();added=true;}}
return added;},removeComponents:function(components){if(!(components instanceof Array)){components=[components];}
for(var i=components.length-1;i>=0;--i){this.removeComponent(components[i]);}},removeComponent:function(component){OpenLayers.Util.removeItem(this.components,component);this.clearBounds();},getLength:function(){var length=0.0;for(var i=0,len=this.components.length;i<len;i++){length+=this.components[i].getLength();}
return length;},getArea:function(){var area=0.0;for(var i=0,len=this.components.length;i<len;i++){area+=this.components[i].getArea();}
return area;},getGeodesicArea:function(projection){var area=0.0;for(var i=0,len=this.components.length;i<len;i++){area+=this.components[i].getGeodesicArea(projection);}
return area;},getCentroid:function(weighted){if(!weighted){return this.components.length&&this.components[0].getCentroid();}
var len=this.components.length;if(!len){return false;}
var areas=[];var centroids=[];var areaSum=0;var minArea=Number.MAX_VALUE;var component;for(var i=0;i<len;++i){component=this.components[i];var area=component.getArea();var centroid=component.getCentroid(true);if(isNaN(area)||isNaN(centroid.x)||isNaN(centroid.y)){continue;}
areas.push(area);areaSum+=area;minArea=(area<minArea&&area>0)?area:minArea;centroids.push(centroid);}
len=areas.length;if(areaSum===0){for(var i=0;i<len;++i){areas[i]=1;}
areaSum=areas.length;}else{for(var i=0;i<len;++i){areas[i]/=minArea;}
areaSum/=minArea;}
var xSum=0,ySum=0,centroid,area;for(var i=0;i<len;++i){centroid=centroids[i];area=areas[i];xSum+=centroid.x*area;ySum+=centroid.y*area;}
return new OpenLayers.Geometry.Point(xSum/areaSum,ySum/areaSum);},getGeodesicLength:function(projection){var length=0.0;for(var i=0,len=this.components.length;i<len;i++){length+=this.components[i].getGeodesicLength(projection);}
return length;},move:function(x,y){for(var i=0,len=this.components.length;i<len;i++){this.components[i].move(x,y);}},rotate:function(angle,origin){for(var i=0,len=this.components.length;i<len;++i){this.components[i].rotate(angle,origin);}},resize:function(scale,origin,ratio){for(var i=0;i<this.components.length;++i){this.components[i].resize(scale,origin,ratio);}
return this;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best,distance;var min=Number.POSITIVE_INFINITY;for(var i=0,len=this.components.length;i<len;++i){result=this.components[i].distanceTo(geometry,options);distance=details?result.distance:result;if(distance<min){min=distance;best=result;if(min==0){break;}}}
return best;},equals:function(geometry){var equivalent=true;if(!geometry||!geometry.CLASS_NAME||(this.CLASS_NAME!=geometry.CLASS_NAME)){equivalent=false;}else if(!(geometry.components instanceof Array)||(geometry.components.length!=this.components.length)){equivalent=false;}else{for(var i=0,len=this.components.length;i<len;++i){if(!this.components[i].equals(geometry.components[i])){equivalent=false;break;}}}
return equivalent;},transform:function(source,dest){if(source&&dest){for(var i=0,len=this.components.length;i<len;i++){var component=this.components[i];component.transform(source,dest);}
this.bounds=null;}
return this;},intersects:function(geometry){var intersect=false;for(var i=0,len=this.components.length;i<len;++i){intersect=geometry.intersects(this.components[i]);if(intersect){break;}}
return intersect;},getVertices:function(nodes){var vertices=[];for(var i=0,len=this.components.length;i<len;++i){Array.prototype.push.apply(vertices,this.components[i].getVertices(nodes));}
return vertices;},CLASS_NAME:"OpenLayers.Geometry.Collection"});OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(x,y){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(x);this.y=parseFloat(y);},clone:function(obj){if(obj==null){obj=new OpenLayers.Geometry.Point(this.x,this.y);}
OpenLayers.Util.applyDefaults(obj,this);return obj;},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y);},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var distance,x0,y0,x1,y1,result;if(geometry instanceof OpenLayers.Geometry.Point){x0=this.x;y0=this.y;x1=geometry.x;y1=geometry.y;distance=Math.sqrt(Math.pow(x0-x1,2)+Math.pow(y0-y1,2));result=!details?distance:{x0:x0,y0:y0,x1:x1,y1:y1,distance:distance};}else{result=geometry.distanceTo(this,options);if(details){result={x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0,distance:result.distance};}}
return result;},equals:function(geom){var equals=false;if(geom!=null){equals=((this.x==geom.x&&this.y==geom.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(geom.x)&&isNaN(geom.y)));}
return equals;},toShortString:function(){return(this.x+", "+this.y);},move:function(x,y){this.x=this.x+x;this.y=this.y+y;this.clearBounds();},rotate:function(angle,origin){angle*=Math.PI/180;var radius=this.distanceTo(origin);var theta=angle+Math.atan2(this.y-origin.y,this.x-origin.x);this.x=origin.x+(radius*Math.cos(theta));this.y=origin.y+(radius*Math.sin(theta));this.clearBounds();},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y);},resize:function(scale,origin,ratio){ratio=(ratio==undefined)?1:ratio;this.x=origin.x+(scale*ratio*(this.x-origin.x));this.y=origin.y+(scale*(this.y-origin.y));this.clearBounds();return this;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.equals(geometry);}else{intersect=geometry.intersects(this);}
return intersect;},transform:function(source,dest){if((source&&dest)){OpenLayers.Projection.transform(this,source,dest);this.bounds=null;}
return this;},getVertices:function(nodes){return[this];},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Rectangle=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,width:null,height:null,initialize:function(x,y,width,height){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=x;this.y=y;this.width=width;this.height=height;},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x+this.width,this.y+this.height);},getLength:function(){var length=(2*this.width)+(2*this.height);return length;},getArea:function(){var area=this.width*this.height;return area;},CLASS_NAME:"OpenLayers.Geometry.Rectangle"});OpenLayers.Geometry.Surface=OpenLayers.Class(OpenLayers.Geometry,{initialize:function(){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Geometry.Surface"});OpenLayers.Layer.KaMapCache=OpenLayers.Class(OpenLayers.Layer.KaMap,{IMAGE_EXTENSIONS:{'jpeg':'jpg','gif':'gif','png':'png','png8':'png','png24':'png','dithered':'png'},DEFAULT_FORMAT:'jpeg',initialize:function(name,url,params,options){OpenLayers.Layer.KaMap.prototype.initialize.apply(this,arguments);this.extension=this.IMAGE_EXTENSIONS[this.params.i.toLowerCase()||DEFAULT_FORMAT];},getURL:function(bounds){bounds=this.adjustBounds(bounds);var mapRes=this.map.getResolution();var scale=Math.round((this.map.getScale()*10000))/10000;var pX=Math.round(bounds.left/mapRes);var pY=-Math.round(bounds.top/mapRes);var metaX=Math.floor(pX/this.tileSize.w/this.params.metaTileSize.w)*this.tileSize.w*this.params.metaTileSize.w;var metaY=Math.floor(pY/this.tileSize.h/this.params.metaTileSize.h)*this.tileSize.h*this.params.metaTileSize.h;var url=this.url;if(url instanceof Array){url=this.selectUrl(paramsString,url);}
var components=[url,"/",this.params.map,"/",scale,"/",this.params.g.replace(/\s/g,'_'),"/def/t",metaY,"/l",metaX,"/t",pY,"l",pX,".",this.extension];return components.join("");},CLASS_NAME:"OpenLayers.Layer.KaMapCache"});OpenLayers.Layer.MapServer.Untiled=OpenLayers.Class(OpenLayers.Layer.MapServer,{singleTile:true,initialize:function(name,url,params,options){OpenLayers.Layer.MapServer.prototype.initialize.apply(this,arguments);var msg="The OpenLayers.Layer.MapServer.Untiled class is deprecated and "+"will be removed in 3.0. Instead, you should use the "+"normal OpenLayers.Layer.MapServer class, passing it the option "+"'singleTile' as true.";OpenLayers.Console.warn(msg);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer.Untiled(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.MapServer.prototype.clone.apply(this,[obj]);return obj;},CLASS_NAME:"OpenLayers.Layer.MapServer.Untiled"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{EVENT_TYPES:["beforefeatureadded","beforefeaturesadded","featureadded","featuresadded","beforefeatureremoved","beforefeaturesremoved","featureremoved","featuresremoved","beforefeatureselected","featureselected","featureunselected","beforefeaturemodified","featuremodified","afterfeaturemodified","vertexmodified","sketchstarted","sketchmodified","sketchcomplete","refresh"],isBaseLayer:false,isFixed:false,isVector:true,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:true,style:null,styleMap:null,strategies:null,protocol:null,renderers:['SVG','VML','Canvas'],renderer:null,rendererOptions:null,geometryType:null,drawn:false,initialize:function(name,options){this.EVENT_TYPES=OpenLayers.Layer.Vector.prototype.EVENT_TYPES.concat(OpenLayers.Layer.prototype.EVENT_TYPES);OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(!this.renderer||!this.renderer.supported()){this.assignRenderer();}
if(!this.renderer||!this.renderer.supported()){this.renderer=null;this.displayError();}
if(!this.styleMap){this.styleMap=new OpenLayers.StyleMap();}
this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies){for(var i=0,len=this.strategies.length;i<len;i++){this.strategies[i].setLayer(this);}}},destroy:function(){if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoDestroy){strategy.destroy();}}
this.strategies=null;}
if(this.protocol){if(this.protocol.autoDestroy){this.protocol.destroy();}
this.protocol=null;}
this.destroyFeatures();this.features=null;this.selectedFeatures=null;this.unrenderedFeatures=null;if(this.renderer){this.renderer.destroy();}
this.renderer=null;this.geometryType=null;this.drawn=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Vector(this.name,this.getOptions());}
obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);var features=this.features;var len=features.length;var clonedFeatures=new Array(len);for(var i=0;i<len;++i){clonedFeatures[i]=features[i].clone();}
obj.features=clonedFeatures;return obj;},refresh:function(obj){if(this.calculateInRange()&&this.visibility){this.events.triggerEvent("refresh",obj);}},assignRenderer:function(){for(var i=0,len=this.renderers.length;i<len;i++){var rendererClass=this.renderers[i];var renderer=(typeof rendererClass=="function")?rendererClass:OpenLayers.Renderer[rendererClass];if(renderer&&renderer.prototype.supported()){this.renderer=new renderer(this.div,this.rendererOptions);break;}}},displayError:function(){if(this.reportError){OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",{'renderers':this.renderers.join("\n")}));}},setMap:function(map){OpenLayers.Layer.prototype.setMap.apply(this,arguments);if(!this.renderer){this.map.removeLayer(this);}else{this.renderer.map=this.map;this.renderer.setSize(this.map.getSize());}},afterAdd:function(){if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoActivate){strategy.activate();}}}},removeMap:function(map){this.drawn=false;if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoActivate){strategy.deactivate();}}}},onMapResize:function(){OpenLayers.Layer.prototype.onMapResize.apply(this,arguments);this.renderer.setSize(this.map.getSize());},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var coordSysUnchanged=true;if(!dragging){this.renderer.root.style.visibility="hidden";this.div.style.left=-parseInt(this.map.layerContainerDiv.style.left)+"px";this.div.style.top=-parseInt(this.map.layerContainerDiv.style.top)+"px";var extent=this.map.getExtent();coordSysUnchanged=this.renderer.setExtent(extent,zoomChanged);this.renderer.root.style.visibility="visible";if(navigator.userAgent.toLowerCase().indexOf("gecko")!=-1){this.div.scrollLeft=this.div.scrollLeft;}
if(!zoomChanged&&coordSysUnchanged){for(var i in this.unrenderedFeatures){var feature=this.unrenderedFeatures[i];this.drawFeature(feature);}}}
if(!this.drawn||zoomChanged||!coordSysUnchanged){this.drawn=true;var feature;for(var i=0,len=this.features.length;i<len;i++){this.renderer.locked=(i!==(len-1));feature=this.features[i];this.drawFeature(feature);}}},display:function(display){OpenLayers.Layer.prototype.display.apply(this,arguments);var currentDisplay=this.div.style.display;if(currentDisplay!=this.renderer.root.style.display){this.renderer.root.style.display=currentDisplay;}},addFeatures:function(features,options){if(!(features instanceof Array)){features=[features];}
var notify=!options||!options.silent;if(notify){var event={features:features};var ret=this.events.triggerEvent("beforefeaturesadded",event);if(ret===false){return;}
features=event.features;}
var featuresAdded=[];for(var i=0,len=features.length;i<len;i++){if(i!=(features.length-1)){this.renderer.locked=true;}else{this.renderer.locked=false;}
var feature=features[i];if(this.geometryType&&!(feature.geometry instanceof this.geometryType)){var throwStr=OpenLayers.i18n('componentShouldBe',{'geomType':this.geometryType.prototype.CLASS_NAME});throw throwStr;}
feature.layer=this;if(!feature.style&&this.style){feature.style=OpenLayers.Util.extend({},this.style);}
if(notify){if(this.events.triggerEvent("beforefeatureadded",{feature:feature})===false){continue;};this.preFeatureInsert(feature);}
featuresAdded.push(feature);this.features.push(feature);this.drawFeature(feature);if(notify){this.events.triggerEvent("featureadded",{feature:feature});this.onFeatureInsert(feature);}}
if(notify){this.events.triggerEvent("featuresadded",{features:featuresAdded});}},removeFeatures:function(features,options){if(!features||features.length===0){return;}
if(features===this.features){return this.removeAllFeatures(options);}
if(!(features instanceof Array)){features=[features];}
if(features===this.selectedFeatures){features=features.slice();}
var notify=!options||!options.silent;if(notify){this.events.triggerEvent("beforefeaturesremoved",{features:features});}
for(var i=features.length-1;i>=0;i--){if(i!=0&&features[i-1].geometry){this.renderer.locked=true;}else{this.renderer.locked=false;}
var feature=features[i];delete this.unrenderedFeatures[feature.id];if(notify){this.events.triggerEvent("beforefeatureremoved",{feature:feature});}
this.features=OpenLayers.Util.removeItem(this.features,feature);feature.layer=null;if(feature.geometry){this.renderer.eraseFeatures(feature);}
if(OpenLayers.Util.indexOf(this.selectedFeatures,feature)!=-1){OpenLayers.Util.removeItem(this.selectedFeatures,feature);}
if(notify){this.events.triggerEvent("featureremoved",{feature:feature});}}
if(notify){this.events.triggerEvent("featuresremoved",{features:features});}},removeAllFeatures:function(options){var notify=!options||!options.silent;var features=this.features;if(notify){this.events.triggerEvent("beforefeaturesremoved",{features:features});}
var feature;for(var i=features.length-1;i>=0;i--){feature=features[i];if(notify){this.events.triggerEvent("beforefeatureremoved",{feature:feature});}
feature.layer=null;if(notify){this.events.triggerEvent("featureremoved",{feature:feature});}}
this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures=[];if(notify){this.events.triggerEvent("featuresremoved",{features:features});}},destroyFeatures:function(features,options){var all=(features==undefined);if(all){features=this.features;}
if(features){this.removeFeatures(features,options);for(var i=features.length-1;i>=0;i--){features[i].destroy();}}},drawFeature:function(feature,style){if(!this.drawn){return}
if(typeof style!="object"){if(!style&&feature.state===OpenLayers.State.DELETE){style="delete";}
var renderIntent=style||feature.renderIntent;style=feature.style||this.style;if(!style){style=this.styleMap.createSymbolizer(feature,renderIntent);}}
if(!this.renderer.drawFeature(feature,style)){this.unrenderedFeatures[feature.id]=feature;}else{delete this.unrenderedFeatures[feature.id];};},eraseFeatures:function(features){this.renderer.eraseFeatures(features);},getFeatureFromEvent:function(evt){if(!this.renderer){OpenLayers.Console.error(OpenLayers.i18n("getFeatureError"));return null;}
var featureId=this.renderer.getFeatureIdFromEvent(evt);return this.getFeatureById(featureId);},getFeatureBy:function(property,value){var feature=null;for(var i=0,len=this.features.length;i<len;++i){if(this.features[i][property]==value){feature=this.features[i];break;}}
return feature;},getFeatureById:function(featureId){return this.getFeatureBy('id',featureId);},getFeatureByFid:function(featureFid){return this.getFeatureBy('fid',featureFid);},onFeatureInsert:function(feature){},preFeatureInsert:function(feature){},getDataExtent:function(){var maxExtent=null;var features=this.features;if(features&&(features.length>0)){maxExtent=new OpenLayers.Bounds();var geometry=null;for(var i=0,len=features.length;i<len;i++){geometry=features[i].geometry;if(geometry){maxExtent.extend(geometry.getBounds());}}}
return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.WMS.Post=OpenLayers.Class(OpenLayers.Layer.WMS,{tileClass:null,unsupportedBrowsers:["mozilla","firefox","opera"],SUPPORTED_TRANSITIONS:[],initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.WMS.prototype.initialize.apply(this,newArguments);this.tileClass=OpenLayers.Util.indexOf(this.unsupportedBrowsers,OpenLayers.Util.getBrowserName())!=-1?OpenLayers.Tile.Image:OpenLayers.Tile.Image.IFrame;},addTile:function(bounds,position){return new this.tileClass(this,position,bounds,null,this.tileSize);},CLASS_NAME:'OpenLayers.Layer.WMS.Post'});OpenLayers.Layer.WMS.Untiled=OpenLayers.Class(OpenLayers.Layer.WMS,{singleTile:true,initialize:function(name,url,params,options){OpenLayers.Layer.WMS.prototype.initialize.apply(this,arguments);var msg="The OpenLayers.Layer.WMS.Untiled class is deprecated and "+"will be removed in 3.0. Instead, you should use the "+"normal OpenLayers.Layer.WMS class, passing it the option "+"'singleTile' as true.";OpenLayers.Console.warn(msg);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS.Untiled(this.name,this.url,this.params,this.getOptions());}
obj=OpenLayers.Layer.WMS.prototype.clone.apply(this,[obj]);return obj;},CLASS_NAME:"OpenLayers.Layer.WMS.Untiled"});OpenLayers.Strategy.Filter=OpenLayers.Class(OpenLayers.Strategy,{filter:null,cache:null,caching:false,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);if(!this.filter||!(this.filter instanceof OpenLayers.Filter)){throw new Error("Filter strategy must be constructed with a filter");}},activate:function(){var activated=OpenLayers.Strategy.prototype.activate.apply(this,arguments);if(activated){this.cache=[];this.layer.events.on({"beforefeaturesadded":this.handleAdd,"beforefeaturesremoved":this.handleRemove,scope:this});}
return activated;},deactivate:function(){this.cache=null;if(this.layer&&this.layer.events){this.layer.events.un({"beforefeaturesadded":this.handleAdd,"beforefeaturesremoved":this.handleRemove,scope:this});}
return OpenLayers.Strategy.prototype.deactivate.apply(this,arguments);},handleAdd:function(event){if(!this.caching){var features=event.features;event.features=[];var feature;for(var i=0,ii=features.length;i<ii;++i){feature=features[i];if(this.filter.evaluate(feature)){event.features.push(feature);}else{this.cache.push(feature);}}}},handleRemove:function(event){if(!this.caching){this.cache=[];}},setFilter:function(filter){this.filter=filter;var previousCache=this.cache;this.cache=[];this.handleAdd({features:this.layer.features});if(this.cache.length>0){this.caching=true;this.layer.removeFeatures(this.cache.slice(),{silent:true});this.caching=false;}
if(previousCache.length>0){var event={features:previousCache};this.handleAdd(event);this.caching=true;this.layer.addFeatures(event.features,{silent:true});this.caching=false;}},CLASS_NAME:"OpenLayers.Strategy.Filter"});OpenLayers.Style2=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,initialize:function(config){OpenLayers.Util.extend(this,config);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i=0,len=this.rules.length;i<len;i++){this.rules[i].destroy();}
delete this.rules;},clone:function(){var config=OpenLayers.Util.extend({},this);if(this.rules){config.rules=[];for(var i=0,len=this.rules.length;i<len;++i){config.rules.push(this.rules[i].clone());}}
return new OpenLayers.Style2(config);},CLASS_NAME:"OpenLayers.Style2"});OpenLayers.Control.GetFeature=OpenLayers.Class(OpenLayers.Control,{protocol:null,multipleKey:null,toggleKey:null,modifiers:null,multiple:false,click:true,single:true,clickout:true,toggle:false,clickTolerance:5,hover:false,box:false,maxFeatures:10,features:null,hoverFeature:null,handlerOptions:null,handlers:null,hoverResponse:null,filterType:OpenLayers.Filter.Spatial.BBOX,EVENT_TYPES:["featureselected","featuresselected","featureunselected","clickout","beforefeatureselected","beforefeaturesselected","hoverfeature","outfeature"],initialize:function(options){this.EVENT_TYPES=OpenLayers.Control.GetFeature.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);options.handlerOptions=options.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[options]);this.features={};this.handlers={};if(this.click){this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.selectClick},this.handlerOptions.click||{});}
if(this.box){this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},OpenLayers.Util.extend(this.handlerOptions.box,{boxDivClassName:"olHandlerBoxSelectFeature"}));}
if(this.hover){this.handlers.hover=new OpenLayers.Handler.Hover(this,{'move':this.cancelHover,'pause':this.selectHover},OpenLayers.Util.extend(this.handlerOptions.hover,{'delay':250}));}},activate:function(){if(!this.active){for(var i in this.handlers){this.handlers[i].activate();}}
return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){if(this.active){for(var i in this.handlers){this.handlers[i].deactivate();}}
return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},selectClick:function(evt){var bounds=this.pixelToBounds(evt.xy);this.setModifiers(evt);this.request(bounds,{single:this.single});},selectBox:function(position){var bounds;if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);}else{if(this.click){return;}
bounds=this.pixelToBounds(position);}
this.setModifiers(this.handlers.box.dragHandler.evt);this.request(bounds);},selectHover:function(evt){var bounds=this.pixelToBounds(evt.xy);this.request(bounds,{single:true,hover:true});},cancelHover:function(){if(this.hoverResponse){this.protocol.abort(this.hoverResponse);this.hoverResponse=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait");}},request:function(bounds,options){options=options||{};var filter=new OpenLayers.Filter.Spatial({type:this.filterType,value:bounds});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");var response=this.protocol.read({maxFeatures:options.single==true?this.maxFeatures:undefined,filter:filter,callback:function(result){if(result.success()){if(result.features.length){if(options.single==true){this.selectBestFeature(result.features,bounds.getCenterLonLat(),options);}else{this.select(result.features);}}else if(options.hover){this.hoverSelect();}else{this.events.triggerEvent("clickout");if(this.clickout){this.unselectAll();}}}
OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait");},scope:this});if(options.hover==true){this.hoverResponse=response;}},selectBestFeature:function(features,clickPosition,options){options=options||{};if(features.length){var point=new OpenLayers.Geometry.Point(clickPosition.lon,clickPosition.lat);var feature,resultFeature,dist;var minDist=Number.MAX_VALUE;for(var i=0;i<features.length;++i){feature=features[i];if(feature.geometry){dist=point.distanceTo(feature.geometry,{edge:false});if(dist<minDist){minDist=dist;resultFeature=feature;if(minDist==0){break;}}}}
if(options.hover==true){this.hoverSelect(resultFeature);}else{this.select(resultFeature||features);}}},setModifiers:function(evt){this.modifiers={multiple:this.multiple||(this.multipleKey&&evt[this.multipleKey]),toggle:this.toggle||(this.toggleKey&&evt[this.toggleKey])};},select:function(features){if(!this.modifiers.multiple&&!this.modifiers.toggle){this.unselectAll();}
if(!(features instanceof Array)){features=[features];}
var cont=this.events.triggerEvent("beforefeaturesselected",{features:features});if(cont!==false){var selectedFeatures=[];var feature;for(var i=0,len=features.length;i<len;++i){feature=features[i];if(this.features[feature.fid||feature.id]){if(this.modifiers.toggle){this.unselect(this.features[feature.fid||feature.id]);}}else{cont=this.events.triggerEvent("beforefeatureselected",{feature:feature});if(cont!==false){this.features[feature.fid||feature.id]=feature;selectedFeatures.push(feature);this.events.triggerEvent("featureselected",{feature:feature});}}}
this.events.triggerEvent("featuresselected",{features:selectedFeatures});}},hoverSelect:function(feature){var fid=feature?feature.fid||feature.id:null;var hfid=this.hoverFeature?this.hoverFeature.fid||this.hoverFeature.id:null;if(hfid&&hfid!=fid){this.events.triggerEvent("outfeature",{feature:this.hoverFeature});this.hoverFeature=null;}
if(fid&&fid!=hfid){this.events.triggerEvent("hoverfeature",{feature:feature});this.hoverFeature=feature;}},unselect:function(feature){delete this.features[feature.fid||feature.id];this.events.triggerEvent("featureunselected",{feature:feature});},unselectAll:function(){for(var fid in this.features){this.unselect(this.features[fid]);}},setMap:function(map){for(var i in this.handlers){this.handlers[i].setMap(map);}
OpenLayers.Control.prototype.setMap.apply(this,arguments);},pixelToBounds:function(pixel){var llPx=pixel.add(-this.clickTolerance/2,this.clickTolerance/2);var urPx=pixel.add(this.clickTolerance/2,-this.clickTolerance/2);var ll=this.map.getLonLatFromPixel(llPx);var ur=this.map.getLonLatFromPixel(urPx);return new OpenLayers.Bounds(ll.lon,ll.lat,ur.lon,ur.lat);},CLASS_NAME:"OpenLayers.Control.GetFeature"});OpenLayers.Control.Snapping=OpenLayers.Class(OpenLayers.Control,{EVENT_TYPES:["beforesnap","snap","unsnap"],DEFAULTS:{tolerance:10,node:true,edge:true,vertex:true},greedy:true,precedence:["node","vertex","edge"],resolution:null,geoToleranceCache:null,layer:null,feature:null,point:null,initialize:function(options){Array.prototype.push.apply(this.EVENT_TYPES,OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);this.options=options||{};if(this.options.layer){this.setLayer(this.options.layer);}
var defaults=OpenLayers.Util.extend({},this.options.defaults);this.defaults=OpenLayers.Util.applyDefaults(defaults,this.DEFAULTS);this.setTargets(this.options.targets);if(this.targets.length===0&&this.layer){this.addTargetLayer(this.layer);}
this.geoToleranceCache={};},setLayer:function(layer){if(this.active){this.deactivate();this.layer=layer;this.activate();}else{this.layer=layer;}},setTargets:function(targets){this.targets=[];if(targets&&targets.length){var target;for(var i=0,len=targets.length;i<len;++i){target=targets[i];if(target instanceof OpenLayers.Layer.Vector){this.addTargetLayer(target);}else{this.addTarget(target);}}}},addTargetLayer:function(layer){this.addTarget({layer:layer});},addTarget:function(target){target=OpenLayers.Util.applyDefaults(target,this.defaults);target.nodeTolerance=target.nodeTolerance||target.tolerance;target.vertexTolerance=target.vertexTolerance||target.tolerance;target.edgeTolerance=target.edgeTolerance||target.tolerance;this.targets.push(target);},removeTargetLayer:function(layer){var target;for(var i=this.targets.length-1;i>=0;--i){target=this.targets[i];if(target.layer===layer){this.removeTarget(target);}}},removeTarget:function(target){return OpenLayers.Util.removeItem(this.targets,target);},activate:function(){var activated=OpenLayers.Control.prototype.activate.call(this);if(activated){if(this.layer&&this.layer.events){this.layer.events.on({sketchstarted:this.onSketchModified,sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});}}
return activated;},deactivate:function(){var deactivated=OpenLayers.Control.prototype.deactivate.call(this);if(deactivated){if(this.layer&&this.layer.events){this.layer.events.un({sketchstarted:this.onSketchModified,sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});}}
this.feature=null;this.point=null;return deactivated;},onSketchModified:function(event){this.feature=event.feature;this.considerSnapping(event.vertex,event.vertex);},onVertexModified:function(event){this.feature=event.feature;var loc=this.layer.map.getLonLatFromViewPortPx(event.pixel);this.considerSnapping(event.vertex,new OpenLayers.Geometry.Point(loc.lon,loc.lat));},considerSnapping:function(point,loc){var best={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY,x:null,y:null};var snapped=false;var result,target;for(var i=0,len=this.targets.length;i<len;++i){target=this.targets[i];result=this.testTarget(target,loc);if(result){if(this.greedy){best=result;best.target=target;snapped=true;break;}else{if((result.rank<best.rank)||(result.rank===best.rank&&result.dist<best.dist)){best=result;best.target=target;snapped=true;}}}}
if(snapped){var proceed=this.events.triggerEvent("beforesnap",{point:point,x:best.x,y:best.y,distance:best.dist,layer:best.target.layer,snapType:this.precedence[best.rank]});if(proceed!==false){point.x=best.x;point.y=best.y;this.point=point;this.events.triggerEvent("snap",{point:point,snapType:this.precedence[best.rank],layer:best.target.layer,distance:best.dist});}else{snapped=false;}}
if(this.point&&!snapped){point.x=loc.x;point.y=loc.y;this.point=null;this.events.triggerEvent("unsnap",{point:point});}},testTarget:function(target,loc){var tolerance={node:this.getGeoTolerance(target.nodeTolerance),vertex:this.getGeoTolerance(target.vertexTolerance),edge:this.getGeoTolerance(target.edgeTolerance)};var maxTolerance=Math.max(tolerance.node,tolerance.vertex,tolerance.edge);var result={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY};var eligible=false;var features=target.layer.features;var feature,type,vertices,vertex,closest,dist,found;var numTypes=this.precedence.length;var ll=new OpenLayers.LonLat(loc.x,loc.y);for(var i=0,len=features.length;i<len;++i){feature=features[i];if(feature!==this.feature&&!feature._sketch&&feature.state!==OpenLayers.State.DELETE&&(!target.filter||target.filter.evaluate(feature.attributes))){if(feature.atPoint(ll,maxTolerance,maxTolerance)){for(var j=0,stop=Math.min(result.rank+1,numTypes);j<stop;++j){type=this.precedence[j];if(target[type]){if(type==="edge"){closest=feature.geometry.distanceTo(loc,{details:true});dist=closest.distance;if(dist<=tolerance[type]&&dist<result.dist){result={rank:j,dist:dist,x:closest.x0,y:closest.y0};eligible=true;break;}}else{vertices=feature.geometry.getVertices(type==="node");found=false;for(var k=0,klen=vertices.length;k<klen;++k){vertex=vertices[k];dist=vertex.distanceTo(loc);if(dist<=tolerance[type]&&(j<result.rank||(j===result.rank&&dist<result.dist))){result={rank:j,dist:dist,x:vertex.x,y:vertex.y};eligible=true;found=true;}}
if(found){break;}}}}}}}
return eligible?result:null;},getGeoTolerance:function(tolerance){var resolution=this.layer.map.getResolution();if(resolution!==this.resolution){this.resolution=resolution;this.geoToleranceCache={};}
var geoTolerance=this.geoToleranceCache[tolerance];if(geoTolerance===undefined){geoTolerance=tolerance*resolution;this.geoToleranceCache[tolerance]=geoTolerance;}
return geoTolerance;},destroy:function(){if(this.active){this.deactivate();}
delete this.layer;delete this.targets;OpenLayers.Control.prototype.destroy.call(this);},CLASS_NAME:"OpenLayers.Control.Snapping"});OpenLayers.Format.Filter=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.0.0",version:null,parser:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},write:function(filter,options){var version=(options&&options.version)||this.version||this.defaultVersion;if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format.Filter["v"+version.replace(/\./g,"_")];if(!format){throw"Can't find a Filter parser for version "+
version;}
this.parser=new format(this.options);}
return this.parser.write(filter);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var version=this.version;if(!version){version=this.defaultVersion;}
if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format.Filter["v"+version.replace(/\./g,"_")];if(!format){throw"Can't find a Filter parser for version "+
version;}
this.parser=new format(this.options);}
var filter=this.parser.read(data);return filter;},CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Format.SLD=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.0.0",version:null,namedLayersAsArray:false,parser:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},write:function(sld,options){var version=(options&&options.version)||this.version||this.defaultVersion;if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format.SLD["v"+version.replace(/\./g,"_")];if(!format){throw"Can't find a SLD parser for version "+
version;}
this.parser=new format(this.options);}
var root=this.parser.write(sld);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},read:function(data,options){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var root=data.documentElement;var version=this.version;if(!version){version=root.getAttribute("version");if(!version){version=this.defaultVersion;}}
if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format.SLD["v"+version.replace(/\./g,"_")];if(!format){throw"Can't find a SLD parser for version "+
version;}
this.parser=new format(this.options);}
var sld=this.parser.read(data,options);return sld;},CLASS_NAME:"OpenLayers.Format.SLD"});OpenLayers.Format.Text=OpenLayers.Class(OpenLayers.Format,{defaultStyle:null,extractStyles:true,initialize:function(options){options=options||{};if(options.extractStyles!==false){options.defaultStyle={'externalGraphic':OpenLayers.Util.getImagesLocation()+"marker.png",'graphicWidth':21,'graphicHeight':25,'graphicXOffset':-10.5,'graphicYOffset':-12.5};}
OpenLayers.Format.prototype.initialize.apply(this,[options]);},read:function(text){var lines=text.split('\n');var columns;var features=[];for(var lcv=0;lcv<(lines.length-1);lcv++){var currLine=lines[lcv].replace(/^\s*/,'').replace(/\s*$/,'');if(currLine.charAt(0)!='#'){if(!columns){columns=currLine.split('\t');}else{var vals=currLine.split('\t');var geometry=new OpenLayers.Geometry.Point(0,0);var attributes={};var style=this.defaultStyle?OpenLayers.Util.applyDefaults({},this.defaultStyle):null;var icon,iconSize,iconOffset,overflow;var set=false;for(var valIndex=0;valIndex<vals.length;valIndex++){if(vals[valIndex]){if(columns[valIndex]=='point'){var coords=vals[valIndex].split(',');geometry.y=parseFloat(coords[0]);geometry.x=parseFloat(coords[1]);set=true;}else if(columns[valIndex]=='lat'){geometry.y=parseFloat(vals[valIndex]);set=true;}else if(columns[valIndex]=='lon'){geometry.x=parseFloat(vals[valIndex]);set=true;}else if(columns[valIndex]=='title')
attributes['title']=vals[valIndex];else if(columns[valIndex]=='image'||columns[valIndex]=='icon'&&style){style['externalGraphic']=vals[valIndex];}else if(columns[valIndex]=='iconSize'&&style){var size=vals[valIndex].split(',');style['graphicWidth']=parseFloat(size[0]);style['graphicHeight']=parseFloat(size[1]);}else if(columns[valIndex]=='iconOffset'&&style){var offset=vals[valIndex].split(',');style['graphicXOffset']=parseFloat(offset[0]);style['graphicYOffset']=parseFloat(offset[1]);}else if(columns[valIndex]=='description'){attributes['description']=vals[valIndex];}else if(columns[valIndex]=='overflow'){attributes['overflow']=vals[valIndex];}else{attributes[columns[valIndex]]=vals[valIndex];}}}
if(set){if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}
var feature=new OpenLayers.Feature.Vector(geometry,attributes,style);features.push(feature);}}}}
return features;},CLASS_NAME:"OpenLayers.Format.Text"});OpenLayers.Geometry.MultiPoint=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Point"],initialize:function(components){OpenLayers.Geometry.Collection.prototype.initialize.apply(this,arguments);},addPoint:function(point,index){this.addComponent(point,index);},removePoint:function(point){this.removeComponent(point);},CLASS_NAME:"OpenLayers.Geometry.MultiPoint"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:false,drawing:false,mouseDown:false,lastDown:null,lastUp:null,persist:false,layerOptions:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
OpenLayers.Handler.prototype.initialize.apply(this,arguments);},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,arguments)){return false;}
var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);return true;},createFeature:function(pixel){var lonlat=this.map.getLonLatFromPixel(pixel);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat));this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.layer.addFeatures([this.point],{silent:true});},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){return false;}
if(this.drawing){this.cancel();}
this.destroyFeature();if(this.layer.map!=null){this.layer.destroy(false);}
this.layer=null;return true;},destroyFeature:function(){if(this.layer){this.layer.destroyFeatures();}
this.point=null;},finalize:function(cancel){var key=cancel?"cancel":"done";this.drawing=false;this.mouseDown=false;this.lastDown=null;this.lastUp=null;this.callback(key,[this.geometryClone()]);if(cancel||!this.persist){this.destroyFeature();}},cancel:function(){this.finalize(true);},click:function(evt){OpenLayers.Event.stop(evt);return false;},dblclick:function(evt){OpenLayers.Event.stop(evt);return false;},modifyFeature:function(pixel){var lonlat=this.map.getLonLatFromPixel(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.point,this.style);},getGeometry:function(){var geometry=this.point&&this.point.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiPoint([geometry]);}
return geometry;},geometryClone:function(){var geom=this.getGeometry();return geom&&geom.clone();},mousedown:function(evt){if(!this.checkModifiers(evt)){return true;}
if(this.lastDown&&this.lastDown.equals(evt.xy)){return true;}
this.drawing=true;if(this.lastDown==null){if(this.persist){this.destroyFeature();}
this.createFeature(evt.xy);}else{this.modifyFeature(evt.xy);}
this.lastDown=evt.xy;return false;},mousemove:function(evt){if(this.drawing){this.modifyFeature(evt.xy);}
return true;},mouseup:function(evt){if(this.drawing){this.finalize();return false;}else{return true;}},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Layer.GML=OpenLayers.Class(OpenLayers.Layer.Vector,{loaded:false,format:null,formatOptions:null,initialize:function(name,url,options){var newArguments=[];newArguments.push(name,options);OpenLayers.Layer.Vector.prototype.initialize.apply(this,newArguments);this.url=url;},setVisibility:function(visibility,noEvent){OpenLayers.Layer.Vector.prototype.setVisibility.apply(this,arguments);if(this.visibility&&!this.loaded){this.loadGML();}},moveTo:function(bounds,zoomChanged,minor){OpenLayers.Layer.Vector.prototype.moveTo.apply(this,arguments);if(this.visibility&&!this.loaded){this.loadGML();}},loadGML:function(){if(!this.loaded){this.events.triggerEvent("loadstart");OpenLayers.Request.GET({url:this.url,success:this.requestSuccess,failure:this.requestFailure,scope:this});this.loaded=true;}},setUrl:function(url){this.url=url;this.destroyFeatures();this.loaded=false;this.loadGML();},requestSuccess:function(request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
var options={};OpenLayers.Util.extend(options,this.formatOptions);if(this.map&&!this.projection.equals(this.map.getProjectionObject())){options.externalProjection=this.projection;options.internalProjection=this.map.getProjectionObject();}
var gml=this.format?new this.format(options):new OpenLayers.Format.GML(options);this.addFeatures(gml.read(doc));this.events.triggerEvent("loadend");},requestFailure:function(request){OpenLayers.Console.userError(OpenLayers.i18n("errorLoadingGML",{'url':this.url}));this.events.triggerEvent("loadend");},CLASS_NAME:"OpenLayers.Layer.GML"});OpenLayers.Layer.PointTrack=OpenLayers.Class(OpenLayers.Layer.Vector,{dataFrom:null,initialize:function(name,options){OpenLayers.Layer.Vector.prototype.initialize.apply(this,arguments);},addNodes:function(pointFeatures){if(pointFeatures.length<2){OpenLayers.Console.error("At least two point features have to be added to create"+"a line from");return;}
var lines=new Array(pointFeatures.length-1);var pointFeature,startPoint,endPoint;for(var i=0,len=pointFeatures.length;i<len;i++){pointFeature=pointFeatures[i];endPoint=pointFeature.geometry;if(!endPoint){var lonlat=pointFeature.lonlat;endPoint=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);}else if(endPoint.CLASS_NAME!="OpenLayers.Geometry.Point"){OpenLayers.Console.error("Only features with point geometries are supported.");return;}
if(i>0){var attributes=(this.dataFrom!=null)?(pointFeatures[i+this.dataFrom].data||pointFeatures[i+this.dataFrom].attributes):null;var line=new OpenLayers.Geometry.LineString([startPoint,endPoint]);lines[i-1]=new OpenLayers.Feature.Vector(line,attributes);}
startPoint=endPoint;}
this.addFeatures(lines);},CLASS_NAME:"OpenLayers.Layer.PointTrack"});OpenLayers.Layer.PointTrack.dataFrom={'SOURCE_NODE':-1,'TARGET_NODE':0};OpenLayers.Layer.Vector.RootContainer=OpenLayers.Class(OpenLayers.Layer.Vector,{displayInLayerSwitcher:false,layers:null,initialize:function(name,options){OpenLayers.Layer.Vector.prototype.initialize.apply(this,arguments);},display:function(){},getFeatureFromEvent:function(evt){var layers=this.layers;var feature;for(var i=0;i<layers.length;i++){feature=layers[i].getFeatureFromEvent(evt);if(feature){return feature;}}},setMap:function(map){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);this.collectRoots();map.events.register("changelayer",this,this.handleChangeLayer);},removeMap:function(map){map.events.unregister("changelayer",this,this.handleChangeLayer);this.resetRoots();OpenLayers.Layer.Vector.prototype.removeMap.apply(this,arguments);},collectRoots:function(){var layer;for(var i=0;i<this.map.layers.length;++i){layer=this.map.layers[i];if(OpenLayers.Util.indexOf(this.layers,layer)!=-1){layer.renderer.moveRoot(this.renderer);}}},resetRoots:function(){var layer;for(var i=0;i<this.layers.length;++i){layer=this.layers[i];if(this.renderer&&layer.renderer.getRenderLayerId()==this.id){this.renderer.moveRoot(layer.renderer);}}},handleChangeLayer:function(evt){var layer=evt.layer;if(evt.property=="order"&&OpenLayers.Util.indexOf(this.layers,layer)!=-1){this.resetRoots();this.collectRoots();}},CLASS_NAME:"OpenLayers.Layer.Vector.RootContainer"});OpenLayers.Layer.WFS=OpenLayers.Class(OpenLayers.Layer.Vector,OpenLayers.Layer.Markers,{isBaseLayer:false,tile:null,ratio:2,DEFAULT_PARAMS:{service:"WFS",version:"1.0.0",request:"GetFeature"},featureClass:null,format:null,formatObject:null,formatOptions:null,vectorMode:true,encodeBBOX:false,extractAttributes:false,initialize:function(name,url,params,options){if(options==undefined){options={};}
if(options.featureClass||!OpenLayers.Layer.Vector||!OpenLayers.Feature.Vector){this.vectorMode=false;}
params=OpenLayers.Util.upperCaseObject(params);OpenLayers.Util.extend(options,{'reportError':false});var newArguments=[];newArguments.push(name,options);OpenLayers.Layer.Vector.prototype.initialize.apply(this,newArguments);if(!this.renderer||!this.vectorMode){this.vectorMode=false;if(!options.featureClass){options.featureClass=OpenLayers.Feature.WFS;}
OpenLayers.Layer.Markers.prototype.initialize.apply(this,newArguments);}
if(this.params&&this.params.typename&&!this.options.typename){this.options.typename=this.params.typename;}
if(!this.options.geometry_column){this.options.geometry_column="the_geom";}
this.params=OpenLayers.Util.applyDefaults(params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));this.url=url;},destroy:function(){if(this.vectorMode){OpenLayers.Layer.Vector.prototype.destroy.apply(this,arguments);}else{OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);}
if(this.tile){this.tile.destroy();}
this.tile=null;this.ratio=null;this.featureClass=null;this.format=null;if(this.formatObject&&this.formatObject.destroy){this.formatObject.destroy();}
this.formatObject=null;this.formatOptions=null;this.vectorMode=null;this.encodeBBOX=null;this.extractAttributes=null;},setMap:function(map){if(this.vectorMode){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);var options={'extractAttributes':this.extractAttributes};OpenLayers.Util.extend(options,this.formatOptions);if(this.map&&!this.projection.equals(this.map.getProjectionObject())){options.externalProjection=this.projection;options.internalProjection=this.map.getProjectionObject();}
this.formatObject=this.format?new this.format(options):new OpenLayers.Format.GML(options);}else{OpenLayers.Layer.Markers.prototype.setMap.apply(this,arguments);}},moveTo:function(bounds,zoomChanged,dragging){if(this.vectorMode){OpenLayers.Layer.Vector.prototype.moveTo.apply(this,arguments);}else{OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);}
if(dragging){return false;}
if(zoomChanged){if(this.vectorMode){this.renderer.clear();}}
if(this.options.minZoomLevel){OpenLayers.Console.warn(OpenLayers.i18n('minZoomLevelError'));if(this.map.getZoom()<this.options.minZoomLevel){return null;}}
if(bounds==null){bounds=this.map.getExtent();}
var firstRendering=(this.tile==null);var outOfBounds=(!firstRendering&&!this.tile.bounds.containsBounds(bounds));if(zoomChanged||firstRendering||(!dragging&&outOfBounds)){var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var tileSize=this.map.getSize();tileSize.w=tileSize.w*this.ratio;tileSize.h=tileSize.h*this.ratio;var ul=new OpenLayers.LonLat(tileBounds.left,tileBounds.top);var pos=this.map.getLayerPxFromLonLat(ul);var url=this.getFullRequestString();var params=null;var filter=this.params.filter||this.params.FILTER;if(filter){params={FILTER:filter};}
else{params={BBOX:this.encodeBBOX?tileBounds.toBBOX():tileBounds.toArray()};}
if(this.map&&!this.projection.equals(this.map.getProjectionObject())){var projectedBounds=tileBounds.clone();projectedBounds.transform(this.map.getProjectionObject(),this.projection);if(!filter){params.BBOX=this.encodeBBOX?projectedBounds.toBBOX():projectedBounds.toArray();}}
url+="&"+OpenLayers.Util.getParameterString(params);if(!this.tile){this.tile=new OpenLayers.Tile.WFS(this,pos,tileBounds,url,tileSize);this.addTileMonitoringHooks(this.tile);this.tile.draw();}else{if(this.vectorMode){this.destroyFeatures();this.renderer.clear();}else{this.clearMarkers();}
this.removeTileMonitoringHooks(this.tile);this.tile.destroy();this.tile=null;this.tile=new OpenLayers.Tile.WFS(this,pos,tileBounds,url,tileSize);this.addTileMonitoringHooks(this.tile);this.tile.draw();}}},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this==this.layer.tile){this.layer.events.triggerEvent("loadstart");}};tile.events.register("loadstart",tile,tile.onLoadStart);tile.onLoadEnd=function(){if(this==this.layer.tile){this.layer.events.triggerEvent("tileloaded");this.layer.events.triggerEvent("loadend");}};tile.events.register("loadend",tile,tile.onLoadEnd);tile.events.register("unload",tile,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,scope:tile});},onMapResize:function(){if(this.vectorMode){OpenLayers.Layer.Vector.prototype.onMapResize.apply(this,arguments);}else{OpenLayers.Layer.Markers.prototype.onMapResize.apply(this,arguments);}},display:function(){if(this.vectorMode){OpenLayers.Layer.Vector.prototype.display.apply(this,arguments);}else{OpenLayers.Layer.Markers.prototype.display.apply(this,arguments);}},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.HTTPRequest.prototype.mergeNewParams.apply(this,newArguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WFS(this.name,this.url,this.params,this.getOptions());}
if(this.vectorMode){obj=OpenLayers.Layer.Vector.prototype.clone.apply(this,[obj]);}else{obj=OpenLayers.Layer.Markers.prototype.clone.apply(this,[obj]);}
return obj;},getFullRequestString:function(newParams,altUrl){var projectionCode=this.projection.getCode()||this.map.getProjection();this.params.SRS=(projectionCode=="none")?null:projectionCode;return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},commit:function(){if(!this.writer){var options={};if(this.map&&!this.projection.equals(this.map.getProjectionObject())){options.externalProjection=this.projection;options.internalProjection=this.map.getProjectionObject();}
this.writer=new OpenLayers.Format.WFS(options,this);}
var data=this.writer.write(this.features);OpenLayers.Request.POST({url:this.url,data:data,success:this.commitSuccess,failure:this.commitFailure,scope:this});},commitSuccess:function(request){var response=request.responseText;if(response.indexOf('SUCCESS')!=-1){this.commitReport(OpenLayers.i18n("commitSuccess",{'response':response}));for(var i=0;i<this.features.length;i++){this.features[i].state=null;}}else if(response.indexOf('FAILED')!=-1||response.indexOf('Exception')!=-1){this.commitReport(OpenLayers.i18n("commitFailed",{'response':response}));}},commitFailure:function(request){},commitReport:function(string,response){OpenLayers.Console.userError(string);},refresh:function(){if(this.tile){if(this.vectorMode){this.renderer.clear();this.features.length=0;}else{this.clearMarkers();this.markers.length=0;}
this.tile.draw();}},getDataExtent:function(){var extent;if(this.vectorMode){extent=OpenLayers.Layer.Vector.prototype.getDataExtent.apply(this);}else{extent=OpenLayers.Layer.Markers.prototype.getDataExtent.apply(this);}
return extent;},setOpacity:function(opacity){if(this.vectorMode){OpenLayers.Layer.Vector.prototype.setOpacity.apply(this,[opacity]);}else{OpenLayers.Layer.Markers.prototype.setOpacity.apply(this,[opacity]);}},CLASS_NAME:"OpenLayers.Layer.WFS"});OpenLayers.Protocol.HTTP=OpenLayers.Class(OpenLayers.Protocol,{url:null,headers:null,params:null,callback:null,scope:null,readWithPOST:false,wildcarded:false,initialize:function(options){options=options||{};this.params={};this.headers={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);},destroy:function(){this.params=null;this.headers=null;OpenLayers.Protocol.prototype.destroy.apply(this);},read:function(options){OpenLayers.Protocol.prototype.read.apply(this,arguments);options=OpenLayers.Util.applyDefaults(options,this.options);options.params=OpenLayers.Util.applyDefaults(options.params,this.options.params);if(options.filter){options.params=this.filterToParams(options.filter,options.params);}
var readWithPOST=(options.readWithPOST!==undefined)?options.readWithPOST:this.readWithPOST;var resp=new OpenLayers.Protocol.Response({requestType:"read"});if(readWithPOST){resp.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleRead,resp,options),data:OpenLayers.Util.getParameterString(options.params),headers:{"Content-Type":"application/x-www-form-urlencoded"}});}else{resp.priv=OpenLayers.Request.GET({url:options.url,callback:this.createCallback(this.handleRead,resp,options),params:options.params,headers:options.headers});}
return resp;},handleRead:function(resp,options){this.handleResponse(resp,options);},filterToParams:function(filter,params){params=params||{};var className=filter.CLASS_NAME;var filterType=className.substring(className.lastIndexOf(".")+1);switch(filterType){case"Spatial":switch(filter.type){case OpenLayers.Filter.Spatial.BBOX:params.bbox=filter.value.toArray();break;case OpenLayers.Filter.Spatial.DWITHIN:params.tolerance=filter.distance;case OpenLayers.Filter.Spatial.WITHIN:params.lon=filter.value.x;params.lat=filter.value.y;break;default:OpenLayers.Console.warn("Unknown spatial filter type "+filter.type);}
break;case"Comparison":var op=OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR[filter.type];if(op!==undefined){var value=filter.value;if(filter.type==OpenLayers.Filter.Comparison.LIKE){value=this.regex2value(value);if(this.wildcarded){value="%"+value+"%";}}
params[filter.property+"__"+op]=value;params.queryable=params.queryable||[];params.queryable.push(filter.property);}else{OpenLayers.Console.warn("Unknown comparison filter type "+filter.type);}
break;case"Logical":if(filter.type===OpenLayers.Filter.Logical.AND){for(var i=0,len=filter.filters.length;i<len;i++){params=this.filterToParams(filter.filters[i],params);}}else{OpenLayers.Console.warn("Unsupported logical filter type "+filter.type);}
break;default:OpenLayers.Console.warn("Unknown filter type "+filterType);}
return params;},regex2value:function(value){value=value.replace(/%/g,"\\%");value=value.replace(/\\\\\.(\*)?/g,function($0,$1){return $1?$0:"\\\\_";});value=value.replace(/\\\\\.\*/g,"\\\\%");value=value.replace(/(\\)?\.(\*)?/g,function($0,$1,$2){return $1||$2?$0:"_";});value=value.replace(/(\\)?\.\*/g,function($0,$1){return $1?$0:"%";});value=value.replace(/\\\./g,".");value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"*";});return value;},create:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:features,requestType:"create"});resp.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleCreate,resp,options),headers:options.headers,data:this.format.write(features)});return resp;},handleCreate:function(resp,options){this.handleResponse(resp,options);},update:function(feature,options){options=options||{};var url=options.url||feature.url||this.options.url+"/"+feature.fid;options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:feature,requestType:"update"});resp.priv=OpenLayers.Request.PUT({url:url,callback:this.createCallback(this.handleUpdate,resp,options),headers:options.headers,data:this.format.write(feature)});return resp;},handleUpdate:function(resp,options){this.handleResponse(resp,options);},"delete":function(feature,options){options=options||{};var url=options.url||feature.url||this.options.url+"/"+feature.fid;options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:feature,requestType:"delete"});resp.priv=OpenLayers.Request.DELETE({url:url,callback:this.createCallback(this.handleDelete,resp,options),headers:options.headers});return resp;},handleDelete:function(resp,options){this.handleResponse(resp,options);},handleResponse:function(resp,options){var request=resp.priv;if(options.callback){if(request.status>=200&&request.status<300){if(resp.requestType!="delete"){resp.features=this.parseFeatures(request);}
resp.code=OpenLayers.Protocol.Response.SUCCESS;}else{resp.code=OpenLayers.Protocol.Response.FAILURE;}
options.callback.call(options.scope,resp);}},parseFeatures:function(request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
if(!doc||doc.length<=0){return null;}
return this.format.read(doc);},commit:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=[],nResponses=0;var types={};types[OpenLayers.State.INSERT]=[];types[OpenLayers.State.UPDATE]=[];types[OpenLayers.State.DELETE]=[];var feature,list,requestFeatures=[];for(var i=0,len=features.length;i<len;++i){feature=features[i];list=types[feature.state];if(list){list.push(feature);requestFeatures.push(feature);}}
var nRequests=(types[OpenLayers.State.INSERT].length>0?1:0)+
types[OpenLayers.State.UPDATE].length+
types[OpenLayers.State.DELETE].length;var success=true;var finalResponse=new OpenLayers.Protocol.Response({reqFeatures:requestFeatures});function insertCallback(response){var len=response.features?response.features.length:0;var fids=new Array(len);for(var i=0;i<len;++i){fids[i]=response.features[i].fid;}
finalResponse.insertIds=fids;callback.apply(this,[response]);}
function callback(response){this.callUserCallback(response,options);success=success&&response.success();nResponses++;if(nResponses>=nRequests){if(options.callback){finalResponse.code=success?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE;options.callback.apply(options.scope,[finalResponse]);}}}
var queue=types[OpenLayers.State.INSERT];if(queue.length>0){resp.push(this.create(queue,OpenLayers.Util.applyDefaults({callback:insertCallback,scope:this},options.create)));}
queue=types[OpenLayers.State.UPDATE];for(var i=queue.length-1;i>=0;--i){resp.push(this.update(queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options.update)));}
queue=types[OpenLayers.State.DELETE];for(var i=queue.length-1;i>=0;--i){resp.push(this["delete"](queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options["delete"])));}
return resp;},abort:function(response){if(response){response.priv.abort();}},callUserCallback:function(resp,options){var opt=options[resp.requestType];if(opt&&opt.callback){opt.callback.call(opt.scope,resp);}},CLASS_NAME:"OpenLayers.Protocol.HTTP"});(function(){var o=OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR={};o[OpenLayers.Filter.Comparison.EQUAL_TO]="eq";o[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]="ne";o[OpenLayers.Filter.Comparison.LESS_THAN]="lt";o[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]="lte";o[OpenLayers.Filter.Comparison.GREATER_THAN]="gt";o[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO]="gte";o[OpenLayers.Filter.Comparison.LIKE]="ilike";})();OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,initialize:function(options){OpenLayers.Strategy.prototype.initialize.apply(this,[options]);},activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"moveend":this.update,scope:this});this.layer.events.on({"refresh":this.update,scope:this});}
return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"moveend":this.update,scope:this});this.layer.events.un({"refresh":this.update,scope:this});}
return deactivated;},update:function(options){var mapBounds=this.getMapBounds();if((options&&options.force)||this.invalidBounds(mapBounds)){this.calculateBounds(mapBounds);this.resolution=this.layer.map.getResolution();this.triggerRead();}},getMapBounds:function(){var bounds=this.layer.map.getExtent();if(!this.layer.projection.equals(this.layer.map.getProjectionObject())){bounds=bounds.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection);}
return bounds;},invalidBounds:function(mapBounds){if(!mapBounds){mapBounds=this.getMapBounds();}
var invalid=!this.bounds||!this.bounds.containsBounds(mapBounds);if(!invalid&&this.resFactor){var ratio=this.resolution/this.layer.map.getResolution();invalid=(ratio>=this.resFactor||ratio<=(1/this.resFactor));}
return invalid;},calculateBounds:function(mapBounds){if(!mapBounds){mapBounds=this.getMapBounds();}
var center=mapBounds.getCenterLonLat();var dataWidth=mapBounds.getWidth()*this.ratio;var dataHeight=mapBounds.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(center.lon-(dataWidth/2),center.lat-(dataHeight/2),center.lon+(dataWidth/2),center.lat+(dataHeight/2));},triggerRead:function(){if(this.response){this.layer.protocol.abort(this.response);this.layer.events.triggerEvent("loadend");}
this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read({filter:this.createFilter(),callback:this.merge,scope:this});},createFilter:function(){var filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});if(this.layer.filter){filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.layer.filter,filter]});}
return filter;},merge:function(resp){this.layer.destroyFeatures();var features=resp.features;if(features&&features.length>0){var remote=this.layer.projection;var local=this.layer.map.getProjectionObject();if(!local.equals(remote)){var geom;for(var i=0,len=features.length;i<len;++i){geom=features[i].geometry;if(geom){geom.transform(remote,local);}}}
this.layer.addFeatures(features);}
this.response=null;this.layer.events.triggerEvent("loadend");},CLASS_NAME:"OpenLayers.Strategy.BBOX"});OpenLayers.Control.SelectFeature=OpenLayers.Class(OpenLayers.Control,{EVENT_TYPES:["beforefeaturehighlighted","featurehighlighted","featureunhighlighted"],multipleKey:null,toggleKey:null,multiple:false,clickout:true,toggle:false,hover:false,highlightOnly:false,box:false,onBeforeSelect:function(){},onSelect:function(){},onUnselect:function(){},scope:null,geometryTypes:null,layer:null,layers:null,callbacks:null,selectStyle:null,renderIntent:"select",handlers:null,initialize:function(layers,options){this.EVENT_TYPES=OpenLayers.Control.SelectFeature.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);if(this.scope===null){this.scope=this;}
this.initLayer(layers);var callbacks={click:this.clickFeature,clickout:this.clickoutFeature};if(this.hover){callbacks.over=this.overFeature;callbacks.out=this.outFeature;}
this.callbacks=OpenLayers.Util.extend(callbacks,this.callbacks);this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};if(this.box){this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"});}},initLayer:function(layers){if(layers instanceof Array){this.layers=layers;this.layer=new OpenLayers.Layer.Vector.RootContainer(this.id+"_container",{layers:layers});}else{this.layer=layers;}},destroy:function(){if(this.active&&this.layers){this.map.removeLayer(this.layer);}
OpenLayers.Control.prototype.destroy.apply(this,arguments);if(this.layers){this.layer.destroy();}},activate:function(){if(!this.active){if(this.layers){this.map.addLayer(this.layer);}
this.handlers.feature.activate();if(this.box&&this.handlers.box){this.handlers.box.activate();}}
return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){if(this.active){this.handlers.feature.deactivate();if(this.handlers.box){this.handlers.box.deactivate();}
if(this.layers){this.map.removeLayer(this.layer);}}
return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},unselectAll:function(options){var layers=this.layers||[this.layer];var layer,feature;for(var l=0;l<layers.length;++l){layer=layers[l];for(var i=layer.selectedFeatures.length-1;i>=0;--i){feature=layer.selectedFeatures[i];if(!options||options.except!=feature){this.unselect(feature);}}}},clickFeature:function(feature){if(!this.hover){var selected=(OpenLayers.Util.indexOf(feature.layer.selectedFeatures,feature)>-1);if(selected){if(this.toggleSelect()){this.unselect(feature);}else if(!this.multipleSelect()){this.unselectAll({except:feature});}}else{if(!this.multipleSelect()){this.unselectAll({except:feature});}
this.select(feature);}}},multipleSelect:function(){return this.multiple||(this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]);},toggleSelect:function(){return this.toggle||(this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]);},clickoutFeature:function(feature){if(!this.hover&&this.clickout){this.unselectAll();}},overFeature:function(feature){var layer=feature.layer;if(this.hover){if(this.highlightOnly){this.highlight(feature);}else if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}},outFeature:function(feature){if(this.hover){if(this.highlightOnly){if(feature._lastHighlighter==this.id){if(feature._prevHighlighter&&feature._prevHighlighter!=this.id){delete feature._lastHighlighter;var control=this.map.getControl(feature._prevHighlighter);if(control){control.highlight(feature);}}else{this.unhighlight(feature);}}}else{this.unselect(feature);}}},highlight:function(feature){var layer=feature.layer;var cont=this.events.triggerEvent("beforefeaturehighlighted",{feature:feature});if(cont!==false){feature._prevHighlighter=feature._lastHighlighter;feature._lastHighlighter=this.id;var style=this.selectStyle||this.renderIntent;layer.drawFeature(feature,style);this.events.triggerEvent("featurehighlighted",{feature:feature});}},unhighlight:function(feature){var layer=feature.layer;feature._lastHighlighter=feature._prevHighlighter;delete feature._prevHighlighter;layer.drawFeature(feature,feature.style||feature.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:feature});},select:function(feature){var cont=this.onBeforeSelect.call(this.scope,feature);var layer=feature.layer;if(cont!==false){cont=layer.events.triggerEvent("beforefeatureselected",{feature:feature});if(cont!==false){layer.selectedFeatures.push(feature);this.highlight(feature);if(!this.handlers.feature.lastFeature){this.handlers.feature.lastFeature=layer.selectedFeatures[0];}
layer.events.triggerEvent("featureselected",{feature:feature});this.onSelect.call(this.scope,feature);}}},unselect:function(feature){var layer=feature.layer;this.unhighlight(feature);OpenLayers.Util.removeItem(layer.selectedFeatures,feature);layer.events.triggerEvent("featureunselected",{feature:feature});this.onUnselect.call(this.scope,feature);},selectBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);if(!this.multipleSelect()){this.unselectAll();}
var prevMultiple=this.multiple;this.multiple=true;var layers=this.layers||[this.layer];var layer;for(var l=0;l<layers.length;++l){layer=layers[l];for(var i=0,len=layer.features.length;i<len;++i){var feature=layer.features[i];if(!feature.getVisibility()){continue;}
if(this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1){if(bounds.toGeometry().intersects(feature.geometry)){if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}}}}
this.multiple=prevMultiple;}},setMap:function(map){this.handlers.feature.setMap(map);if(this.box){this.handlers.box.setMap(map);}
OpenLayers.Control.prototype.setMap.apply(this,arguments);},setLayer:function(layers){var isActive=this.active;this.unselectAll();this.deactivate();if(this.layers){this.layer.destroy();this.layers=null;}
this.initLayer(layers);this.handlers.feature.layer=this.layer;if(isActive){this.activate();}},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){var obj={};this.readers.ogc["Filter"].apply(this,[data,obj]);return obj.filter;},readers:{"ogc":{"Filter":function(node,parent){var obj={fids:[],filters:[]};this.readChildNodes(node,obj);if(obj.fids.length>0){parent.filter=new OpenLayers.Filter.FeatureId({fids:obj.fids});}else if(obj.filters.length>0){parent.filter=obj.filters[0];}},"FeatureId":function(node,obj){var fid=node.getAttribute("fid");if(fid){obj.fids.push(fid);}},"And":function(node,obj){var filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND});this.readChildNodes(node,filter);obj.filters.push(filter);},"Or":function(node,obj){var filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(node,filter);obj.filters.push(filter);},"Not":function(node,obj){var filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLessThan":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsGreaterThan":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLessThanOrEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsGreaterThanOrEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsBetween":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(node,filter);obj.filters.push(filter);},"Literal":function(node,obj){obj.value=OpenLayers.String.numericIf(this.getChildValue(node));},"PropertyName":function(node,filter){filter.property=this.getChildValue(node);},"LowerBoundary":function(node,filter){filter.lowerBoundary=OpenLayers.String.numericIf(this.readOgcExpression(node));},"UpperBoundary":function(node,filter){filter.upperBoundary=OpenLayers.String.numericIf(this.readOgcExpression(node));},"Intersects":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.INTERSECTS);},"Within":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.WITHIN);},"Contains":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.CONTAINS);},"DWithin":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.DWITHIN);},"Distance":function(node,obj){obj.distance=parseInt(this.getChildValue(node));obj.distanceUnits=node.getAttribute("units");}}},readSpatial:function(node,obj,type){var filter=new OpenLayers.Filter.Spatial({type:type});this.readChildNodes(node,filter);filter.value=filter.components[0];delete filter.components;obj.filters.push(filter);},readOgcExpression:function(node){var obj={};this.readChildNodes(node,obj);var value=obj.value;if(value===undefined){value=this.getChildValue(node);}
return value;},write:function(filter){return this.writers.ogc["Filter"].apply(this,[filter]);},writers:{"ogc":{"Filter":function(filter){var node=this.createElementNSPlus("ogc:Filter");var sub=filter.CLASS_NAME.split(".").pop();if(sub=="FeatureId"){for(var i=0;i<filter.fids.length;++i){this.writeNode("FeatureId",filter.fids[i],node);}}else{this.writeNode(this.getFilterType(filter),filter,node);}
return node;},"FeatureId":function(fid){return this.createElementNSPlus("ogc:FeatureId",{attributes:{fid:fid}});},"And":function(filter){var node=this.createElementNSPlus("ogc:And");var childFilter;for(var i=0;i<filter.filters.length;++i){childFilter=filter.filters[i];this.writeNode(this.getFilterType(childFilter),childFilter,node);}
return node;},"Or":function(filter){var node=this.createElementNSPlus("ogc:Or");var childFilter;for(var i=0;i<filter.filters.length;++i){childFilter=filter.filters[i];this.writeNode(this.getFilterType(childFilter),childFilter,node);}
return node;},"Not":function(filter){var node=this.createElementNSPlus("ogc:Not");var childFilter=filter.filters[0];this.writeNode(this.getFilterType(childFilter),childFilter,node);return node;},"PropertyIsLessThan":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLessThan");this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsGreaterThan":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsGreaterThan");this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsLessThanOrEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsGreaterThanOrEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsBetween":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsBetween");this.writeNode("PropertyName",filter,node);this.writeNode("LowerBoundary",filter,node);this.writeNode("UpperBoundary",filter,node);return node;},"PropertyName":function(filter){return this.createElementNSPlus("ogc:PropertyName",{value:filter.property});},"Literal":function(value){return this.createElementNSPlus("ogc:Literal",{value:value});},"LowerBoundary":function(filter){var node=this.createElementNSPlus("ogc:LowerBoundary");this.writeNode("Literal",filter.lowerBoundary,node);return node;},"UpperBoundary":function(filter){var node=this.createElementNSPlus("ogc:UpperBoundary");this.writeNode("Literal",filter.upperBoundary,node);return node;},"INTERSECTS":function(filter){return this.writeSpatial(filter,"Intersects");},"WITHIN":function(filter){return this.writeSpatial(filter,"Within");},"CONTAINS":function(filter){return this.writeSpatial(filter,"Contains");},"DWITHIN":function(filter){var node=this.writeSpatial(filter,"DWithin");this.writeNode("Distance",filter,node);return node;},"Distance":function(filter){return this.createElementNSPlus("ogc:Distance",{attributes:{units:filter.distanceUnits},value:filter.distance});}}},getFilterType:function(filter){var filterType=this.filterMap[filter.type];if(!filterType){throw"Filter writing not supported for rule type: "+filter.type;}
return filterType;},filterMap:{"&&":"And","||":"Or","!":"Not","==":"PropertyIsEqualTo","!=":"PropertyIsNotEqualTo","<":"PropertyIsLessThan",">":"PropertyIsGreaterThan","<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike","BBOX":"BBOX","DWITHIN":"DWITHIN","WITHIN":"WITHIN","CONTAINS":"CONTAINS","INTERSECTS":"INTERSECTS"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],initialize:function(points){OpenLayers.Geometry.MultiPoint.prototype.initialize.apply(this,arguments);},getLength:function(){var length=0.0;if(this.components&&(this.components.length>1)){for(var i=1,len=this.components.length;i<len;i++){length+=this.components[i-1].distanceTo(this.components[i]);}}
return length;},getGeodesicLength:function(projection){var geom=this;if(projection){var gg=new OpenLayers.Projection("EPSG:4326");if(!gg.equals(projection)){geom=this.clone().transform(projection,gg);}}
var length=0.0;if(geom.components&&(geom.components.length>1)){var p1,p2;for(var i=1,len=geom.components.length;i<len;i++){p1=geom.components[i-1];p2=geom.components[i];length+=OpenLayers.Util.distVincenty({lon:p1.x,lat:p1.y},{lon:p2.x,lat:p2.y});}}
return length*1000;},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Layer.Text=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,initialize:function(name,options){OpenLayers.Layer.Markers.prototype.initialize.apply(this,arguments);this.features=new Array();},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null;},loadText:function(){if(!this.loaded){if(this.location!=null){var onFail=function(e){this.events.triggerEvent("loadend");};this.events.triggerEvent("loadstart");OpenLayers.Request.GET({url:this.location,success:this.parseData,failure:onFail,scope:this});this.loaded=true;}}},moveTo:function(bounds,zoomChanged,minor){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);if(this.visibility&&!this.loaded){this.loadText();}},parseData:function(ajaxRequest){var text=ajaxRequest.responseText;var options={};OpenLayers.Util.extend(options,this.formatOptions);if(this.map&&!this.projection.equals(this.map.getProjectionObject())){options.externalProjection=this.projection;options.internalProjection=this.map.getProjectionObject();}
var parser=new OpenLayers.Format.Text(options);var features=parser.read(text);for(var i=0,len=features.length;i<len;i++){var data={};var feature=features[i];var location;var iconSize,iconOffset;location=new OpenLayers.LonLat(feature.geometry.x,feature.geometry.y);if(feature.style.graphicWidth&&feature.style.graphicHeight){iconSize=new OpenLayers.Size(feature.style.graphicWidth,feature.style.graphicHeight);}
if(feature.style.graphicXOffset!==undefined&&feature.style.graphicYOffset!==undefined){iconOffset=new OpenLayers.Pixel(feature.style.graphicXOffset,feature.style.graphicYOffset);}
if(feature.style.externalGraphic!=null){data.icon=new OpenLayers.Icon(feature.style.externalGraphic,iconSize,iconOffset);}else{data.icon=OpenLayers.Marker.defaultIcon();if(iconSize!=null){data.icon.setSize(iconSize);}}
if((feature.attributes.title!=null)&&(feature.attributes.description!=null)){data['popupContentHTML']='<h2>'+feature.attributes.title+'</h2>'+'<p>'+feature.attributes.description+'</p>';}
data['overflow']=feature.attributes.overflow||"auto";var markerFeature=new OpenLayers.Feature(this,location,data);this.features.push(markerFeature);var marker=markerFeature.createMarker();if((feature.attributes.title!=null)&&(feature.attributes.description!=null)){marker.events.register('click',markerFeature,this.markerClick);}
this.addMarker(marker);}
this.events.triggerEvent("loadend");},markerClick:function(evt){var sameMarkerClicked=(this==this.layer.selectedFeature);this.layer.selectedFeature=(!sameMarkerClicked)?this:null;for(var i=0,len=this.layer.map.popups.length;i<len;i++){this.layer.map.removePopup(this.layer.map.popups[i]);}
if(!sameMarkerClicked){this.layer.map.addPopup(this.createPopup());}
OpenLayers.Event.stop(evt);},clearFeatures:function(){if(this.features!=null){while(this.features.length>0){var feature=this.features[0];OpenLayers.Util.removeItem(this.features,feature);feature.destroy();}}},CLASS_NAME:"OpenLayers.Layer.Text"});OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,clickout:true,toggle:true,standalone:false,layer:null,feature:null,vertices:null,virtualVertices:null,selectControl:null,dragControl:null,handlers:null,deleteCodes:null,virtualStyle:null,mode:null,modified:false,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(layer,options){this.layer=layer;this.vertices=[];this.virtualVertices=[];this.virtualStyle=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer());this.virtualStyle.fillOpacity=0.3;this.virtualStyle.strokeOpacity=0.3;this.deleteCodes=[46,68];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[options]);if(!(this.deleteCodes instanceof Array)){this.deleteCodes=[this.deleteCodes];}
var control=this;var selectOptions={geometryTypes:this.geometryTypes,clickout:this.clickout,toggle:this.toggle,onBeforeSelect:this.beforeSelectFeature,onSelect:this.selectFeature,onUnselect:this.unselectFeature,scope:this};if(this.standalone===false){this.selectControl=new OpenLayers.Control.SelectFeature(layer,selectOptions);}
var dragOptions={geometryTypes:["OpenLayers.Geometry.Point"],snappingOptions:this.snappingOptions,onStart:function(feature,pixel){control.dragStart.apply(control,[feature,pixel]);},onDrag:function(feature,pixel){control.dragVertex.apply(control,[feature,pixel]);},onComplete:function(feature){control.dragComplete.apply(control,[feature]);},featureCallbacks:{over:function(feature){if(control.standalone!==true||feature._sketch||control.feature===feature){control.dragControl.overFeature.apply(control.dragControl,[feature]);}}}};this.dragControl=new OpenLayers.Control.DragFeature(layer,dragOptions);var keyboardOptions={keydown:this.handleKeypress};this.handlers={keyboard:new OpenLayers.Handler.Keyboard(this,keyboardOptions)};},destroy:function(){this.layer=null;this.standalone||this.selectControl.destroy();this.dragControl.destroy();OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){return((this.standalone||this.selectControl.activate())&&this.handlers.keyboard.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){var deactivated=false;if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.layer.removeFeatures(this.vertices,{silent:true});this.layer.removeFeatures(this.virtualVertices,{silent:true});this.vertices=[];this.dragControl.deactivate();var feature=this.feature;var valid=feature&&feature.geometry&&feature.layer;if(this.standalone===false){if(valid){this.selectControl.unselect.apply(this.selectControl,[feature]);}
this.selectControl.deactivate();}else{if(valid){this.unselectFeature(feature);}}
this.handlers.keyboard.deactivate();deactivated=true;}
return deactivated;},beforeSelectFeature:function(feature){return this.layer.events.triggerEvent("beforefeaturemodified",{feature:feature});},selectFeature:function(feature){this.feature=feature;this.modified=false;this.resetVertices();this.dragControl.activate();this.onModificationStart(this.feature);},unselectFeature:function(feature){this.layer.removeFeatures(this.vertices,{silent:true});this.vertices=[];this.layer.destroyFeatures(this.virtualVertices,{silent:true});this.virtualVertices=[];if(this.dragHandle){this.layer.destroyFeatures([this.dragHandle],{silent:true});delete this.dragHandle;}
if(this.radiusHandle){this.layer.destroyFeatures([this.radiusHandle],{silent:true});delete this.radiusHandle;}
this.feature=null;this.dragControl.deactivate();this.onModificationEnd(feature);this.layer.events.triggerEvent("afterfeaturemodified",{feature:feature,modified:this.modified});this.modified=false;},dragStart:function(feature,pixel){if(feature!=this.feature&&!feature.geometry.parent&&feature!=this.dragHandle&&feature!=this.radiusHandle){if(this.standalone===false&&this.feature){this.selectControl.clickFeature.apply(this.selectControl,[this.feature]);}
if(this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)!=-1){this.standalone||this.selectControl.clickFeature.apply(this.selectControl,[feature]);this.dragControl.overFeature.apply(this.dragControl,[feature]);this.dragControl.lastPixel=pixel;this.dragControl.handlers.drag.started=true;this.dragControl.handlers.drag.start=pixel;this.dragControl.handlers.drag.last=pixel;}}},dragVertex:function(vertex,pixel){this.modified=true;if(this.feature.geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){if(this.feature!=vertex){this.feature=vertex;}
this.layer.events.triggerEvent("vertexmodified",{vertex:vertex.geometry,feature:this.feature,pixel:pixel});}else{if(vertex._index){vertex.geometry.parent.addComponent(vertex.geometry,vertex._index);delete vertex._index;OpenLayers.Util.removeItem(this.virtualVertices,vertex);this.vertices.push(vertex);}else if(vertex==this.dragHandle){this.layer.removeFeatures(this.vertices,{silent:true});this.vertices=[];if(this.radiusHandle){this.layer.destroyFeatures([this.radiusHandle],{silent:true});this.radiusHandle=null;}}else if(vertex!==this.radiusHandle){this.layer.events.triggerEvent("vertexmodified",{vertex:vertex.geometry,feature:this.feature,pixel:pixel});}
if(this.virtualVertices.length>0){this.layer.destroyFeatures(this.virtualVertices,{silent:true});this.virtualVertices=[];}
this.layer.drawFeature(this.feature,this.standalone?undefined:this.selectControl.renderIntent);}
this.layer.drawFeature(vertex);},dragComplete:function(vertex){this.resetVertices();this.setFeatureState();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature});},setFeatureState:function(){if(this.feature.state!=OpenLayers.State.INSERT&&this.feature.state!=OpenLayers.State.DELETE){this.feature.state=OpenLayers.State.UPDATE;}},resetVertices:function(){if(this.dragControl.feature){this.dragControl.outFeature(this.dragControl.feature);}
if(this.vertices.length>0){this.layer.removeFeatures(this.vertices,{silent:true});this.vertices=[];}
if(this.virtualVertices.length>0){this.layer.removeFeatures(this.virtualVertices,{silent:true});this.virtualVertices=[];}
if(this.dragHandle){this.layer.destroyFeatures([this.dragHandle],{silent:true});this.dragHandle=null;}
if(this.radiusHandle){this.layer.destroyFeatures([this.radiusHandle],{silent:true});this.radiusHandle=null;}
if(this.feature&&this.feature.geometry.CLASS_NAME!="OpenLayers.Geometry.Point"){if((this.mode&OpenLayers.Control.ModifyFeature.DRAG)){this.collectDragHandle();}
if((this.mode&(OpenLayers.Control.ModifyFeature.ROTATE|OpenLayers.Control.ModifyFeature.RESIZE))){this.collectRadiusHandle();}
if(this.mode&OpenLayers.Control.ModifyFeature.RESHAPE){if(!(this.mode&OpenLayers.Control.ModifyFeature.RESIZE)){this.collectVertices();}}}},handleKeypress:function(evt){var code=evt.keyCode;if(this.feature&&OpenLayers.Util.indexOf(this.deleteCodes,code)!=-1){var vertex=this.dragControl.feature;if(vertex&&OpenLayers.Util.indexOf(this.vertices,vertex)!=-1&&!this.dragControl.handlers.drag.dragging&&vertex.geometry.parent){vertex.geometry.parent.removeComponent(vertex.geometry);this.layer.drawFeature(this.feature,this.standalone?undefined:this.selectControl.renderIntent);this.resetVertices();this.setFeatureState();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature});}}},collectVertices:function(){this.vertices=[];this.virtualVertices=[];var control=this;function collectComponentVertices(geometry){var i,vertex,component,len;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){vertex=new OpenLayers.Feature.Vector(geometry);vertex._sketch=true;control.vertices.push(vertex);}else{var numVert=geometry.components.length;if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){numVert-=1;}
for(i=0;i<numVert;++i){component=geometry.components[i];if(component.CLASS_NAME=="OpenLayers.Geometry.Point"){vertex=new OpenLayers.Feature.Vector(component);vertex._sketch=true;control.vertices.push(vertex);}else{collectComponentVertices(component);}}
if(geometry.CLASS_NAME!="OpenLayers.Geometry.MultiPoint"){for(i=0,len=geometry.components.length;i<len-1;++i){var prevVertex=geometry.components[i];var nextVertex=geometry.components[i+1];if(prevVertex.CLASS_NAME=="OpenLayers.Geometry.Point"&&nextVertex.CLASS_NAME=="OpenLayers.Geometry.Point"){var x=(prevVertex.x+nextVertex.x)/2;var y=(prevVertex.y+nextVertex.y)/2;var point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(x,y),null,control.virtualStyle);point.geometry.parent=geometry;point._index=i+1;point._sketch=true;control.virtualVertices.push(point);}}}}}
collectComponentVertices.call(this,this.feature.geometry);this.layer.addFeatures(this.virtualVertices,{silent:true});this.layer.addFeatures(this.vertices,{silent:true});},collectDragHandle:function(){var geometry=this.feature.geometry;var center=geometry.getBounds().getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var origin=new OpenLayers.Feature.Vector(originGeometry);originGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);geometry.move(x,y);};origin._sketch=true;this.dragHandle=origin;this.layer.addFeatures([this.dragHandle],{silent:true});},collectRadiusHandle:function(){var geometry=this.feature.geometry;var bounds=geometry.getBounds();var center=bounds.getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var radiusGeometry=new OpenLayers.Geometry.Point(bounds.right,bounds.bottom);var radius=new OpenLayers.Feature.Vector(radiusGeometry);var resize=(this.mode&OpenLayers.Control.ModifyFeature.RESIZE);var reshape=(this.mode&OpenLayers.Control.ModifyFeature.RESHAPE);var rotate=(this.mode&OpenLayers.Control.ModifyFeature.ROTATE);radiusGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);var dx1=this.x-originGeometry.x;var dy1=this.y-originGeometry.y;var dx0=dx1-x;var dy0=dy1-y;if(rotate){var a0=Math.atan2(dy0,dx0);var a1=Math.atan2(dy1,dx1);var angle=a1-a0;angle*=180/Math.PI;geometry.rotate(angle,originGeometry);}
if(resize){var scale,ratio;if(reshape){scale=dy1/dy0;ratio=(dx1/dx0)/scale;}else{var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));scale=l1/l0;}
geometry.resize(scale,originGeometry,ratio);}};radius._sketch=true;this.radiusHandle=radius;this.layer.addFeatures([this.radiusHandle],{silent:true});},setMap:function(map){this.standalone||this.selectControl.setMap(map);this.dragControl.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{initialize:function(points){OpenLayers.Geometry.Curve.prototype.initialize.apply(this,arguments);},removeComponent:function(point){if(this.components&&(this.components.length>2)){OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);}},intersects:function(geometry){var intersect=false;var type=geometry.CLASS_NAME;if(type=="OpenLayers.Geometry.LineString"||type=="OpenLayers.Geometry.LinearRing"||type=="OpenLayers.Geometry.Point"){var segs1=this.getSortedSegments();var segs2;if(type=="OpenLayers.Geometry.Point"){segs2=[{x1:geometry.x,y1:geometry.y,x2:geometry.x,y2:geometry.y}];}else{segs2=geometry.getSortedSegments();}
var seg1,seg1x1,seg1x2,seg1y1,seg1y2,seg2,seg2y1,seg2y2;outer:for(var i=0,len=segs1.length;i<len;++i){seg1=segs1[i];seg1x1=seg1.x1;seg1x2=seg1.x2;seg1y1=seg1.y1;seg1y2=seg1.y2;inner:for(var j=0,jlen=segs2.length;j<jlen;++j){seg2=segs2[j];if(seg2.x1>seg1x2){break;}
if(seg2.x2<seg1x1){continue;}
seg2y1=seg2.y1;seg2y2=seg2.y2;if(Math.min(seg2y1,seg2y2)>Math.max(seg1y1,seg1y2)){continue;}
if(Math.max(seg2y1,seg2y2)<Math.min(seg1y1,seg1y2)){continue;}
if(OpenLayers.Geometry.segmentsIntersect(seg1,seg2)){intersect=true;break outer;}}}}else{intersect=geometry.intersects(this);}
return intersect;},getSortedSegments:function(){var numSeg=this.components.length-1;var segments=new Array(numSeg),point1,point2;for(var i=0;i<numSeg;++i){point1=this.components[i];point2=this.components[i+1];if(point1.x<point2.x){segments[i]={x1:point1.x,y1:point1.y,x2:point2.x,y2:point2.y};}else{segments[i]={x1:point2.x,y1:point2.y,x2:point1.x,y2:point1.y};}}
function byX1(seg1,seg2){return seg1.x1-seg2.x1;}
return segments.sort(byX1);},splitWithSegment:function(seg,options){var edge=!(options&&options.edge===false);var tolerance=options&&options.tolerance;var lines=[];var verts=this.getVertices();var points=[];var intersections=[];var split=false;var vert1,vert2,point;var node,vertex,target;var interOptions={point:true,tolerance:tolerance};var result=null;for(var i=0,stop=verts.length-2;i<=stop;++i){vert1=verts[i];points.push(vert1.clone());vert2=verts[i+1];target={x1:vert1.x,y1:vert1.y,x2:vert2.x,y2:vert2.y};point=OpenLayers.Geometry.segmentsIntersect(seg,target,interOptions);if(point instanceof OpenLayers.Geometry.Point){if((point.x===seg.x1&&point.y===seg.y1)||(point.x===seg.x2&&point.y===seg.y2)||point.equals(vert1)||point.equals(vert2)){vertex=true;}else{vertex=false;}
if(vertex||edge){if(!point.equals(intersections[intersections.length-1])){intersections.push(point.clone());}
if(i===0){if(point.equals(vert1)){continue;}}
if(point.equals(vert2)){continue;}
split=true;if(!point.equals(vert1)){points.push(point);}
lines.push(new OpenLayers.Geometry.LineString(points));points=[point.clone()];}}}
if(split){points.push(vert2.clone());lines.push(new OpenLayers.Geometry.LineString(points));}
if(intersections.length>0){var xDir=seg.x1<seg.x2?1:-1;var yDir=seg.y1<seg.y2?1:-1;result={lines:lines,points:intersections.sort(function(p1,p2){return(xDir*p1.x-xDir*p2.x)||(yDir*p1.y-yDir*p2.y);})};}
return result;},split:function(target,options){var results=null;var mutual=options&&options.mutual;var sourceSplit,targetSplit,sourceParts,targetParts;if(target instanceof OpenLayers.Geometry.LineString){var verts=this.getVertices();var vert1,vert2,seg,splits,lines,point;var points=[];sourceParts=[];for(var i=0,stop=verts.length-2;i<=stop;++i){vert1=verts[i];vert2=verts[i+1];seg={x1:vert1.x,y1:vert1.y,x2:vert2.x,y2:vert2.y};targetParts=targetParts||[target];if(mutual){points.push(vert1.clone());}
for(var j=0;j<targetParts.length;++j){splits=targetParts[j].splitWithSegment(seg,options);if(splits){lines=splits.lines;if(lines.length>0){lines.unshift(j,1);Array.prototype.splice.apply(targetParts,lines);j+=lines.length-2;}
if(mutual){for(var k=0,len=splits.points.length;k<len;++k){point=splits.points[k];if(!point.equals(vert1)){points.push(point);sourceParts.push(new OpenLayers.Geometry.LineString(points));if(point.equals(vert2)){points=[];}else{points=[point.clone()];}}}}}}}
if(mutual&&sourceParts.length>0&&points.length>0){points.push(vert2.clone());sourceParts.push(new OpenLayers.Geometry.LineString(points));}}else{results=target.splitWith(this,options);}
if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
if(targetSplit||sourceSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
return results;},splitWith:function(geometry,options){return geometry.split(this,options);},getVertices:function(nodes){var vertices;if(nodes===true){vertices=[this.components[0],this.components[this.components.length-1]];}else if(nodes===false){vertices=this.components.slice(1,this.components.length-1);}else{vertices=this.components.slice();}
return vertices;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best={};var min=Number.POSITIVE_INFINITY;if(geometry instanceof OpenLayers.Geometry.Point){var segs=this.getSortedSegments();var x=geometry.x;var y=geometry.y;var seg;for(var i=0,len=segs.length;i<len;++i){seg=segs[i];result=OpenLayers.Geometry.distanceToSegment(geometry,seg);if(result.distance<min){min=result.distance;best=result;if(min===0){break;}}else{if(seg.x2>x&&((y>seg.y1&&y<seg.y2)||(y<seg.y1&&y>seg.y2))){break;}}}
if(details){best={distance:best.distance,x0:best.x,y0:best.y,x1:x,y1:y};}else{best=best.distance;}}else if(geometry instanceof OpenLayers.Geometry.LineString){var segs0=this.getSortedSegments();var segs1=geometry.getSortedSegments();var seg0,seg1,intersection,x0,y0;var len1=segs1.length;var interOptions={point:true};outer:for(var i=0,len=segs0.length;i<len;++i){seg0=segs0[i];x0=seg0.x1;y0=seg0.y1;for(var j=0;j<len1;++j){seg1=segs1[j];intersection=OpenLayers.Geometry.segmentsIntersect(seg0,seg1,interOptions);if(intersection){min=0;best={distance:0,x0:intersection.x,y0:intersection.y,x1:intersection.x,y1:intersection.y};break outer;}else{result=OpenLayers.Geometry.distanceToSegment({x:x0,y:y0},seg1);if(result.distance<min){min=result.distance;best={distance:min,x0:x0,y0:y0,x1:result.x,y1:result.y};}}}}
if(!details){best=best.distance;}
if(min!==0){if(seg0){result=geometry.distanceTo(new OpenLayers.Geometry.Point(seg0.x2,seg0.y2),options);var dist=details?result.distance:result;if(dist<min){if(details){best={distance:min,x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0};}else{best=dist;}}}}}else{best=geometry.distanceTo(this,options);if(details){best={distance:best.distance,x0:best.x1,y0:best.y1,x1:best.x0,y1:best.y0};}}
return best;},CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Control.TransformFeature=OpenLayers.Class(OpenLayers.Control,{EVENT_TYPES:["beforesetfeature","setfeature","beforetransform","transform","transformcomplete"],geometryTypes:null,layer:null,preserveAspectRatio:false,rotate:true,feature:null,renderIntent:"temporary",rotationHandleSymbolizer:null,box:null,center:null,scale:1,ratio:1,rotation:0,handles:null,rotationHandles:null,dragControl:null,initialize:function(layer,options){this.EVENT_TYPES=OpenLayers.Control.TransformFeature.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);this.layer=layer;if(!this.rotationHandleSymbolizer){this.rotationHandleSymbolizer={stroke:false,pointRadius:10,fillOpacity:0,cursor:"pointer"};}
this.createBox();this.createControl();},activate:function(){var activated=false;if(OpenLayers.Control.prototype.activate.apply(this,arguments)){this.dragControl.activate();this.layer.addFeatures([this.box]);this.rotate&&this.layer.addFeatures(this.rotationHandles);this.layer.addFeatures(this.handles);activated=true;}
return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.layer.removeFeatures(this.handles);this.rotate&&this.layer.removeFeatures(this.rotationHandles);this.layer.removeFeatures([this.box]);this.dragControl.deactivate();deactivated=true;}
return deactivated;},setMap:function(map){this.dragControl.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},setFeature:function(feature,initialParams){initialParams=OpenLayers.Util.applyDefaults(initialParams,{rotation:0,scale:1,ratio:1});var evt={feature:feature};var oldRotation=this.rotation;var oldCenter=this.center;OpenLayers.Util.extend(this,initialParams);if(this.events.triggerEvent("beforesetfeature",evt)===false){return;}
this.feature=feature;this.activate();this._setfeature=true;var featureBounds=this.feature.geometry.getBounds();this.box.move(featureBounds.getCenterLonLat());this.box.geometry.rotate(-oldRotation,oldCenter);this._angle=0;var ll;if(this.rotation){var geom=feature.geometry.clone();geom.rotate(-this.rotation,this.center);var box=new OpenLayers.Feature.Vector(geom.getBounds().toGeometry());box.geometry.rotate(this.rotation,this.center);this.box.geometry.rotate(this.rotation,this.center);this.box.move(box.geometry.getBounds().getCenterLonLat());var llGeom=box.geometry.components[0].components[0];ll=llGeom.getBounds().getCenterLonLat();}else{ll=new OpenLayers.LonLat(featureBounds.left,featureBounds.bottom);}
this.handles[0].move(ll);delete this._setfeature;this.events.triggerEvent("setfeature",evt);},createBox:function(){var control=this;this.center=new OpenLayers.Geometry.Point(0,0);var box=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(-1,-1),new OpenLayers.Geometry.Point(0,-1),new OpenLayers.Geometry.Point(1,-1),new OpenLayers.Geometry.Point(1,0),new OpenLayers.Geometry.Point(1,1),new OpenLayers.Geometry.Point(0,1),new OpenLayers.Geometry.Point(-1,1),new OpenLayers.Geometry.Point(-1,0),new OpenLayers.Geometry.Point(-1,-1)]),null,typeof this.renderIntent=="string"?null:this.renderIntent);box.geometry.move=function(x,y){control._moving=true;OpenLayers.Geometry.LineString.prototype.move.apply(this,arguments);control.center.move(x,y);delete control._moving;};var vertexMoveFn=function(x,y){OpenLayers.Geometry.Point.prototype.move.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.move(x,y);this._handle.geometry.move(x,y);};var vertexResizeFn=function(scale,center,ratio){OpenLayers.Geometry.Point.prototype.resize.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.resize(scale,center,ratio);this._handle.geometry.resize(scale,center,ratio);};var vertexRotateFn=function(angle,center){OpenLayers.Geometry.Point.prototype.rotate.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.rotate(angle,center);this._handle.geometry.rotate(angle,center);};var handleMoveFn=function(x,y){var oldX=this.x,oldY=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,x,y);if(control._moving){return;}
var evt=control.dragControl.handlers.drag.evt;var preserveAspectRatio=!control._setfeature&&control.preserveAspectRatio;var reshape=!preserveAspectRatio&&!(evt&&evt.shiftKey);var oldGeom=new OpenLayers.Geometry.Point(oldX,oldY);var centerGeometry=control.center;this.rotate(-control.rotation,centerGeometry);oldGeom.rotate(-control.rotation,centerGeometry);var dx1=this.x-centerGeometry.x;var dy1=this.y-centerGeometry.y;var dx0=dx1-(this.x-oldGeom.x);var dy0=dy1-(this.y-oldGeom.y);this.x=oldX;this.y=oldY;var scale,ratio=1;if(reshape){scale=Math.abs(dy0)<0.00001?1:dy1/dy0;ratio=(Math.abs(dx0)<0.00001?1:(dx1/dx0))/scale;}else{var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));scale=l1/l0;}
control._moving=true;control.box.geometry.rotate(-control.rotation,centerGeometry);delete control._moving;control.box.geometry.resize(scale,centerGeometry,ratio);control.box.geometry.rotate(control.rotation,centerGeometry);control.transformFeature({scale:scale,ratio:ratio});};var rotationHandleMoveFn=function(x,y){var oldX=this.x,oldY=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,x,y);if(control._moving){return;}
var evt=control.dragControl.handlers.drag.evt;var constrain=(evt&&evt.shiftKey)?45:1;var centerGeometry=control.center;var dx1=this.x-centerGeometry.x;var dy1=this.y-centerGeometry.y;var dx0=dx1-x;var dy0=dy1-y;this.x=oldX;this.y=oldY;var a0=Math.atan2(dy0,dx0);var a1=Math.atan2(dy1,dx1);var angle=a1-a0;angle*=180/Math.PI;control._angle=(control._angle+angle)%360;var diff=control.rotation%constrain;if(Math.abs(control._angle)>=constrain||diff!==0){angle=Math.round(control._angle/constrain)*constrain-
diff;control._angle=0;control.box.geometry.rotate(angle,centerGeometry);control.transformFeature({rotation:angle});}};var handles=new Array(8);var rotationHandles=new Array(4);var geom,handle,rotationHandle;for(var i=0;i<8;++i){geom=box.geometry.components[i];handle=new OpenLayers.Feature.Vector(geom.clone(),null,typeof this.renderIntent=="string"?null:this.renderIntent);if(i%2==0){rotationHandle=new OpenLayers.Feature.Vector(geom.clone(),null,typeof this.rotationHandleSymbolizer=="string"?null:this.rotationHandleSymbolizer);rotationHandle.geometry.move=rotationHandleMoveFn;geom._rotationHandle=rotationHandle;rotationHandles[i/2]=rotationHandle;}
geom.move=vertexMoveFn;geom.resize=vertexResizeFn;geom.rotate=vertexRotateFn;handle.geometry.move=handleMoveFn;geom._handle=handle;handles[i]=handle;}
this.box=box;this.rotationHandles=rotationHandles;this.handles=handles;},createControl:function(){var control=this;this.dragControl=new OpenLayers.Control.DragFeature(this.layer,{documentDrag:true,moveFeature:function(pixel){if(this.feature===control.feature){this.feature=control.box;}
OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,arguments);},onDrag:function(feature,pixel){if(feature===control.box){control.transformFeature({center:control.center});control.drawHandles();}},onStart:function(feature,pixel){var eligible=!control.geometryTypes||OpenLayers.Util.indexOf(control.geometryTypes,feature.geometry.CLASS_NAME)!==-1;var i=OpenLayers.Util.indexOf(control.handles,feature);i+=OpenLayers.Util.indexOf(control.rotationHandles,feature);if(feature!==control.feature&&feature!==control.box&&i==-2&&eligible){control.setFeature(feature);}},onComplete:function(feature,pixel){control.events.triggerEvent("transformcomplete",{feature:control.feature});}});},drawHandles:function(){var layer=this.layer;for(var i=0;i<8;++i){if(this.rotate&&i%2===0){layer.drawFeature(this.rotationHandles[i/2],this.rotationHandleSymbolizer);}
layer.drawFeature(this.handles[i],this.renderIntent);}},transformFeature:function(mods){if(!this._setfeature){this.scale*=(mods.scale||1);this.ratio*=(mods.ratio||1);var oldRotation=this.rotation;this.rotation=(this.rotation+(mods.rotation||0))%360;if(this.events.triggerEvent("beforetransform",mods)!==false){var feature=this.feature;var geom=feature.geometry;var center=this.center;geom.rotate(-oldRotation,center);if(mods.scale||mods.ratio){geom.resize(mods.scale,center,mods.ratio);}else if(mods.center){feature.move(mods.center.getBounds().getCenterLonLat());}
geom.rotate(this.rotation,center);this.layer.drawFeature(feature);feature.toState(OpenLayers.State.UPDATE);this.events.triggerEvent("transform",mods);}}
this.layer.drawFeature(this.box,this.renderIntent);this.drawHandles();},destroy:function(){var geom;for(var i=0;i<8;++i){geom=this.box.geometry.components[i];geom._handle.destroy();geom._handle=null;geom._rotationHandle&&geom._rotationHandle.destroy();geom._rotationHandle=null;}
this.box.destroy();this.box=null;this.layer=null;this.dragControl.destroy();OpenLayers.Control.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Format.GPX=OpenLayers.Class(OpenLayers.Format.XML,{extractWaypoints:true,extractTracks:true,extractRoutes:true,extractAttributes:true,initialize:function(options){this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(doc){if(typeof doc=="string"){doc=OpenLayers.Format.XML.prototype.read.apply(this,[doc]);}
var features=[];if(this.extractTracks){var tracks=doc.getElementsByTagName("trk");for(var i=0,len=tracks.length;i<len;i++){var attrs={};if(this.extractAttributes){attrs=this.parseAttributes(tracks[i]);}
var segs=this.getElementsByTagNameNS(tracks[i],tracks[i].namespaceURI,"trkseg");for(var j=0,seglen=segs.length;j<seglen;j++){var track=this.extractSegment(segs[j],"trkpt");features.push(new OpenLayers.Feature.Vector(track,attrs));}}}
if(this.extractRoutes){var routes=doc.getElementsByTagName("rte");for(var k=0,klen=routes.length;k<klen;k++){var attrs={};if(this.extractAttributes){attrs=this.parseAttributes(routes[k]);}
var route=this.extractSegment(routes[k],"rtept");features.push(new OpenLayers.Feature.Vector(route,attrs));}}
if(this.extractWaypoints){var waypoints=doc.getElementsByTagName("wpt");for(var l=0,len=waypoints.length;l<len;l++){var attrs={};if(this.extractAttributes){attrs=this.parseAttributes(waypoints[l]);}
var wpt=new OpenLayers.Geometry.Point(waypoints[l].getAttribute("lon"),waypoints[l].getAttribute("lat"));features.push(new OpenLayers.Feature.Vector(wpt,attrs));}}
if(this.internalProjection&&this.externalProjection){for(var g=0,featLength=features.length;g<featLength;g++){features[g].geometry.transform(this.externalProjection,this.internalProjection);}}
return features;},extractSegment:function(segment,segmentType){var points=this.getElementsByTagNameNS(segment,segment.namespaceURI,segmentType);var point_features=[];for(var i=0,len=points.length;i<len;i++){point_features.push(new OpenLayers.Geometry.Point(points[i].getAttribute("lon"),points[i].getAttribute("lat")));}
return new OpenLayers.Geometry.LineString(point_features);},parseAttributes:function(node){var attributes={};var attrNode=node.firstChild;while(attrNode){if(attrNode.nodeType==1){var value=attrNode.firstChild;if(value.nodeType==3||value.nodeType==4){name=(attrNode.prefix)?attrNode.nodeName.split(":")[1]:attrNode.nodeName;if(name!="trkseg"&&name!="rtept"){attributes[name]=value.nodeValue;}}}
attrNode=attrNode.nextSibling;}
return attributes;},CLASS_NAME:"OpenLayers.Format.GPX"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],initialize:function(points){OpenLayers.Geometry.LineString.prototype.initialize.apply(this,arguments);},addComponent:function(point,index){var added=false;var lastPoint=this.components.pop();if(index!=null||!point.equals(lastPoint)){added=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);}
var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);return added;},removeComponent:function(point){if(this.components.length>4){this.components.pop();OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);}},move:function(x,y){for(var i=0,len=this.components.length;i<len-1;i++){this.components[i].move(x,y);}},rotate:function(angle,origin){for(var i=0,len=this.components.length;i<len-1;++i){this.components[i].rotate(angle,origin);}},resize:function(scale,origin,ratio){for(var i=0,len=this.components.length;i<len-1;++i){this.components[i].resize(scale,origin,ratio);}
return this;},transform:function(source,dest){if(source&&dest){for(var i=0,len=this.components.length;i<len-1;i++){var component=this.components[i];component.transform(source,dest);}
this.bounds=null;}
return this;},getCentroid:function(){if(this.components&&(this.components.length>2)){var sumX=0.0;var sumY=0.0;for(var i=0;i<this.components.length-1;i++){var b=this.components[i];var c=this.components[i+1];sumX+=(b.x+c.x)*(b.x*c.y-c.x*b.y);sumY+=(b.y+c.y)*(b.x*c.y-c.x*b.y);}
var area=-1*this.getArea();var x=sumX/(6*area);var y=sumY/(6*area);return new OpenLayers.Geometry.Point(x,y);}else{return null;}},getArea:function(){var area=0.0;if(this.components&&(this.components.length>2)){var sum=0.0;for(var i=0,len=this.components.length;i<len-1;i++){var b=this.components[i];var c=this.components[i+1];sum+=(b.x+c.x)*(c.y-b.y);}
area=-sum/2.0;}
return area;},getGeodesicArea:function(projection){var ring=this;if(projection){var gg=new OpenLayers.Projection("EPSG:4326");if(!gg.equals(projection)){ring=this.clone().transform(projection,gg);}}
var area=0.0;var len=ring.components&&ring.components.length;if(len>2){var p1,p2;for(var i=0;i<len-1;i++){p1=ring.components[i];p2=ring.components[i+1];area+=OpenLayers.Util.rad(p2.x-p1.x)*(2+Math.sin(OpenLayers.Util.rad(p1.y))+
Math.sin(OpenLayers.Util.rad(p2.y)));}
area=area*6378137.0*6378137.0/2.0;}
return area;},containsPoint:function(point){var approx=OpenLayers.Number.limitSigDigs;var digs=14;var px=approx(point.x,digs);var py=approx(point.y,digs);function getX(y,x1,y1,x2,y2){return(((x1-x2)*y)+((x2*y1)-(x1*y2)))/(y1-y2);}
var numSeg=this.components.length-1;var start,end,x1,y1,x2,y2,cx,cy;var crosses=0;for(var i=0;i<numSeg;++i){start=this.components[i];x1=approx(start.x,digs);y1=approx(start.y,digs);end=this.components[i+1];x2=approx(end.x,digs);y2=approx(end.y,digs);if(y1==y2){if(py==y1){if(x1<=x2&&(px>=x1&&px<=x2)||x1>=x2&&(px<=x1&&px>=x2)){crosses=-1;break;}}
continue;}
cx=approx(getX(py,x1,y1,x2,y2),digs);if(cx==px){if(y1<y2&&(py>=y1&&py<=y2)||y1>y2&&(py<=y1&&py>=y2)){crosses=-1;break;}}
if(cx<=px){continue;}
if(x1!=x2&&(cx<Math.min(x1,x2)||cx>Math.max(x1,x2))){continue;}
if(y1<y2&&(py>=y1&&py<y2)||y1>y2&&(py<y1&&py>=y2)){++crosses;}}
var contained=(crosses==-1)?1:!!(crosses&1);return contained;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"){intersect=geometry.intersects(this);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){intersect=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[geometry]);}else{for(var i=0,len=geometry.components.length;i<len;++i){intersect=geometry.components[i].intersects(this);if(intersect){break;}}}
return intersect;},getVertices:function(nodes){return(nodes===true)?[]:this.components.slice(0,this.components.length-1);},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],initialize:function(components){OpenLayers.Geometry.Collection.prototype.initialize.apply(this,arguments);},split:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,sourceLine,sourceLines,sourceSplit,targetSplit;var sourceParts=[];var targetParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){sourceLine=this.components[i];sourceSplit=false;for(var j=0;j<targetParts.length;++j){splits=sourceLine.split(targetParts[j],options);if(splits){if(mutual){sourceLines=splits[0];for(var k=0,klen=sourceLines.length;k<klen;++k){if(k===0&&sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLines[k]);}else{sourceParts.push(new OpenLayers.Geometry.MultiLineString([sourceLines[k]]));}}
sourceSplit=true;splits=splits[1];}
if(splits.length){splits.unshift(j,1);Array.prototype.splice.apply(targetParts,splits);break;}}}
if(!sourceSplit){if(sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLine.clone());}else{sourceParts=[new OpenLayers.Geometry.MultiLineString(sourceLine.clone())];}}}
if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
return results;},splitWith:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,targetLine,sourceLines,sourceSplit,targetSplit,sourceParts,targetParts;if(geometry instanceof OpenLayers.Geometry.LineString){targetParts=[];sourceParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){targetSplit=false;targetLine=this.components[i];for(var j=0;j<sourceParts.length;++j){splits=sourceParts[j].split(targetLine,options);if(splits){if(mutual){sourceLines=splits[0];if(sourceLines.length){sourceLines.unshift(j,1);Array.prototype.splice.apply(sourceParts,sourceLines);j+=sourceLines.length-2;}
splits=splits[1];if(splits.length===0){splits=[targetLine.clone()];}}
for(var k=0,klen=splits.length;k<klen;++k){if(k===0&&targetParts.length){targetParts[targetParts.length-1].addComponent(splits[k]);}else{targetParts.push(new OpenLayers.Geometry.MultiLineString([splits[k]]));}}
targetSplit=true;}}
if(!targetSplit){if(targetParts.length){targetParts[targetParts.length-1].addComponent(targetLine.clone());}else{targetParts=[new OpenLayers.Geometry.MultiLineString([targetLine.clone()])];}}}}else{results=geometry.split(this);}
if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
return results;},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,freehand:false,freehandToggle:'shiftKey',initialize:function(control,callbacks,options){OpenLayers.Handler.Point.prototype.initialize.apply(this,arguments);},createFeature:function(pixel){var lonlat=this.control.map.getLonLatFromPixel(pixel);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat));this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([this.point.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.line,this.point],{silent:true});},destroyFeature:function(){OpenLayers.Handler.Point.prototype.destroyFeature.apply(this);this.line=null;},removePoint:function(){if(this.point){this.layer.removeFeatures([this.point]);}},addPoint:function(pixel){this.layer.removeFeatures([this.point]);var lonlat=this.control.map.getLonLatFromPixel(pixel);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();},freehandMode:function(evt){return(this.freehandToggle&&evt[this.freehandToggle])?!this.freehand:this.freehand;},modifyFeature:function(pixel){var lonlat=this.control.map.getLonLatFromPixel(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.getSketch()]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style);},getSketch:function(){return this.line;},getGeometry:function(){var geometry=this.line&&this.line.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiLineString([geometry]);}
return geometry;},mousedown:function(evt){if(this.lastDown&&this.lastDown.equals(evt.xy)){return false;}
if(this.lastDown==null){if(this.persist){this.destroyFeature();}
this.createFeature(evt.xy);}else if((this.lastUp==null)||!this.lastUp.equals(evt.xy)){this.addPoint(evt.xy);}
this.mouseDown=true;this.lastDown=evt.xy;this.drawing=true;return false;},mousemove:function(evt){if(this.drawing){if(this.mouseDown&&this.freehandMode(evt)){this.addPoint(evt.xy);}else{this.modifyFeature(evt.xy);}}
return true;},mouseup:function(evt){this.mouseDown=false;if(this.drawing){if(this.freehandMode(evt)){this.removePoint();this.finalize();}else{if(this.lastUp==null){this.addPoint(evt.xy);}
this.lastUp=evt.xy;}
return false;}
return true;},dblclick:function(evt){if(!this.freehandMode(evt)){var index=this.line.geometry.components.length-1;this.line.geometry.removeComponent(this.line.geometry.components[index]);this.removePoint();this.finalize();}
return false;},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Control.Split=OpenLayers.Class(OpenLayers.Control,{EVENT_TYPES:["beforesplit","split","aftersplit"],layer:null,source:null,sourceOptions:null,tolerance:null,edge:true,deferDelete:false,mutual:true,targetFilter:null,sourceFilter:null,handler:null,initialize:function(options){Array.prototype.push.apply(this.EVENT_TYPES,OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);this.options=options||{};if(this.options.source){this.setSource(this.options.source);}},setSource:function(layer){if(this.active){this.deactivate();if(this.handler){this.handler.destroy();delete this.handler;}
this.source=layer;this.activate();}else{this.source=layer;}},activate:function(){var activated=OpenLayers.Control.prototype.activate.call(this);if(activated){if(!this.source){if(!this.handler){this.handler=new OpenLayers.Handler.Path(this,{done:function(geometry){this.onSketchComplete({feature:new OpenLayers.Feature.Vector(geometry)});}},{layerOptions:this.sourceOptions});}
this.handler.activate();}else if(this.source.events){this.source.events.on({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});}}
return activated;},deactivate:function(){var deactivated=OpenLayers.Control.prototype.deactivate.call(this);if(deactivated){if(this.source&&this.source.events){this.layer.events.un({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});}}
return deactivated;},onSketchComplete:function(event){this.feature=null;return!this.considerSplit(event.feature);},afterFeatureModified:function(event){if(event.modified){var feature=event.feature;if(feature.geometry instanceof OpenLayers.Geometry.LineString||feature.geometry instanceof OpenLayers.Geometry.MultiLineString){this.feature=event.feature;this.considerSplit(event.feature);}}},removeByGeometry:function(features,geometry){for(var i=0,len=features.length;i<len;++i){if(features[i].geometry===geometry){features.splice(i,1);break;}}},isEligible:function(target){return(target.state!==OpenLayers.State.DELETE)&&(target.geometry instanceof OpenLayers.Geometry.LineString||target.geometry instanceof OpenLayers.Geometry.MultiLineString)&&(this.feature!==target)&&(!this.targetFilter||this.targetFilter.evaluate(target.attributes));},considerSplit:function(feature){var sourceSplit=false;var targetSplit=false;if(!this.sourceFilter||this.sourceFilter.evaluate(feature.attributes)){var features=this.layer&&this.layer.features||[];var target,results,proceed;var additions=[],removals=[];var mutual=(this.layer===this.source)&&this.mutual;var options={edge:this.edge,tolerance:this.tolerance,mutual:mutual};var sourceParts=[feature.geometry];var targetFeature,targetParts;var source,parts;for(var i=0,len=features.length;i<len;++i){targetFeature=features[i];if(this.isEligible(targetFeature)){targetParts=[targetFeature.geometry];for(var j=0;j<sourceParts.length;++j){source=sourceParts[j];for(var k=0;k<targetParts.length;++k){target=targetParts[k];if(source.getBounds().intersectsBounds(target.getBounds())){results=source.split(target,options);if(results){proceed=this.events.triggerEvent("beforesplit",{source:feature,target:targetFeature});if(proceed!==false){if(mutual){parts=results[0];if(parts.length>1){parts.unshift(j,1);Array.prototype.splice.apply(sourceParts,parts);j+=parts.length-3;}
results=results[1];}
if(results.length>1){results.unshift(k,1);Array.prototype.splice.apply(targetParts,results);k+=results.length-3;}}}}}}
if(targetParts&&targetParts.length>1){this.geomsToFeatures(targetFeature,targetParts);this.events.triggerEvent("split",{original:targetFeature,features:targetParts});Array.prototype.push.apply(additions,targetParts);removals.push(targetFeature);targetSplit=true;}}}
if(sourceParts&&sourceParts.length>1){this.geomsToFeatures(feature,sourceParts);this.events.triggerEvent("split",{original:feature,features:sourceParts});Array.prototype.push.apply(additions,sourceParts);removals.push(feature);sourceSplit=true;}
if(sourceSplit||targetSplit){if(this.deferDelete){var feat,destroys=[];for(var i=0,len=removals.length;i<len;++i){feat=removals[i];if(feat.state===OpenLayers.State.INSERT){destroys.push(feat);}else{feat.state=OpenLayers.State.DELETE;this.layer.drawFeature(feat);}}
this.layer.destroyFeatures(destroys,{silent:true});for(var i=0,len=additions.length;i<len;++i){additions[i].state=OpenLayers.State.INSERT;}}else{this.layer.destroyFeatures(removals,{silent:true});}
this.layer.addFeatures(additions,{silent:true});this.events.triggerEvent("aftersplit",{source:feature,features:additions});}}
return sourceSplit;},geomsToFeatures:function(feature,geoms){var clone=feature.clone();delete clone.geometry;var newFeature;for(var i=0,len=geoms.length;i<len;++i){newFeature=clone.clone();newFeature.geometry=geoms[i];newFeature.state=OpenLayers.State.INSERT;geoms[i]=newFeature;}},destroy:function(){if(this.active){this.deactivate();}
OpenLayers.Control.prototype.destroy.call(this);},CLASS_NAME:"OpenLayers.Control.Split"});OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],initialize:function(components){OpenLayers.Geometry.Collection.prototype.initialize.apply(this,arguments);},getArea:function(){var area=0.0;if(this.components&&(this.components.length>0)){area+=Math.abs(this.components[0].getArea());for(var i=1,len=this.components.length;i<len;i++){area-=Math.abs(this.components[i].getArea());}}
return area;},getGeodesicArea:function(projection){var area=0.0;if(this.components&&(this.components.length>0)){area+=Math.abs(this.components[0].getGeodesicArea(projection));for(var i=1,len=this.components.length;i<len;i++){area-=Math.abs(this.components[i].getGeodesicArea(projection));}}
return area;},containsPoint:function(point){var numRings=this.components.length;var contained=false;if(numRings>0){contained=this.components[0].containsPoint(point);if(contained!==1){if(contained&&numRings>1){var hole;for(var i=1;i<numRings;++i){hole=this.components[i].containsPoint(point);if(hole){if(hole===1){contained=1;}else{contained=false;}
break;}}}}}
return contained;},intersects:function(geometry){var intersect=false;var i,len;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"||geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){for(i=0,len=this.components.length;i<len;++i){intersect=geometry.intersects(this.components[i]);if(intersect){break;}}
if(!intersect){for(i=0,len=geometry.components.length;i<len;++i){intersect=this.containsPoint(geometry.components[i]);if(intersect){break;}}}}else{for(i=0,len=geometry.components.length;i<len;++i){intersect=this.intersects(geometry.components[i]);if(intersect){break;}}}
if(!intersect&&geometry.CLASS_NAME=="OpenLayers.Geometry.Polygon"){var ring=this.components[0];for(i=0,len=ring.components.length;i<len;++i){intersect=geometry.containsPoint(ring.components[i]);if(intersect){break;}}}
return intersect;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var result;if(!edge&&this.intersects(geometry)){result=0;}else{result=OpenLayers.Geometry.Collection.prototype.distanceTo.apply(this,[geometry,options]);}
return result;},CLASS_NAME:"OpenLayers.Geometry.Polygon"});OpenLayers.Geometry.Polygon.createRegularPolygon=function(origin,radius,sides,rotation){var angle=Math.PI*((1/sides)-(1/2));if(rotation){angle+=(rotation/180)*Math.PI;}
var rotatedAngle,x,y;var points=[];for(var i=0;i<sides;++i){rotatedAngle=angle+(i*2*Math.PI/sides);x=origin.x+(radius*Math.cos(rotatedAngle));y=origin.y+(radius*Math.sin(rotatedAngle));points.push(new OpenLayers.Geometry.Point(x,y));}
var ring=new OpenLayers.Geometry.LinearRing(points);return new OpenLayers.Geometry.Polygon([ring]);};OpenLayers.Format.GeoRSS=OpenLayers.Class(OpenLayers.Format.XML,{rssns:"http://backend.userland.com/rss2",featureNS:"http://mapserver.gis.umn.edu/mapserver",georssns:"http://www.georss.org/georss",geons:"http://www.w3.org/2003/01/geo/wgs84_pos#",featureTitle:"Untitled",featureDescription:"No Description",gmlParser:null,xy:false,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},createGeometryFromItem:function(item){var point=this.getElementsByTagNameNS(item,this.georssns,"point");var lat=this.getElementsByTagNameNS(item,this.geons,'lat');var lon=this.getElementsByTagNameNS(item,this.geons,'long');var line=this.getElementsByTagNameNS(item,this.georssns,"line");var polygon=this.getElementsByTagNameNS(item,this.georssns,"polygon");var where=this.getElementsByTagNameNS(item,this.georssns,"where");var box=this.getElementsByTagNameNS(item,this.georssns,"box");if(point.length>0||(lat.length>0&&lon.length>0)){var location;if(point.length>0){location=OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s+/);if(location.length!=2){location=OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s*,\s*/);}}else{location=[parseFloat(lat[0].firstChild.nodeValue),parseFloat(lon[0].firstChild.nodeValue)];}
var geometry=new OpenLayers.Geometry.Point(parseFloat(location[1]),parseFloat(location[0]));}else if(line.length>0){var coords=OpenLayers.String.trim(this.concatChildValues(line[0])).split(/\s+/);var components=[];var point;for(var i=0,len=coords.length;i<len;i+=2){point=new OpenLayers.Geometry.Point(parseFloat(coords[i+1]),parseFloat(coords[i]));components.push(point);}
geometry=new OpenLayers.Geometry.LineString(components);}else if(polygon.length>0){var coords=OpenLayers.String.trim(this.concatChildValues(polygon[0])).split(/\s+/);var components=[];var point;for(var i=0,len=coords.length;i<len;i+=2){point=new OpenLayers.Geometry.Point(parseFloat(coords[i+1]),parseFloat(coords[i]));components.push(point);}
geometry=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);}else if(where.length>0){if(!this.gmlParser){this.gmlParser=new OpenLayers.Format.GML({'xy':this.xy});}
var feature=this.gmlParser.parseFeature(where[0]);geometry=feature.geometry;}else if(box.length>0){var coords=OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/);var components=[];var point;if(coords.length>3){point=new OpenLayers.Geometry.Point(parseFloat(coords[1]),parseFloat(coords[0]));components.push(point);point=new OpenLayers.Geometry.Point(parseFloat(coords[1]),parseFloat(coords[2]));components.push(point);point=new OpenLayers.Geometry.Point(parseFloat(coords[3]),parseFloat(coords[2]));components.push(point);point=new OpenLayers.Geometry.Point(parseFloat(coords[3]),parseFloat(coords[0]));components.push(point);point=new OpenLayers.Geometry.Point(parseFloat(coords[1]),parseFloat(coords[0]));components.push(point);}
geometry=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);}
if(geometry&&this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}
return geometry;},createFeatureFromItem:function(item){var geometry=this.createGeometryFromItem(item);var title=this.getChildValue(item,"*","title",this.featureTitle);var description=this.getChildValue(item,"*","description",this.getChildValue(item,"*","content",this.getChildValue(item,"*","summary",this.featureDescription)));var link=this.getChildValue(item,"*","link");if(!link){try{link=this.getElementsByTagNameNS(item,"*","link")[0].getAttribute("href");}catch(e){link=null;}}
var id=this.getChildValue(item,"*","id",null);var data={"title":title,"description":description,"link":link};var feature=new OpenLayers.Feature.Vector(geometry,data);feature.fid=id;return feature;},getChildValue:function(node,nsuri,name,def){var value;var eles=this.getElementsByTagNameNS(node,nsuri,name);if(eles&&eles[0]&&eles[0].firstChild&&eles[0].firstChild.nodeValue){value=eles[0].firstChild.nodeValue;}else{value=(def==undefined)?"":def;}
return value;},read:function(doc){if(typeof doc=="string"){doc=OpenLayers.Format.XML.prototype.read.apply(this,[doc]);}
var itemlist=null;itemlist=this.getElementsByTagNameNS(doc,'*','item');if(itemlist.length==0){itemlist=this.getElementsByTagNameNS(doc,'*','entry');}
var numItems=itemlist.length;var features=new Array(numItems);for(var i=0;i<numItems;i++){features[i]=this.createFeatureFromItem(itemlist[i]);}
return features;},write:function(features){var georss;if(features instanceof Array){georss=this.createElementNS(this.rssns,"rss");for(var i=0,len=features.length;i<len;i++){georss.appendChild(this.createFeatureXML(features[i]));}}else{georss=this.createFeatureXML(features);}
return OpenLayers.Format.XML.prototype.write.apply(this,[georss]);},createFeatureXML:function(feature){var geometryNode=this.buildGeometryNode(feature.geometry);var featureNode=this.createElementNS(this.rssns,"item");var titleNode=this.createElementNS(this.rssns,"title");titleNode.appendChild(this.createTextNode(feature.attributes.title?feature.attributes.title:""));var descNode=this.createElementNS(this.rssns,"description");descNode.appendChild(this.createTextNode(feature.attributes.description?feature.attributes.description:""));featureNode.appendChild(titleNode);featureNode.appendChild(descNode);if(feature.attributes.link){var linkNode=this.createElementNS(this.rssns,"link");linkNode.appendChild(this.createTextNode(feature.attributes.link));featureNode.appendChild(linkNode);}
for(var attr in feature.attributes){if(attr=="link"||attr=="title"||attr=="description"){continue;}
var attrText=this.createTextNode(feature.attributes[attr]);var nodename=attr;if(attr.search(":")!=-1){nodename=attr.split(":")[1];}
var attrContainer=this.createElementNS(this.featureNS,"feature:"+nodename);attrContainer.appendChild(attrText);featureNode.appendChild(attrContainer);}
featureNode.appendChild(geometryNode);return featureNode;},buildGeometryNode:function(geometry){if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
var node;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Polygon"){node=this.createElementNS(this.georssns,'georss:polygon');node.appendChild(this.buildCoordinatesNode(geometry.components[0]));}
else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"){node=this.createElementNS(this.georssns,'georss:line');node.appendChild(this.buildCoordinatesNode(geometry));}
else if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){node=this.createElementNS(this.georssns,'georss:point');node.appendChild(this.buildCoordinatesNode(geometry));}else{throw"Couldn't parse "+geometry.CLASS_NAME;}
return node;},buildCoordinatesNode:function(geometry){var points=null;if(geometry.components){points=geometry.components;}
var path;if(points){var numPoints=points.length;var parts=new Array(numPoints);for(var i=0;i<numPoints;i++){parts[i]=points[i].y+" "+points[i].x;}
path=parts.join(" ");}else{path=geometry.y+" "+geometry.x;}
return this.createTextNode(path);},CLASS_NAME:"OpenLayers.Format.GeoRSS"});OpenLayers.Format.KML=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{kml:"http://www.opengis.net/kml/2.2",gx:"http://www.google.com/kml/ext/2.2"},kmlns:"http://earth.google.com/kml/2.0",placemarksDesc:"No description available",foldersName:"OpenLayers export",foldersDesc:"Exported on "+new Date(),extractAttributes:true,extractStyles:false,extractTracks:false,trackAttributes:null,internalns:null,features:null,styles:null,styleBaseUrl:"",fetched:null,maxDepth:0,initialize:function(options){this.regExes={trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g),kmlColor:(/(\w{2})(\w{2})(\w{2})(\w{2})/),kmlIconPalette:(/root:\/\/icons\/palette-(\d+)(\.\w+)/),straightBracket:(/\$\[(.*?)\]/g)};this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){this.features=[];this.styles={};this.fetched={};var options={depth:0,styleBaseUrl:this.styleBaseUrl};return this.parseData(data,options);},parseData:function(data,options){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var types=["Link","NetworkLink","Style","StyleMap","Placemark"];for(var i=0,len=types.length;i<len;++i){var type=types[i];var nodes=this.getElementsByTagNameNS(data,"*",type);if(nodes.length==0){continue;}
switch(type.toLowerCase()){case"link":case"networklink":this.parseLinks(nodes,options);break;case"style":if(this.extractStyles){this.parseStyles(nodes,options);}
break;case"stylemap":if(this.extractStyles){this.parseStyleMaps(nodes,options);}
break;case"placemark":this.parseFeatures(nodes,options);break;}}
return this.features;},parseLinks:function(nodes,options){if(options.depth>=this.maxDepth){return false;}
var newOptions=OpenLayers.Util.extend({},options);newOptions.depth++;for(var i=0,len=nodes.length;i<len;i++){var href=this.parseProperty(nodes[i],"*","href");if(href&&!this.fetched[href]){this.fetched[href]=true;var data=this.fetchLink(href);if(data){this.parseData(data,newOptions);}}}},fetchLink:function(href){var request=OpenLayers.Request.GET({url:href,async:false});if(request){return request.responseText;}},parseStyles:function(nodes,options){for(var i=0,len=nodes.length;i<len;i++){var style=this.parseStyle(nodes[i]);if(style){var styleName=(options.styleBaseUrl||"")+"#"+style.id;this.styles[styleName]=style;}}},parseKmlColor:function(kmlColor){var color=null;if(kmlColor){var matches=kmlColor.match(this.regExes.kmlColor);if(matches){color={color:'#'+matches[4]+matches[3]+matches[2],opacity:parseInt(matches[1],16)/255};}}
return color;},parseStyle:function(node){var style={};var types=["LineStyle","PolyStyle","IconStyle","BalloonStyle","LabelStyle"];var type,nodeList,geometry,parser;for(var i=0,len=types.length;i<len;++i){type=types[i];styleTypeNode=this.getElementsByTagNameNS(node,"*",type)[0];if(!styleTypeNode){continue;}
switch(type.toLowerCase()){case"linestyle":var kmlColor=this.parseProperty(styleTypeNode,"*","color");var color=this.parseKmlColor(kmlColor);if(color){style["strokeColor"]=color.color;style["strokeOpacity"]=color.opacity;}
var width=this.parseProperty(styleTypeNode,"*","width");if(width){style["strokeWidth"]=width;}
break;case"polystyle":var kmlColor=this.parseProperty(styleTypeNode,"*","color");var color=this.parseKmlColor(kmlColor);if(color){style["fillOpacity"]=color.opacity;style["fillColor"]=color.color;}
var fill=this.parseProperty(styleTypeNode,"*","fill");if(fill=="0"){style["fillColor"]="none";}
var outline=this.parseProperty(styleTypeNode,"*","outline");if(outline=="0"){style["strokeWidth"]="0";}
break;case"iconstyle":var scale=parseFloat(this.parseProperty(styleTypeNode,"*","scale")||1);var width=32*scale;var height=32*scale;var iconNode=this.getElementsByTagNameNS(styleTypeNode,"*","Icon")[0];if(iconNode){var href=this.parseProperty(iconNode,"*","href");if(href){var w=this.parseProperty(iconNode,"*","w");var h=this.parseProperty(iconNode,"*","h");var google="http://maps.google.com/mapfiles/kml";if(OpenLayers.String.startsWith(href,google)&&!w&&!h){w=64;h=64;scale=scale/2;}
w=w||h;h=h||w;if(w){width=parseInt(w)*scale;}
if(h){height=parseInt(h)*scale;}
var matches=href.match(this.regExes.kmlIconPalette);if(matches){var palette=matches[1];var file_extension=matches[2];var x=this.parseProperty(iconNode,"*","x");var y=this.parseProperty(iconNode,"*","y");var posX=x?x/32:0;var posY=y?(7-y/32):7;var pos=posY*8+posX;href="http://maps.google.com/mapfiles/kml/pal"
+palette+"/icon"+pos+file_extension;}
style["graphicOpacity"]=1;style["externalGraphic"]=href;}}
var hotSpotNode=this.getElementsByTagNameNS(styleTypeNode,"*","hotSpot")[0];if(hotSpotNode){var x=parseFloat(hotSpotNode.getAttribute("x"));var y=parseFloat(hotSpotNode.getAttribute("y"));var xUnits=hotSpotNode.getAttribute("xunits");if(xUnits=="pixels"){style["graphicXOffset"]=-x*scale;}
else if(xUnits=="insetPixels"){style["graphicXOffset"]=-width+(x*scale);}
else if(xUnits=="fraction"){style["graphicXOffset"]=-width*x;}
var yUnits=hotSpotNode.getAttribute("yunits");if(yUnits=="pixels"){style["graphicYOffset"]=-height+(y*scale)+1;}
else if(yUnits=="insetPixels"){style["graphicYOffset"]=-(y*scale)+1;}
else if(yUnits=="fraction"){style["graphicYOffset"]=-height*(1-y)+1;}}
style["graphicWidth"]=width;style["graphicHeight"]=height;break;case"balloonstyle":var balloonStyle=OpenLayers.Util.getXmlNodeValue(styleTypeNode);if(balloonStyle){style["balloonStyle"]=balloonStyle.replace(this.regExes.straightBracket,"${$1}");}
break;case"labelstyle":var kmlColor=this.parseProperty(styleTypeNode,"*","color");var color=this.parseKmlColor(kmlColor);if(color){style["fontColor"]=color.color;style["fontOpacity"]=color.opacity;}
break;default:}}
if(!style["strokeColor"]&&style["fillColor"]){style["strokeColor"]=style["fillColor"];}
var id=node.getAttribute("id");if(id&&style){style.id=id;}
return style;},parseStyleMaps:function(nodes,options){for(var i=0,len=nodes.length;i<len;i++){var node=nodes[i];var pairs=this.getElementsByTagNameNS(node,"*","Pair");var id=node.getAttribute("id");for(var j=0,jlen=pairs.length;j<jlen;j++){var pair=pairs[j];var key=this.parseProperty(pair,"*","key");var styleUrl=this.parseProperty(pair,"*","styleUrl");if(styleUrl&&key=="normal"){this.styles[(options.styleBaseUrl||"")+"#"+id]=this.styles[(options.styleBaseUrl||"")+styleUrl];}
if(styleUrl&&key=="highlight"){}}}},parseFeatures:function(nodes,options){var features=[];for(var i=0,len=nodes.length;i<len;i++){var featureNode=nodes[i];var feature=this.parseFeature.apply(this,[featureNode]);if(feature){if(this.extractStyles&&feature.attributes&&feature.attributes.styleUrl){feature.style=this.getStyle(feature.attributes.styleUrl,options);}
if(this.extractStyles){var inlineStyleNode=this.getElementsByTagNameNS(featureNode,"*","Style")[0];if(inlineStyleNode){var inlineStyle=this.parseStyle(inlineStyleNode);if(inlineStyle){feature.style=OpenLayers.Util.extend(feature.style,inlineStyle);}}}
if(this.extractTracks){var tracks=this.getElementsByTagNameNS(featureNode,this.namespaces.gx,"Track");if(tracks&&tracks.length>0){var track=tracks[0];var container={features:[],feature:feature};this.readNode(track,container);if(container.features.length>0){features.push.apply(features,container.features);}}}else{features.push(feature);}}else{throw"Bad Placemark: "+i;}}
this.features=this.features.concat(features);},readers:{"kml":{"when":function(node,container){container.whens.push(OpenLayers.Date.parse(this.getChildValue(node)));},"_trackPointAttribute":function(node,container){var name=node.nodeName.split(":").pop();container.attributes[name].push(this.getChildValue(node));}},"gx":{"Track":function(node,container){var obj={whens:[],points:[],angles:[]};if(this.trackAttributes){var name;obj.attributes={};for(var i=0,ii=this.trackAttributes.length;i<ii;++i){name=this.trackAttributes[i];obj.attributes[name]=[];if(!(name in this.readers.kml)){this.readers.kml[name]=this.readers.kml._trackPointAttribute;}}}
this.readChildNodes(node,obj);if(obj.whens.length!==obj.points.length){throw new Error("gx:Track with unequal number of when ("+obj.whens.length+") and gx:coord ("+obj.points.length+") elements.");}
var hasAngles=obj.angles.length>0;if(hasAngles&&obj.whens.length!==obj.angles.length){throw new Error("gx:Track with unequal number of when ("+obj.whens.length+") and gx:angles ("+obj.angles.length+") elements.");}
var feature,point,angles;for(var i=0,ii=obj.whens.length;i<ii;++i){feature=container.feature.clone();feature.fid=container.feature.fid||container.feature.id;point=obj.points[i];feature.geometry=point;if("z"in point){feature.attributes.altitude=point.z;}
if(this.internalProjection&&this.externalProjection){feature.geometry.transform(this.externalProjection,this.internalProjection);}
if(this.trackAttributes){for(var j=0,jj=this.trackAttributes.length;j<jj;++j){feature.attributes[name]=obj.attributes[this.trackAttributes[j]][i];}}
feature.attributes.when=obj.whens[i];feature.attributes.trackId=container.feature.id;if(hasAngles){angles=obj.angles[i];feature.attributes.heading=parseFloat(angles[0]);feature.attributes.tilt=parseFloat(angles[1]);feature.attributes.roll=parseFloat(angles[2]);}
container.features.push(feature);}},"coord":function(node,container){var str=this.getChildValue(node);var coords=str.replace(this.regExes.trimSpace,"").split(/\s+/);var point=new OpenLayers.Geometry.Point(coords[0],coords[1]);if(coords.length>2){point.z=parseFloat(coords[2]);}
container.points.push(point);},"angles":function(node,container){var str=this.getChildValue(node);var parts=str.replace(this.regExes.trimSpace,"").split(/\s+/);container.angles.push(parts);}}},parseFeature:function(node){var order=["MultiGeometry","Polygon","LineString","Point"];var type,nodeList,geometry,parser;for(var i=0,len=order.length;i<len;++i){type=order[i];this.internalns=node.namespaceURI?node.namespaceURI:this.kmlns;nodeList=this.getElementsByTagNameNS(node,this.internalns,type);if(nodeList.length>0){var parser=this.parseGeometry[type.toLowerCase()];if(parser){geometry=parser.apply(this,[nodeList[0]]);if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}}else{OpenLayers.Console.error(OpenLayers.i18n("unsupportedGeometryType",{'geomType':type}));}
break;}}
var attributes;if(this.extractAttributes){attributes=this.parseAttributes(node);}
var feature=new OpenLayers.Feature.Vector(geometry,attributes);var fid=node.getAttribute("id")||node.getAttribute("name");if(fid!=null){feature.fid=fid;}
return feature;},getStyle:function(styleUrl,options){var styleBaseUrl=OpenLayers.Util.removeTail(styleUrl);var newOptions=OpenLayers.Util.extend({},options);newOptions.depth++;newOptions.styleBaseUrl=styleBaseUrl;if(!this.styles[styleUrl]&&!OpenLayers.String.startsWith(styleUrl,"#")&&newOptions.depth<=this.maxDepth&&!this.fetched[styleBaseUrl]){var data=this.fetchLink(styleBaseUrl);if(data){this.parseData(data,newOptions);}}
var style=OpenLayers.Util.extend({},this.styles[styleUrl]);return style;},parseGeometry:{point:function(node){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"coordinates");var coords=[];if(nodeList.length>0){var coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.removeSpace,"");coords=coordString.split(",");}
var point=null;if(coords.length>1){if(coords.length==2){coords[2]=null;}
point=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{throw"Bad coordinate string: "+coordString;}
return point;},linestring:function(node,ring){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"coordinates");var line=null;if(nodeList.length>0){var coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coordString=coordString.replace(this.regExes.trimComma,",");var pointList=coordString.split(this.regExes.splitSpace);var numPoints=pointList.length;var points=new Array(numPoints);var coords,numCoords;for(var i=0;i<numPoints;++i){coords=pointList[i].split(",");numCoords=coords.length;if(numCoords>1){if(coords.length==2){coords[2]=null;}
points[i]=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{throw"Bad LineString point coordinates: "+
pointList[i];}}
if(numPoints){if(ring){line=new OpenLayers.Geometry.LinearRing(points);}else{line=new OpenLayers.Geometry.LineString(points);}}else{throw"Bad LineString coordinates: "+coordString;}}
return line;},polygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"LinearRing");var numRings=nodeList.length;var components=new Array(numRings);if(numRings>0){var ring;for(var i=0,len=nodeList.length;i<len;++i){ring=this.parseGeometry.linestring.apply(this,[nodeList[i],true]);if(ring){components[i]=ring;}else{throw"Bad LinearRing geometry: "+i;}}}
return new OpenLayers.Geometry.Polygon(components);},multigeometry:function(node){var child,parser;var parts=[];var children=node.childNodes;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){var type=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var parser=this.parseGeometry[type.toLowerCase()];if(parser){parts.push(parser.apply(this,[child]));}}}
return new OpenLayers.Geometry.Collection(parts);}},parseAttributes:function(node){var attributes={};var edNodes=node.getElementsByTagName("ExtendedData");if(edNodes.length){attributes=this.parseExtendedData(edNodes[0]);}
var child,grandchildren,grandchild;var children=node.childNodes;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){grandchildren=child.childNodes;if(grandchildren.length>=1&&grandchildren.length<=3){var grandchild;switch(grandchildren.length){case 1:grandchild=grandchildren[0];break;case 2:var c1=grandchildren[0];var c2=grandchildren[1];grandchild=(c1.nodeType==3||c1.nodeType==4)?c1:c2;break;case 3:default:grandchild=grandchildren[1];break;}
if(grandchild.nodeType==3||grandchild.nodeType==4){var name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var value=OpenLayers.Util.getXmlNodeValue(grandchild);if(value){value=value.replace(this.regExes.trimSpace,"");attributes[name]=value;}}}}}
return attributes;},parseExtendedData:function(node){var attributes={};var i,len,data,key;var dataNodes=node.getElementsByTagName("Data");for(i=0,len=dataNodes.length;i<len;i++){data=dataNodes[i];key=data.getAttribute("name");var ed={};var valueNode=data.getElementsByTagName("value");if(valueNode.length){ed['value']=this.getChildValue(valueNode[0]);}
var nameNode=data.getElementsByTagName("displayName");if(nameNode.length){ed['displayName']=this.getChildValue(nameNode[0]);}
attributes[key]=ed;}
var simpleDataNodes=node.getElementsByTagName("SimpleData");for(i=0,len=simpleDataNodes.length;i<len;i++){var ed={};data=simpleDataNodes[i];key=data.getAttribute("name");ed['value']=this.getChildValue(data);ed['displayName']=key;attributes[key]=ed;}
return attributes;},parseProperty:function(xmlNode,namespace,tagName){var value;var nodeList=this.getElementsByTagNameNS(xmlNode,namespace,tagName);try{value=OpenLayers.Util.getXmlNodeValue(nodeList[0]);}catch(e){value=null;}
return value;},write:function(features){if(!(features instanceof Array)){features=[features];}
var kml=this.createElementNS(this.kmlns,"kml");var folder=this.createFolderXML();for(var i=0,len=features.length;i<len;++i){folder.appendChild(this.createPlacemarkXML(features[i]));}
kml.appendChild(folder);return OpenLayers.Format.XML.prototype.write.apply(this,[kml]);},createFolderXML:function(){var folder=this.createElementNS(this.kmlns,"Folder");if(this.foldersName){var folderName=this.createElementNS(this.kmlns,"name");var folderNameText=this.createTextNode(this.foldersName);folderName.appendChild(folderNameText);folder.appendChild(folderName);}
if(this.foldersDesc){var folderDesc=this.createElementNS(this.kmlns,"description");var folderDescText=this.createTextNode(this.foldersDesc);folderDesc.appendChild(folderDescText);folder.appendChild(folderDesc);}
return folder;},createPlacemarkXML:function(feature){var placemarkName=this.createElementNS(this.kmlns,"name");var name=feature.style&&feature.style.label?feature.style.label:feature.attributes.name||feature.id;placemarkName.appendChild(this.createTextNode(name));var placemarkDesc=this.createElementNS(this.kmlns,"description");var desc=feature.attributes.description||this.placemarksDesc;placemarkDesc.appendChild(this.createTextNode(desc));var placemarkNode=this.createElementNS(this.kmlns,"Placemark");if(feature.fid!=null){placemarkNode.setAttribute("id",feature.fid);}
placemarkNode.appendChild(placemarkName);placemarkNode.appendChild(placemarkDesc);var geometryNode=this.buildGeometryNode(feature.geometry);placemarkNode.appendChild(geometryNode);return placemarkNode;},buildGeometryNode:function(geometry){if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
var className=geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);var builder=this.buildGeometry[type.toLowerCase()];var node=null;if(builder){node=builder.apply(this,[geometry]);}
return node;},buildGeometry:{point:function(geometry){var kml=this.createElementNS(this.kmlns,"Point");kml.appendChild(this.buildCoordinatesNode(geometry));return kml;},multipoint:function(geometry){return this.buildGeometry.collection.apply(this,[geometry]);},linestring:function(geometry){var kml=this.createElementNS(this.kmlns,"LineString");kml.appendChild(this.buildCoordinatesNode(geometry));return kml;},multilinestring:function(geometry){return this.buildGeometry.collection.apply(this,[geometry]);},linearring:function(geometry){var kml=this.createElementNS(this.kmlns,"LinearRing");kml.appendChild(this.buildCoordinatesNode(geometry));return kml;},polygon:function(geometry){var kml=this.createElementNS(this.kmlns,"Polygon");var rings=geometry.components;var ringMember,ringGeom,type;for(var i=0,len=rings.length;i<len;++i){type=(i==0)?"outerBoundaryIs":"innerBoundaryIs";ringMember=this.createElementNS(this.kmlns,type);ringGeom=this.buildGeometry.linearring.apply(this,[rings[i]]);ringMember.appendChild(ringGeom);kml.appendChild(ringMember);}
return kml;},multipolygon:function(geometry){return this.buildGeometry.collection.apply(this,[geometry]);},collection:function(geometry){var kml=this.createElementNS(this.kmlns,"MultiGeometry");var child;for(var i=0,len=geometry.components.length;i<len;++i){child=this.buildGeometryNode.apply(this,[geometry.components[i]]);if(child){kml.appendChild(child);}}
return kml;}},buildCoordinatesNode:function(geometry){var coordinatesNode=this.createElementNS(this.kmlns,"coordinates");var path;var points=geometry.components;if(points){var point;var numPoints=points.length;var parts=new Array(numPoints);for(var i=0;i<numPoints;++i){point=points[i];parts[i]=point.x+","+point.y;}
path=parts.join(" ");}else{path=geometry.x+","+geometry.y;}
var txtNode=this.createTextNode(path);coordinatesNode.appendChild(txtNode);return coordinatesNode;},CLASS_NAME:"OpenLayers.Format.KML"});OpenLayers.Format.OSM=OpenLayers.Class(OpenLayers.Format.XML,{checkTags:false,interestingTagsExclude:null,areaTags:null,initialize:function(options){var layer_defaults={'interestingTagsExclude':['source','source_ref','source:ref','history','attribution','created_by'],'areaTags':['area','building','leisure','tourism','ruins','historic','landuse','military','natural','sport']};layer_defaults=OpenLayers.Util.extend(layer_defaults,options);var interesting={};for(var i=0;i<layer_defaults.interestingTagsExclude.length;i++){interesting[layer_defaults.interestingTagsExclude[i]]=true;}
layer_defaults.interestingTagsExclude=interesting;var area={};for(var i=0;i<layer_defaults.areaTags.length;i++){area[layer_defaults.areaTags[i]]=true;}
layer_defaults.areaTags=area;this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[layer_defaults]);},read:function(doc){if(typeof doc=="string"){doc=OpenLayers.Format.XML.prototype.read.apply(this,[doc]);}
var nodes=this.getNodes(doc);var ways=this.getWays(doc);var feat_list=new Array(ways.length);for(var i=0;i<ways.length;i++){var point_list=new Array(ways[i].nodes.length);var poly=this.isWayArea(ways[i])?1:0;for(var j=0;j<ways[i].nodes.length;j++){var node=nodes[ways[i].nodes[j]];var point=new OpenLayers.Geometry.Point(node.lon,node.lat);point.osm_id=parseInt(ways[i].nodes[j]);point_list[j]=point;node.used=true;}
var geometry=null;if(poly){geometry=new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(point_list));}else{geometry=new OpenLayers.Geometry.LineString(point_list);}
if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}
var feat=new OpenLayers.Feature.Vector(geometry,ways[i].tags);feat.osm_id=parseInt(ways[i].id);feat.fid="way."+feat.osm_id;feat_list[i]=feat;}
for(var node_id in nodes){var node=nodes[node_id];if(!node.used||this.checkTags){var tags=null;if(this.checkTags){var result=this.getTags(node.node,true);if(node.used&&!result[1]){continue;}
tags=result[0];}else{tags=this.getTags(node.node);}
var feat=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(node['lon'],node['lat']),tags);if(this.internalProjection&&this.externalProjection){feat.geometry.transform(this.externalProjection,this.internalProjection);}
feat.osm_id=parseInt(node_id);feat.fid="node."+feat.osm_id;feat_list.push(feat);}
node.node=null;}
return feat_list;},getNodes:function(doc){var node_list=doc.getElementsByTagName("node");var nodes={};for(var i=0;i<node_list.length;i++){var node=node_list[i];var id=node.getAttribute("id");nodes[id]={'lat':node.getAttribute("lat"),'lon':node.getAttribute("lon"),'node':node};}
return nodes;},getWays:function(doc){var way_list=doc.getElementsByTagName("way");var return_ways=[];for(var i=0;i<way_list.length;i++){var way=way_list[i];var way_object={id:way.getAttribute("id")};way_object.tags=this.getTags(way);var node_list=way.getElementsByTagName("nd");way_object.nodes=new Array(node_list.length);for(var j=0;j<node_list.length;j++){way_object.nodes[j]=node_list[j].getAttribute("ref");}
return_ways.push(way_object);}
return return_ways;},getTags:function(dom_node,interesting_tags){var tag_list=dom_node.getElementsByTagName("tag");var tags={};var interesting=false;for(var j=0;j<tag_list.length;j++){var key=tag_list[j].getAttribute("k");tags[key]=tag_list[j].getAttribute("v");if(interesting_tags){if(!this.interestingTagsExclude[key]){interesting=true;}}}
return interesting_tags?[tags,interesting]:tags;},isWayArea:function(way){var poly_shaped=false;var poly_tags=false;if(way.nodes[0]==way.nodes[way.nodes.length-1]){poly_shaped=true;}
if(this.checkTags){for(var key in way.tags){if(this.areaTags[key]){poly_tags=true;break;}}}
return poly_shaped&&(this.checkTags?poly_tags:true);},write:function(features){if(!(features instanceof Array)){features=[features];}
this.osm_id=1;this.created_nodes={};var root_node=this.createElementNS(null,"osm");root_node.setAttribute("version","0.5");root_node.setAttribute("generator","OpenLayers "+OpenLayers.VERSION_NUMBER);for(var i=features.length-1;i>=0;i--){var nodes=this.createFeatureNodes(features[i]);for(var j=0;j<nodes.length;j++){root_node.appendChild(nodes[j]);}}
return OpenLayers.Format.XML.prototype.write.apply(this,[root_node]);},createFeatureNodes:function(feature){var nodes=[];var className=feature.geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);type=type.toLowerCase();var builder=this.createXML[type];if(builder){nodes=builder.apply(this,[feature]);}
return nodes;},createXML:{'point':function(point){var id=null;var geometry=point.geometry?point.geometry:point;var already_exists=false;if(point.osm_id){id=point.osm_id;if(this.created_nodes[id]){already_exists=true;}}else{id=-this.osm_id;this.osm_id++;}
if(already_exists){node=this.created_nodes[id];}else{var node=this.createElementNS(null,"node");}
this.created_nodes[id]=node;node.setAttribute("id",id);node.setAttribute("lon",geometry.x);node.setAttribute("lat",geometry.y);if(point.attributes){this.serializeTags(point,node);}
this.setState(point,node);return already_exists?[]:[node];},linestring:function(feature){var nodes=[];var geometry=feature.geometry;if(feature.osm_id){id=feature.osm_id;}else{id=-this.osm_id;this.osm_id++;}
var way=this.createElementNS(null,"way");way.setAttribute("id",id);for(var i=0;i<geometry.components.length;i++){var node=this.createXML['point'].apply(this,[geometry.components[i]]);if(node.length){node=node[0];var node_ref=node.getAttribute("id");nodes.push(node);}else{node_ref=geometry.components[i].osm_id;node=this.created_nodes[node_ref];}
this.setState(feature,node);var nd_dom=this.createElementNS(null,"nd");nd_dom.setAttribute("ref",node_ref);way.appendChild(nd_dom);}
this.serializeTags(feature,way);nodes.push(way);return nodes;},polygon:function(feature){var attrs=OpenLayers.Util.extend({'area':'yes'},feature.attributes);var feat=new OpenLayers.Feature.Vector(feature.geometry.components[0],attrs);feat.osm_id=feature.osm_id;return this.createXML['linestring'].apply(this,[feat]);}},serializeTags:function(feature,node){for(var key in feature.attributes){var tag=this.createElementNS(null,"tag");tag.setAttribute("k",key);tag.setAttribute("v",feature.attributes[key]);node.appendChild(tag);}},setState:function(feature,node){if(feature.state){var state=null;switch(feature.state){case OpenLayers.State.UPDATE:state="modify";case OpenLayers.State.DELETE:state="delete";}
if(state){node.setAttribute("action",state);}}},CLASS_NAME:"OpenLayers.Format.OSM"});OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],initialize:function(components){OpenLayers.Geometry.Collection.prototype.initialize.apply(this,arguments);},CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Handler.Polygon=OpenLayers.Class(OpenLayers.Handler.Path,{polygon:null,initialize:function(control,callbacks,options){OpenLayers.Handler.Path.prototype.initialize.apply(this,arguments);},createFeature:function(pixel){var lonlat=this.control.map.getLonLatFromPixel(pixel);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat));this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LinearRing([this.point.geometry]));this.polygon=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([this.line.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.polygon,this.point],{silent:true});},destroyFeature:function(){OpenLayers.Handler.Path.prototype.destroyFeature.apply(this);this.polygon=null;},drawFeature:function(){this.layer.drawFeature(this.polygon,this.style);this.layer.drawFeature(this.point,this.style);},getSketch:function(){return this.polygon;},getGeometry:function(){var geometry=this.polygon&&this.polygon.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiPolygon([geometry]);}
return geometry;},dblclick:function(evt){if(!this.freehandMode(evt)){var index=this.line.geometry.components.length-2;this.line.geometry.removeComponent(this.line.geometry.components[index]);this.removePoint();this.finalize();}
return false;},CLASS_NAME:"OpenLayers.Handler.Polygon"});OpenLayers.Control.EditingToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(layer,options){OpenLayers.Control.Panel.prototype.initialize.apply(this,[options]);this.addControls([new OpenLayers.Control.Navigation()]);var controls=[new OpenLayers.Control.DrawFeature(layer,OpenLayers.Handler.Point,{'displayClass':'olControlDrawFeaturePoint'}),new OpenLayers.Control.DrawFeature(layer,OpenLayers.Handler.Path,{'displayClass':'olControlDrawFeaturePath'}),new OpenLayers.Control.DrawFeature(layer,OpenLayers.Handler.Polygon,{'displayClass':'olControlDrawFeaturePolygon'})];this.addControls(controls);},draw:function(){var div=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);this.activateControl(this.controls[0]);return div;},CLASS_NAME:"OpenLayers.Control.EditingToolbar"});OpenLayers.Control.SLDSelect=OpenLayers.Class(OpenLayers.Control,{EVENT_TYPES:["selected"],clearOnDeactivate:false,layers:null,callbacks:null,selectionSymbolizer:{'Polygon':{fillColor:'#FF0000',stroke:false},'Line':{strokeColor:'#FF0000',strokeWidth:2},'Point':{graphicName:'square',fillColor:'#FF0000',pointRadius:5}},layerOptions:null,handlerOptions:null,sketchStyle:null,wfsCache:{},layerCache:{},initialize:function(handler,options){this.EVENT_TYPES=OpenLayers.Control.SLDSelect.prototype.EVENT_TYPES.concat(OpenLayers.Control.prototype.EVENT_TYPES);OpenLayers.Control.prototype.initialize.apply(this,[options]);this.callbacks=OpenLayers.Util.extend({done:this.select,click:this.select},this.callbacks);this.handlerOptions=this.handlerOptions||{};this.layerOptions=OpenLayers.Util.applyDefaults(this.layerOptions,{displayInLayerSwitcher:false});if(this.sketchStyle){this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":this.sketchStyle})});}
this.handler=new handler(this,this.callbacks,this.handlerOptions);},destroy:function(){for(var key in this.layerCache){delete this.layerCache[key];}
for(var key in this.wfsCache){delete this.wfsCache[key];}
OpenLayers.Control.prototype.destroy.apply(this,arguments);},coupleLayerVisiblity:function(evt){this.setVisibility(evt.object.getVisibility());},createSelectionLayer:function(source){var selectionLayer;if(!this.layerCache[source.id]){selectionLayer=new OpenLayers.Layer.WMS.Post(source.name,source.url,source.params,OpenLayers.Util.applyDefaults(this.layerOptions,source.getOptions()));this.layerCache[source.id]=selectionLayer;if(this.layerOptions.displayInLayerSwitcher===false){source.events.on({"visibilitychanged":this.coupleLayerVisiblity,scope:selectionLayer});}
this.map.addLayer(selectionLayer);}else{selectionLayer=this.layerCache[source.id];}
return selectionLayer;},createSLD:function(layer,filters,geometryAttributes){var sld={version:"1.0.0",namedLayers:{}};var layerNames=[layer.params.LAYERS].join(",").split(",");for(var i=0,len=layerNames.length;i<len;i++){var name=layerNames[i];sld.namedLayers[name]={name:name,userStyles:[]};var symbolizer=this.selectionSymbolizer;var geometryAttribute=geometryAttributes[i];if(geometryAttribute.type.indexOf('Polygon')>=0){symbolizer={Polygon:this.selectionSymbolizer['Polygon']};}else if(geometryAttribute.type.indexOf('LineString')>=0){symbolizer={Line:this.selectionSymbolizer['Line']};}else if(geometryAttribute.type.indexOf('Point')>=0){symbolizer={Point:this.selectionSymbolizer['Point']};}
var filter=filters[i];sld.namedLayers[name].userStyles.push({name:'default',rules:[new OpenLayers.Rule({symbolizer:symbolizer,filter:filter,maxScaleDenominator:layer.options.minScale})]});}
return new OpenLayers.Format.SLD().write(sld);},parseDescribeLayer:function(request){var format=new OpenLayers.Format.WMSDescribeLayer();var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
var describeLayer=format.read(doc);var typeNames=[];var url=null;for(var i=0,len=describeLayer.length;i<len;i++){if(describeLayer[i].owsType=="WFS"){typeNames.push(describeLayer[i].typeName);url=describeLayer[i].owsURL;}}
var options={url:url,params:{SERVICE:"WFS",TYPENAME:typeNames.toString(),REQUEST:"DescribeFeatureType",VERSION:"1.0.0"},callback:function(request){var format=new OpenLayers.Format.WFSDescribeFeatureType();var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
var describeFeatureType=format.read(doc);this.control.wfsCache[this.layer.id]=describeFeatureType;this.control._queue&&this.control.applySelection();},scope:this};OpenLayers.Request.GET(options);},getGeometryAttributes:function(layer){var result=[];var cache=this.wfsCache[layer.id];for(var i=0,len=cache.featureTypes.length;i<len;i++){var typeName=cache.featureTypes[i];var properties=typeName.properties;for(var j=0,lenj=properties.length;j<lenj;j++){var property=properties[j];var type=property.type;if((type.indexOf('LineString')>=0)||(type.indexOf('GeometryAssociationType')>=0)||(type.indexOf('GeometryPropertyType')>=0)||(type.indexOf('Point')>=0)||(type.indexOf('Polygon')>=0)){result.push(property);}}}
return result;},activate:function(){var activated=OpenLayers.Control.prototype.activate.call(this);if(activated){for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];if(layer&&!this.wfsCache[layer.id]){var options={url:layer.url,params:{SERVICE:"WMS",VERSION:layer.params.VERSION,LAYERS:layer.params.LAYERS,REQUEST:"DescribeLayer"},callback:this.parseDescribeLayer,scope:{layer:layer,control:this}};OpenLayers.Request.GET(options);}}}
return activated;},deactivate:function(){var deactivated=OpenLayers.Control.prototype.deactivate.call(this);if(deactivated){for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];if(layer&&this.clearOnDeactivate===true){var layerCache=this.layerCache;var selectionLayer=layerCache[layer.id];if(selectionLayer){layer.events.un({"visibilitychanged":this.coupleLayerVisiblity,scope:selectionLayer});selectionLayer.destroy();delete layerCache[layer.id];}}}}
return deactivated;},setLayers:function(layers){if(this.active){this.deactivate();this.layers=layers;this.activate();}else{this.layers=layers;}},createFilter:function(geometryAttribute,geometry){var filter=null;if(this.handler instanceof OpenLayers.Handler.RegularPolygon){if(this.handler.irregular===true){filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:geometryAttribute.name,value:geometry.getBounds()});}else{filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:geometryAttribute.name,value:geometry});}}else if(this.handler instanceof OpenLayers.Handler.Polygon){filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:geometryAttribute.name,value:geometry});}else if(this.handler instanceof OpenLayers.Handler.Path){if(geometryAttribute.type.indexOf('Point')>=0){filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,property:geometryAttribute.name,distance:this.map.getExtent().getWidth()*0.01,distanceUnits:this.map.getUnits(),value:geometry});}else{filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:geometryAttribute.name,value:geometry});}}else if(this.handler instanceof OpenLayers.Handler.Click){if(geometryAttribute.type.indexOf('Polygon')>=0){filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:geometryAttribute.name,value:geometry});}else{filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,property:geometryAttribute.name,distance:this.map.getExtent().getWidth()*0.01,distanceUnits:this.map.getUnits(),value:geometry});}}
return filter;},select:function(geometry){this._queue=function(){for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];var geometryAttributes=this.getGeometryAttributes(layer);var filters=[];for(var j=0,lenj=geometryAttributes.length;j<lenj;j++){var geometryAttribute=geometryAttributes[j];if(geometryAttribute!==null){if(!(geometry instanceof OpenLayers.Geometry)){var point=this.map.getLonLatFromPixel(geometry.xy);geometry=new OpenLayers.Geometry.Point(point.lon,point.lat);}
var filter=this.createFilter(geometryAttribute,geometry);if(filter!==null){filters.push(filter);}}}
var selectionLayer=this.createSelectionLayer(layer);var sld=this.createSLD(layer,filters,geometryAttributes);this.events.triggerEvent("selected",{layer:layer,filters:filters});selectionLayer.mergeNewParams({SLD_BODY:sld});delete this._queue;}};this.applySelection();},applySelection:function(){var canApply=true;for(var i=0,len=this.layers.length;i<len;i++){if(!this.wfsCache[this.layers[i].id]){canApply=false;break;}}
canApply&&this._queue.call(this);},CLASS_NAME:"OpenLayers.Control.SLDSelect"});OpenLayers.Format.ArcXML=OpenLayers.Class(OpenLayers.Format.XML,{fontStyleKeys:['antialiasing','blockout','font','fontcolor','fontsize','fontstyle','glowing','interval','outline','printmode','shadow','transparency'],request:null,response:null,initialize:function(options){this.request=new OpenLayers.Format.ArcXML.Request();this.response=new OpenLayers.Format.ArcXML.Response();if(options){if(options.requesttype=="feature"){this.request.get_image=null;var qry=this.request.get_feature.query;this.addCoordSys(qry.featurecoordsys,options.featureCoordSys);this.addCoordSys(qry.filtercoordsys,options.filterCoordSys);if(options.polygon){qry.isspatial=true;qry.spatialfilter.polygon=options.polygon;}else if(options.envelope){qry.isspatial=true;qry.spatialfilter.envelope={minx:0,miny:0,maxx:0,maxy:0};this.parseEnvelope(qry.spatialfilter.envelope,options.envelope);}}else if(options.requesttype=="image"){this.request.get_feature=null;var props=this.request.get_image.properties;this.parseEnvelope(props.envelope,options.envelope);this.addLayers(props.layerlist,options.layers);this.addImageSize(props.imagesize,options.tileSize);this.addCoordSys(props.featurecoordsys,options.featureCoordSys);this.addCoordSys(props.filtercoordsys,options.filterCoordSys);}else{this.request=null;}}
OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},parseEnvelope:function(env,arr){if(arr&&arr.length==4){env.minx=arr[0];env.miny=arr[1];env.maxx=arr[2];env.maxy=arr[3];}},addLayers:function(ll,lyrs){for(var lind=0,len=lyrs.length;lind<len;lind++){ll.push(lyrs[lind]);}},addImageSize:function(imsize,olsize){if(olsize!==null){imsize.width=olsize.w;imsize.height=olsize.h;imsize.printwidth=olsize.w;imsize.printheight=olsize.h;}},addCoordSys:function(featOrFilt,fsys){if(typeof fsys=="string"){featOrFilt.id=parseInt(fsys);featOrFilt.string=fsys;}
else if(typeof fsys=="object"&&fsys.proj!==null){featOrFilt.id=fsys.proj.srsProjNumber;featOrFilt.string=fsys.proj.srsCode;}else{featOrFilt=fsys;}},iserror:function(data){var ret=null;if(!data){ret=(this.response.error!=='');}else{data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);var errorNodes=data.documentElement.getElementsByTagName("ERROR");ret=(errorNodes!==null&&errorNodes.length>0);}
return ret;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var arcNode=null;if(data&&data.documentElement){if(data.documentElement.nodeName=="ARCXML"){arcNode=data.documentElement;}else{arcNode=data.documentElement.getElementsByTagName("ARCXML")[0];}}
if(!arcNode||arcNode.firstChild.nodeName==='parsererror'){var error,source;try{error=data.firstChild.nodeValue;source=data.firstChild.childNodes[1].firstChild.nodeValue;}catch(err){}
throw{message:"Error parsing the ArcXML request",error:error,source:source};}
var response=this.parseResponse(arcNode);return response;},write:function(request){if(!request){request=this.request;}
var root=this.createElementNS("","ARCXML");root.setAttribute("version","1.1");var reqElem=this.createElementNS("","REQUEST");if(request.get_image!=null){var getElem=this.createElementNS("","GET_IMAGE");reqElem.appendChild(getElem);var propElem=this.createElementNS("","PROPERTIES");getElem.appendChild(propElem);var props=request.get_image.properties;if(props.featurecoordsys!=null){var feat=this.createElementNS("","FEATURECOORDSYS");propElem.appendChild(feat);if(props.featurecoordsys.id===0){feat.setAttribute("string",props.featurecoordsys['string']);}
else{feat.setAttribute("id",props.featurecoordsys.id);}}
if(props.filtercoordsys!=null){var filt=this.createElementNS("","FILTERCOORDSYS");propElem.appendChild(filt);if(props.filtercoordsys.id===0){filt.setAttribute("string",props.filtercoordsys.string);}
else{filt.setAttribute("id",props.filtercoordsys.id);}}
if(props.envelope!=null){var env=this.createElementNS("","ENVELOPE");propElem.appendChild(env);env.setAttribute("minx",props.envelope.minx);env.setAttribute("miny",props.envelope.miny);env.setAttribute("maxx",props.envelope.maxx);env.setAttribute("maxy",props.envelope.maxy);}
var imagesz=this.createElementNS("","IMAGESIZE");propElem.appendChild(imagesz);imagesz.setAttribute("height",props.imagesize.height);imagesz.setAttribute("width",props.imagesize.width);if(props.imagesize.height!=props.imagesize.printheight||props.imagesize.width!=props.imagesize.printwidth){imagesz.setAttribute("printheight",props.imagesize.printheight);imagesz.setArrtibute("printwidth",props.imagesize.printwidth);}
if(props.background!=null){var backgrnd=this.createElementNS("","BACKGROUND");propElem.appendChild(backgrnd);backgrnd.setAttribute("color",props.background.color.r+","+
props.background.color.g+","+
props.background.color.b);if(props.background.transcolor!==null){backgrnd.setAttribute("transcolor",props.background.transcolor.r+","+
props.background.transcolor.g+","+
props.background.transcolor.b);}}
if(props.layerlist!=null&&props.layerlist.length>0){var layerlst=this.createElementNS("","LAYERLIST");propElem.appendChild(layerlst);for(var ld=0;ld<props.layerlist.length;ld++){var ldef=this.createElementNS("","LAYERDEF");layerlst.appendChild(ldef);ldef.setAttribute("id",props.layerlist[ld].id);ldef.setAttribute("visible",props.layerlist[ld].visible);if(typeof props.layerlist[ld].query=="object"){var query=props.layerlist[ld].query;if(query.where.length<0){continue;}
var queryElem=null;if(typeof query.spatialfilter=="boolean"&&query.spatialfilter){queryElem=this.createElementNS("","SPATIALQUERY");}
else{queryElem=this.createElementNS("","QUERY");}
queryElem.setAttribute("where",query.where);if(typeof query.accuracy=="number"&&query.accuracy>0){queryElem.setAttribute("accuracy",query.accuracy);}
if(typeof query.featurelimit=="number"&&query.featurelimit<2000){queryElem.setAttribute("featurelimit",query.featurelimit);}
if(typeof query.subfields=="string"&&query.subfields!="#ALL#"){queryElem.setAttribute("subfields",query.subfields);}
if(typeof query.joinexpression=="string"&&query.joinexpression.length>0){queryElem.setAttribute("joinexpression",query.joinexpression);}
if(typeof query.jointables=="string"&&query.jointables.length>0){queryElem.setAttribute("jointables",query.jointables);}
ldef.appendChild(queryElem);}
if(typeof props.layerlist[ld].renderer=="object"){this.addRenderer(ldef,props.layerlist[ld].renderer);}}}}else if(request.get_feature!=null){var getElem=this.createElementNS("","GET_FEATURES");getElem.setAttribute("outputmode","newxml");getElem.setAttribute("checkesc","true");if(request.get_feature.geometry){getElem.setAttribute("geometry",request.get_feature.geometry);}
else{getElem.setAttribute("geometry","false");}
if(request.get_feature.compact){getElem.setAttribute("compact",request.get_feature.compact);}
if(request.get_feature.featurelimit=="number"){getElem.setAttribute("featurelimit",request.get_feature.featurelimit);}
getElem.setAttribute("globalenvelope","true");reqElem.appendChild(getElem);if(request.get_feature.layer!=null&&request.get_feature.layer.length>0){var lyrElem=this.createElementNS("","LAYER");lyrElem.setAttribute("id",request.get_feature.layer);getElem.appendChild(lyrElem);}
var fquery=request.get_feature.query;if(fquery!=null){var qElem=null;if(fquery.isspatial){qElem=this.createElementNS("","SPATIALQUERY");}else{qElem=this.createElementNS("","QUERY");}
getElem.appendChild(qElem);if(typeof fquery.accuracy=="number"){qElem.setAttribute("accuracy",fquery.accuracy);}
if(fquery.featurecoordsys!=null){var fcsElem1=this.createElementNS("","FEATURECOORDSYS");if(fquery.featurecoordsys.id==0){fcsElem1.setAttribute("string",fquery.featurecoordsys.string);}else{fcsElem1.setAttribute("id",fquery.featurecoordsys.id);}
qElem.appendChild(fcsElem1);}
if(fquery.filtercoordsys!=null){var fcsElem2=this.createElementNS("","FILTERCOORDSYS");if(fquery.filtercoordsys.id===0){fcsElem2.setAttribute("string",fquery.filtercoordsys.string);}else{fcsElem2.setAttribute("id",fquery.filtercoordsys.id);}
qElem.appendChild(fcsElem2);}
if(fquery.buffer>0){var bufElem=this.createElementNS("","BUFFER");bufElem.setAttribute("distance",fquery.buffer);qElem.appendChild(bufElem);}
if(fquery.isspatial){var spfElem=this.createElementNS("","SPATIALFILTER");spfElem.setAttribute("relation",fquery.spatialfilter.relation);qElem.appendChild(spfElem);if(fquery.spatialfilter.envelope){var envElem=this.createElementNS("","ENVELOPE");envElem.setAttribute("minx",fquery.spatialfilter.envelope.minx);envElem.setAttribute("miny",fquery.spatialfilter.envelope.miny);envElem.setAttribute("maxx",fquery.spatialfilter.envelope.maxx);envElem.setAttribute("maxy",fquery.spatialfilter.envelope.maxy);spfElem.appendChild(envElem);}else if(typeof fquery.spatialfilter.polygon=="object"){spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon));}}
if(fquery.where!=null&&fquery.where.length>0){qElem.setAttribute("where",fquery.where);}}}
root.appendChild(reqElem);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},addGroupRenderer:function(ldef,toprenderer){var topRelem=this.createElementNS("","GROUPRENDERER");ldef.appendChild(topRelem);for(var rind=0;rind<toprenderer.length;rind++){var renderer=toprenderer[rind];this.addRenderer(topRelem,renderer);}},addRenderer:function(topRelem,renderer){if(renderer instanceof Array){this.addGroupRenderer(topRelem,renderer);}else{var renderElem=this.createElementNS("",renderer.type.toUpperCase()+"RENDERER");topRelem.appendChild(renderElem);if(renderElem.tagName=="VALUEMAPRENDERER"){this.addValueMapRenderer(renderElem,renderer);}else if(renderElem.tagName=="VALUEMAPLABELRENDERER"){this.addValueMapLabelRenderer(renderElem,renderer);}else if(renderElem.tagName=="SIMPLELABELRENDERER"){this.addSimpleLabelRenderer(renderElem,renderer);}else if(renderElem.tagName=="SCALEDEPENDENTRENDERER"){this.addScaleDependentRenderer(renderElem,renderer);}}},addScaleDependentRenderer:function(renderElem,renderer){if(typeof renderer.lower=="string"||typeof renderer.lower=="number"){renderElem.setAttribute("lower",renderer.lower);}
if(typeof renderer.upper=="string"||typeof renderer.upper=="number"){renderElem.setAttribute("upper",renderer.upper);}
this.addRenderer(renderElem,renderer.renderer);},addValueMapLabelRenderer:function(renderElem,renderer){renderElem.setAttribute("lookupfield",renderer.lookupfield);renderElem.setAttribute("labelfield",renderer.labelfield);if(typeof renderer.exacts=="object"){for(var ext=0,extlen=renderer.exacts.length;ext<extlen;ext++){var exact=renderer.exacts[ext];var eelem=this.createElementNS("","EXACT");if(typeof exact.value=="string"){eelem.setAttribute("value",exact.value);}
if(typeof exact.label=="string"){eelem.setAttribute("label",exact.label);}
if(typeof exact.method=="string"){eelem.setAttribute("method",exact.method);}
renderElem.appendChild(eelem);if(typeof exact.symbol=="object"){var selem=null;if(exact.symbol.type=="text"){selem=this.createElementNS("","TEXTSYMBOL");}
if(selem!=null){var keys=this.fontStyleKeys;for(var i=0,len=keys.length;i<len;i++){var key=keys[i];if(exact.symbol[key]){selem.setAttribute(key,exact.symbol[key]);}}
eelem.appendChild(selem);}}}}},addValueMapRenderer:function(renderElem,renderer){renderElem.setAttribute("lookupfield",renderer.lookupfield);if(typeof renderer.ranges=="object"){for(var rng=0,rnglen=renderer.ranges.length;rng<rnglen;rng++){var range=renderer.ranges[rng];var relem=this.createElementNS("","RANGE");relem.setAttribute("lower",range.lower);relem.setAttribute("upper",range.upper);renderElem.appendChild(relem);if(typeof range.symbol=="object"){var selem=null;if(range.symbol.type=="simplepolygon"){selem=this.createElementNS("","SIMPLEPOLYGONSYMBOL");}
if(selem!=null){if(typeof range.symbol.boundarycolor=="string"){selem.setAttribute("boundarycolor",range.symbol.boundarycolor);}
if(typeof range.symbol.fillcolor=="string"){selem.setAttribute("fillcolor",range.symbol.fillcolor);}
if(typeof range.symbol.filltransparency=="number"){selem.setAttribute("filltransparency",range.symbol.filltransparency);}
relem.appendChild(selem);}}}}else if(typeof renderer.exacts=="object"){for(var ext=0,extlen=renderer.exacts.length;ext<extlen;ext++){var exact=renderer.exacts[ext];var eelem=this.createElementNS("","EXACT");if(typeof exact.value=="string"){eelem.setAttribute("value",exact.value);}
if(typeof exact.label=="string"){eelem.setAttribute("label",exact.label);}
if(typeof exact.method=="string"){eelem.setAttribute("method",exact.method);}
renderElem.appendChild(eelem);if(typeof exact.symbol=="object"){var selem=null;if(exact.symbol.type=="simplemarker"){selem=this.createElementNS("","SIMPLEMARKERSYMBOL");}
if(selem!=null){if(typeof exact.symbol.antialiasing=="string"){selem.setAttribute("antialiasing",exact.symbol.antialiasing);}
if(typeof exact.symbol.color=="string"){selem.setAttribute("color",exact.symbol.color);}
if(typeof exact.symbol.outline=="string"){selem.setAttribute("outline",exact.symbol.outline);}
if(typeof exact.symbol.overlap=="string"){selem.setAttribute("overlap",exact.symbol.overlap);}
if(typeof exact.symbol.shadow=="string"){selem.setAttribute("shadow",exact.symbol.shadow);}
if(typeof exact.symbol.transparency=="number"){selem.setAttribute("transparency",exact.symbol.transparency);}
if(typeof exact.symbol.usecentroid=="string"){selem.setAttribute("usecentroid",exact.symbol.usecentroid);}
if(typeof exact.symbol.width=="number"){selem.setAttribute("width",exact.symbol.width);}
eelem.appendChild(selem);}}}}},addSimpleLabelRenderer:function(renderElem,renderer){renderElem.setAttribute("field",renderer.field);var keys=['featureweight','howmanylabels','labelbufferratio','labelpriorities','labelweight','linelabelposition','rotationalangles'];for(var i=0,len=keys.length;i<len;i++){var key=keys[i];if(renderer[key]){renderElem.setAttribute(key,renderer[key]);}}
if(renderer.symbol.type=="text"){var symbol=renderer.symbol;var selem=this.createElementNS("","TEXTSYMBOL");renderElem.appendChild(selem);var keys=this.fontStyleKeys;for(var i=0,len=keys.length;i<len;i++){var key=keys[i];if(symbol[key]){selem.setAttribute(key,renderer[key]);}}}},writePolygonGeometry:function(polygon){if(!(polygon instanceof OpenLayers.Geometry.Polygon)){throw{message:'Cannot write polygon geometry to ArcXML with an '+
polygon.CLASS_NAME+' object.',geometry:polygon};}
var polyElem=this.createElementNS("","POLYGON");for(var ln=0,lnlen=polygon.components.length;ln<lnlen;ln++){var ring=polygon.components[ln];var ringElem=this.createElementNS("","RING");for(var rn=0,rnlen=ring.components.length;rn<rnlen;rn++){var point=ring.components[rn];var pointElem=this.createElementNS("","POINT");pointElem.setAttribute("x",point.x);pointElem.setAttribute("y",point.y);ringElem.appendChild(pointElem);}
polyElem.appendChild(ringElem);}
return polyElem;},parseResponse:function(data){if(typeof data=="string"){var newData=new OpenLayers.Format.XML();data=newData.read(data);}
var response=new OpenLayers.Format.ArcXML.Response();var errorNode=data.getElementsByTagName("ERROR");if(errorNode!=null&&errorNode.length>0){response.error=this.getChildValue(errorNode,"Unknown error.");}else{var responseNode=data.getElementsByTagName("RESPONSE");if(responseNode==null||responseNode.length==0){response.error="No RESPONSE tag found in ArcXML response.";return response;}
var rtype=responseNode[0].firstChild.nodeName;if(rtype=="#text"){rtype=responseNode[0].firstChild.nextSibling.nodeName;}
if(rtype=="IMAGE"){var envelopeNode=data.getElementsByTagName("ENVELOPE");var outputNode=data.getElementsByTagName("OUTPUT");if(envelopeNode==null||envelopeNode.length==0){response.error="No ENVELOPE tag found in ArcXML response.";}else if(outputNode==null||outputNode.length==0){response.error="No OUTPUT tag found in ArcXML response.";}else{var envAttr=this.parseAttributes(envelopeNode[0]);var outputAttr=this.parseAttributes(outputNode[0]);if(typeof outputAttr.type=="string"){response.image={envelope:envAttr,output:{type:outputAttr.type,data:this.getChildValue(outputNode[0])}};}else{response.image={envelope:envAttr,output:outputAttr};}}}else if(rtype=="FEATURES"){var features=responseNode[0].getElementsByTagName("FEATURES");var featureCount=features[0].getElementsByTagName("FEATURECOUNT");response.features.featurecount=featureCount[0].getAttribute("count");if(response.features.featurecount>0){var envelope=features[0].getElementsByTagName("ENVELOPE");response.features.envelope=this.parseAttributes(envelope[0],typeof(0));var featureList=features[0].getElementsByTagName("FEATURE");for(var fn=0;fn<featureList.length;fn++){var feature=new OpenLayers.Feature.Vector();var fields=featureList[fn].getElementsByTagName("FIELD");for(var fdn=0;fdn<fields.length;fdn++){var fieldName=fields[fdn].getAttribute("name");var fieldValue=fields[fdn].getAttribute("value");feature.attributes[fieldName]=fieldValue;}
var geom=featureList[fn].getElementsByTagName("POLYGON");if(geom.length>0){var ring=geom[0].getElementsByTagName("RING");var polys=[];for(var rn=0;rn<ring.length;rn++){var linearRings=[];linearRings.push(this.parsePointGeometry(ring[rn]));var holes=ring[rn].getElementsByTagName("HOLE");for(var hn=0;hn<holes.length;hn++){linearRings.push(this.parsePointGeometry(holes[hn]));}
holes=null;polys.push(new OpenLayers.Geometry.Polygon(linearRings));linearRings=null;}
ring=null;if(polys.length==1){feature.geometry=polys[0];}else
{feature.geometry=new OpenLayers.Geometry.MultiPolygon(polys);}}
response.features.feature.push(feature);}}}else{response.error="Unidentified response type.";}}
return response;},parseAttributes:function(node,type){var attributes={};for(var attr=0;attr<node.attributes.length;attr++){if(type=="number"){attributes[node.attributes[attr].nodeName]=parseFloat(node.attributes[attr].nodeValue);}else{attributes[node.attributes[attr].nodeName]=node.attributes[attr].nodeValue;}}
return attributes;},parsePointGeometry:function(node){var ringPoints=[];var coords=node.getElementsByTagName("COORDS");if(coords.length>0){var coordArr=this.getChildValue(coords[0]);coordArr=coordArr.split(/;/);for(var cn=0;cn<coordArr.length;cn++){var coordItems=coordArr[cn].split(/ /);ringPoints.push(new OpenLayers.Geometry.Point(parseFloat(coordItems[0]),parseFloat(coordItems[1])));}
coords=null;}else{var point=node.getElementsByTagName("POINT");if(point.length>0){for(var pn=0;pn<point.length;pn++){ringPoints.push(new OpenLayers.Geometry.Point(parseFloat(point[pn].getAttribute("x")),parseFloat(point[pn].getAttribute("y"))));}}
point=null;}
return new OpenLayers.Geometry.LinearRing(ringPoints);},CLASS_NAME:"OpenLayers.Format.ArcXML"});OpenLayers.Format.ArcXML.Request=OpenLayers.Class({initialize:function(params){var defaults={get_image:{properties:{background:null,draw:true,envelope:{minx:0,miny:0,maxx:0,maxy:0},featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},imagesize:{height:0,width:0,dpi:96,printheight:0,printwidth:0,scalesymbols:false},layerlist:[],output:{baseurl:"",legendbaseurl:"",legendname:"",legendpath:"",legendurl:"",name:"",path:"",type:"jpg",url:""}}},get_feature:{layer:"",query:{isspatial:false,featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},buffer:0,where:"",spatialfilter:{relation:"envelope_intersection",envelope:null}}},environment:{separators:{cs:" ",ts:";"}},layer:[],workspaces:[]};return OpenLayers.Util.extend(this,defaults);},CLASS_NAME:"OpenLayers.Format.ArcXML.Request"});OpenLayers.Format.ArcXML.Response=OpenLayers.Class({initialize:function(params){var defaults={image:{envelope:null,output:''},features:{featurecount:0,envelope:null,feature:[]},error:''};return OpenLayers.Util.extend(this,defaults);},CLASS_NAME:"OpenLayers.Format.ArcXML.Response"});OpenLayers.Format.GML=OpenLayers.Class(OpenLayers.Format.XML,{featureNS:"http://mapserver.gis.umn.edu/mapserver",featurePrefix:"feature",featureName:"featureMember",layerName:"features",geometryName:"geometry",collectionName:"FeatureCollection",gmlns:"http://www.opengis.net/gml",extractAttributes:true,xy:true,initialize:function(options){this.regExes={trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)};OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
var featureNodes=this.getElementsByTagNameNS(data.documentElement,this.gmlns,this.featureName);var features=[];for(var i=0;i<featureNodes.length;i++){var feature=this.parseFeature(featureNodes[i]);if(feature){features.push(feature);}}
return features;},parseFeature:function(node){var order=["MultiPolygon","Polygon","MultiLineString","LineString","MultiPoint","Point","Envelope"];var type,nodeList,geometry,parser;for(var i=0;i<order.length;++i){type=order[i];nodeList=this.getElementsByTagNameNS(node,this.gmlns,type);if(nodeList.length>0){parser=this.parseGeometry[type.toLowerCase()];if(parser){geometry=parser.apply(this,[nodeList[0]]);if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}}else{OpenLayers.Console.error(OpenLayers.i18n("unsupportedGeometryType",{'geomType':type}));}
break;}}
var bounds;var boxNodes=this.getElementsByTagNameNS(node,this.gmlns,"Box");for(i=0;i<boxNodes.length;++i){var boxNode=boxNodes[i];var box=this.parseGeometry["box"].apply(this,[boxNode]);var parentNode=boxNode.parentNode;var parentName=parentNode.localName||parentNode.nodeName.split(":").pop();if(parentName==="boundedBy"){bounds=box;}else{geometry=box.toGeometry();}}
var attributes;if(this.extractAttributes){attributes=this.parseAttributes(node);}
var feature=new OpenLayers.Feature.Vector(geometry,attributes);feature.bounds=bounds;feature.gml={featureType:node.firstChild.nodeName.split(":")[1],featureNS:node.firstChild.namespaceURI,featureNSPrefix:node.firstChild.prefix};var childNode=node.firstChild;var fid;while(childNode){if(childNode.nodeType==1){fid=childNode.getAttribute("fid")||childNode.getAttribute("id");if(fid){break;}}
childNode=childNode.nextSibling;}
feature.fid=fid;return feature;},parseGeometry:{point:function(node){var nodeList,coordString;var coords=[];var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"pos");if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);}
if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.removeSpace,"");coords=coordString.split(",");}}
if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coord");if(nodeList.length>0){var xList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"X");var yList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"Y");if(xList.length>0&&yList.length>0){coords=[xList[0].firstChild.nodeValue,yList[0].firstChild.nodeValue];}}}
if(coords.length==2){coords[2]=null;}
if(this.xy){return new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}
else{return new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}},multipoint:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"Point");var components=[];if(nodeList.length>0){var point;for(var i=0;i<nodeList.length;++i){point=this.parseGeometry.point.apply(this,[nodeList[i]]);if(point){components.push(point);}}}
return new OpenLayers.Geometry.MultiPoint(components);},linestring:function(node,ring){var nodeList,coordString;var coords=[];var points=[];nodeList=this.getElementsByTagNameNS(node,this.gmlns,"posList");if(nodeList.length>0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);var dim=parseInt(nodeList[0].getAttribute("dimension"));var j,x,y,z;for(var i=0;i<coords.length/dim;++i){j=i*dim;x=coords[j];y=coords[j+1];z=(dim==2)?null:coords[j+2];if(this.xy){points.push(new OpenLayers.Geometry.Point(x,y,z));}else{points.push(new OpenLayers.Geometry.Point(y,x,z));}}}
if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");if(nodeList.length>0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coordString=coordString.replace(this.regExes.trimComma,",");var pointList=coordString.split(this.regExes.splitSpace);for(var i=0;i<pointList.length;++i){coords=pointList[i].split(",");if(coords.length==2){coords[2]=null;}
if(this.xy){points.push(new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]));}else{points.push(new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]));}}}}
var line=null;if(points.length!=0){if(ring){line=new OpenLayers.Geometry.LinearRing(points);}else{line=new OpenLayers.Geometry.LineString(points);}}
return line;},multilinestring:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"LineString");var components=[];if(nodeList.length>0){var line;for(var i=0;i<nodeList.length;++i){line=this.parseGeometry.linestring.apply(this,[nodeList[i]]);if(line){components.push(line);}}}
return new OpenLayers.Geometry.MultiLineString(components);},polygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"LinearRing");var components=[];if(nodeList.length>0){var ring;for(var i=0;i<nodeList.length;++i){ring=this.parseGeometry.linestring.apply(this,[nodeList[i],true]);if(ring){components.push(ring);}}}
return new OpenLayers.Geometry.Polygon(components);},multipolygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"Polygon");var components=[];if(nodeList.length>0){var polygon;for(var i=0;i<nodeList.length;++i){polygon=this.parseGeometry.polygon.apply(this,[nodeList[i]]);if(polygon){components.push(polygon);}}}
return new OpenLayers.Geometry.MultiPolygon(components);},envelope:function(node){var components=[];var coordString;var envelope;var lpoint=this.getElementsByTagNameNS(node,this.gmlns,"lowerCorner");if(lpoint.length>0){var coords=[];if(lpoint.length>0){coordString=lpoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);}
if(coords.length==2){coords[2]=null;}
if(this.xy){var lowerPoint=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{var lowerPoint=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}}
var upoint=this.getElementsByTagNameNS(node,this.gmlns,"upperCorner");if(upoint.length>0){var coords=[];if(upoint.length>0){coordString=upoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);}
if(coords.length==2){coords[2]=null;}
if(this.xy){var upperPoint=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{var upperPoint=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}}
if(lowerPoint&&upperPoint){components.push(new OpenLayers.Geometry.Point(lowerPoint.x,lowerPoint.y));components.push(new OpenLayers.Geometry.Point(upperPoint.x,lowerPoint.y));components.push(new OpenLayers.Geometry.Point(upperPoint.x,upperPoint.y));components.push(new OpenLayers.Geometry.Point(lowerPoint.x,upperPoint.y));components.push(new OpenLayers.Geometry.Point(lowerPoint.x,lowerPoint.y));var ring=new OpenLayers.Geometry.LinearRing(components);envelope=new OpenLayers.Geometry.Polygon([ring]);}
return envelope;},box:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");var coordString;var coords,beginPoint=null,endPoint=null;if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coords=coordString.split(" ");if(coords.length==2){beginPoint=coords[0].split(",");endPoint=coords[1].split(",");}}
if(beginPoint!==null&&endPoint!==null){return new OpenLayers.Bounds(parseFloat(beginPoint[0]),parseFloat(beginPoint[1]),parseFloat(endPoint[0]),parseFloat(endPoint[1]));}}},parseAttributes:function(node){var attributes={};var childNode=node.firstChild;var children,i,child,grandchildren,grandchild,name,value;while(childNode){if(childNode.nodeType==1){children=childNode.childNodes;for(i=0;i<children.length;++i){child=children[i];if(child.nodeType==1){grandchildren=child.childNodes;if(grandchildren.length==1){grandchild=grandchildren[0];if(grandchild.nodeType==3||grandchild.nodeType==4){name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;value=grandchild.nodeValue.replace(this.regExes.trimSpace,"");attributes[name]=value;}}else{attributes[child.nodeName.split(":").pop()]=null;}}}
break;}
childNode=childNode.nextSibling;}
return attributes;},write:function(features){if(!(features instanceof Array)){features=[features];}
var gml=this.createElementNS("http://www.opengis.net/wfs","wfs:"+this.collectionName);for(var i=0;i<features.length;i++){gml.appendChild(this.createFeatureXML(features[i]));}
return OpenLayers.Format.XML.prototype.write.apply(this,[gml]);},createFeatureXML:function(feature){var geometry=feature.geometry;var geometryNode=this.buildGeometryNode(geometry);var geomContainer=this.createElementNS(this.featureNS,this.featurePrefix+":"+
this.geometryName);geomContainer.appendChild(geometryNode);var featureNode=this.createElementNS(this.gmlns,"gml:"+this.featureName);var featureContainer=this.createElementNS(this.featureNS,this.featurePrefix+":"+
this.layerName);var fid=feature.fid||feature.id;featureContainer.setAttribute("fid",fid);featureContainer.appendChild(geomContainer);for(var attr in feature.attributes){var attrText=this.createTextNode(feature.attributes[attr]);var nodename=attr.substring(attr.lastIndexOf(":")+1);var attrContainer=this.createElementNS(this.featureNS,this.featurePrefix+":"+
nodename);attrContainer.appendChild(attrText);featureContainer.appendChild(attrContainer);}
featureNode.appendChild(featureContainer);return featureNode;},buildGeometryNode:function(geometry){if(this.externalProjection&&this.internalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
var className=geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);var builder=this.buildGeometry[type.toLowerCase()];return builder.apply(this,[geometry]);},buildGeometry:{point:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:Point");gml.appendChild(this.buildCoordinatesNode(geometry));return gml;},multipoint:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:MultiPoint");var points=geometry.components;var pointMember,pointGeom;for(var i=0;i<points.length;i++){pointMember=this.createElementNS(this.gmlns,"gml:pointMember");pointGeom=this.buildGeometry.point.apply(this,[points[i]]);pointMember.appendChild(pointGeom);gml.appendChild(pointMember);}
return gml;},linestring:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:LineString");gml.appendChild(this.buildCoordinatesNode(geometry));return gml;},multilinestring:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:MultiLineString");var lines=geometry.components;var lineMember,lineGeom;for(var i=0;i<lines.length;++i){lineMember=this.createElementNS(this.gmlns,"gml:lineStringMember");lineGeom=this.buildGeometry.linestring.apply(this,[lines[i]]);lineMember.appendChild(lineGeom);gml.appendChild(lineMember);}
return gml;},linearring:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:LinearRing");gml.appendChild(this.buildCoordinatesNode(geometry));return gml;},polygon:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:Polygon");var rings=geometry.components;var ringMember,ringGeom,type;for(var i=0;i<rings.length;++i){type=(i==0)?"outerBoundaryIs":"innerBoundaryIs";ringMember=this.createElementNS(this.gmlns,"gml:"+type);ringGeom=this.buildGeometry.linearring.apply(this,[rings[i]]);ringMember.appendChild(ringGeom);gml.appendChild(ringMember);}
return gml;},multipolygon:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:MultiPolygon");var polys=geometry.components;var polyMember,polyGeom;for(var i=0;i<polys.length;++i){polyMember=this.createElementNS(this.gmlns,"gml:polygonMember");polyGeom=this.buildGeometry.polygon.apply(this,[polys[i]]);polyMember.appendChild(polyGeom);gml.appendChild(polyMember);}
return gml;},bounds:function(bounds){var gml=this.createElementNS(this.gmlns,"gml:Box");gml.appendChild(this.buildCoordinatesNode(bounds));return gml;}},buildCoordinatesNode:function(geometry){var coordinatesNode=this.createElementNS(this.gmlns,"gml:coordinates");coordinatesNode.setAttribute("decimal",".");coordinatesNode.setAttribute("cs",",");coordinatesNode.setAttribute("ts"," ");var parts=[];if(geometry instanceof OpenLayers.Bounds){parts.push(geometry.left+","+geometry.bottom);parts.push(geometry.right+","+geometry.top);}else{var points=(geometry.components)?geometry.components:[geometry];for(var i=0;i<points.length;i++){parts.push(points[i].x+","+points[i].y);}}
var txtNode=this.createTextNode(parts.join(" "));coordinatesNode.appendChild(txtNode);return coordinatesNode;},CLASS_NAME:"OpenLayers.Format.GML"});OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:false,initialize:function(options){OpenLayers.Format.JSON.prototype.initialize.apply(this,[options]);},read:function(json,type,filter){type=(type)?type:"FeatureCollection";var results=null;var obj=null;if(typeof json=="string"){obj=OpenLayers.Format.JSON.prototype.read.apply(this,[json,filter]);}else{obj=json;}
if(!obj){OpenLayers.Console.error("Bad JSON: "+json);}else if(typeof(obj.type)!="string"){OpenLayers.Console.error("Bad GeoJSON - no type: "+json);}else if(this.isValidType(obj,type)){switch(type){case"Geometry":try{results=this.parseGeometry(obj);}catch(err){OpenLayers.Console.error(err);}
break;case"Feature":try{results=this.parseFeature(obj);results.type="Feature";}catch(err){OpenLayers.Console.error(err);}
break;case"FeatureCollection":results=[];switch(obj.type){case"Feature":try{results.push(this.parseFeature(obj));}catch(err){results=null;OpenLayers.Console.error(err);}
break;case"FeatureCollection":for(var i=0,len=obj.features.length;i<len;++i){try{results.push(this.parseFeature(obj.features[i]));}catch(err){results=null;OpenLayers.Console.error(err);}}
break;default:try{var geom=this.parseGeometry(obj);results.push(new OpenLayers.Feature.Vector(geom));}catch(err){results=null;OpenLayers.Console.error(err);}}
break;}}
return results;},isValidType:function(obj,type){var valid=false;switch(type){case"Geometry":if(OpenLayers.Util.indexOf(["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon","Box","GeometryCollection"],obj.type)==-1){OpenLayers.Console.error("Unsupported geometry type: "+
obj.type);}else{valid=true;}
break;case"FeatureCollection":valid=true;break;default:if(obj.type==type){valid=true;}else{OpenLayers.Console.error("Cannot convert types from "+
obj.type+" to "+type);}}
return valid;},parseFeature:function(obj){var feature,geometry,attributes,bbox;attributes=(obj.properties)?obj.properties:{};bbox=(obj.geometry&&obj.geometry.bbox)||obj.bbox;try{geometry=this.parseGeometry(obj.geometry);}catch(err){throw err;}
feature=new OpenLayers.Feature.Vector(geometry,attributes);if(bbox){feature.bounds=OpenLayers.Bounds.fromArray(bbox);}
if(obj.id){feature.fid=obj.id;}
return feature;},parseGeometry:function(obj){if(obj==null){return null;}
var geometry,collection=false;if(obj.type=="GeometryCollection"){if(!(obj.geometries instanceof Array)){throw"GeometryCollection must have geometries array: "+obj;}
var numGeom=obj.geometries.length;var components=new Array(numGeom);for(var i=0;i<numGeom;++i){components[i]=this.parseGeometry.apply(this,[obj.geometries[i]]);}
geometry=new OpenLayers.Geometry.Collection(components);collection=true;}else{if(!(obj.coordinates instanceof Array)){throw"Geometry must have coordinates array: "+obj;}
if(!this.parseCoords[obj.type.toLowerCase()]){throw"Unsupported geometry type: "+obj.type;}
try{geometry=this.parseCoords[obj.type.toLowerCase()].apply(this,[obj.coordinates]);}catch(err){throw err;}}
if(this.internalProjection&&this.externalProjection&&!collection){geometry.transform(this.externalProjection,this.internalProjection);}
return geometry;},parseCoords:{"point":function(array){if(this.ignoreExtraDims==false&&array.length!=2){throw"Only 2D points are supported: "+array;}
return new OpenLayers.Geometry.Point(array[0],array[1]);},"multipoint":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
points.push(p);}
return new OpenLayers.Geometry.MultiPoint(points);},"linestring":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
points.push(p);}
return new OpenLayers.Geometry.LineString(points);},"multilinestring":function(array){var lines=[];var l=null;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
lines.push(l);}
return new OpenLayers.Geometry.MultiLineString(lines);},"polygon":function(array){var rings=[];var r,l;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
r=new OpenLayers.Geometry.LinearRing(l.components);rings.push(r);}
return new OpenLayers.Geometry.Polygon(rings);},"multipolygon":function(array){var polys=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["polygon"].apply(this,[array[i]]);}catch(err){throw err;}
polys.push(p);}
return new OpenLayers.Geometry.MultiPolygon(polys);},"box":function(array){if(array.length!=2){throw"GeoJSON box coordinates must have 2 elements";}
return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(array[0][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[0][1])])]);}},write:function(obj,pretty){var geojson={"type":null};if(obj instanceof Array){geojson.type="FeatureCollection";var numFeatures=obj.length;geojson.features=new Array(numFeatures);for(var i=0;i<numFeatures;++i){var element=obj[i];if(!element instanceof OpenLayers.Feature.Vector){var msg="FeatureCollection only supports collections "+"of features: "+element;throw msg;}
geojson.features[i]=this.extract.feature.apply(this,[element]);}}else if(obj.CLASS_NAME.indexOf("OpenLayers.Geometry")==0){geojson=this.extract.geometry.apply(this,[obj]);}else if(obj instanceof OpenLayers.Feature.Vector){geojson=this.extract.feature.apply(this,[obj]);if(obj.layer&&obj.layer.projection){geojson.crs=this.createCRSObject(obj);}}
return OpenLayers.Format.JSON.prototype.write.apply(this,[geojson,pretty]);},createCRSObject:function(object){var proj=object.layer.projection.toString();var crs={};if(proj.match(/epsg:/i)){var code=parseInt(proj.substring(proj.indexOf(":")+1));if(code==4326){crs={"type":"OGC","properties":{"urn":"urn:ogc:def:crs:OGC:1.3:CRS84"}};}else{crs={"type":"EPSG","properties":{"code":code}};}}
return crs;},extract:{'feature':function(feature){var geom=this.extract.geometry.apply(this,[feature.geometry]);return{"type":"Feature","id":feature.fid==null?feature.id:feature.fid,"properties":feature.attributes,"geometry":geom};},'geometry':function(geometry){if(geometry==null){return null;}
if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
var geometryType=geometry.CLASS_NAME.split('.')[2];var data=this.extract[geometryType.toLowerCase()].apply(this,[geometry]);var json;if(geometryType=="Collection"){json={"type":"GeometryCollection","geometries":data};}else{json={"type":geometryType,"coordinates":data};}
return json;},'point':function(point){return[point.x,point.y];},'multipoint':function(multipoint){var array=[];for(var i=0,len=multipoint.components.length;i<len;++i){array.push(this.extract.point.apply(this,[multipoint.components[i]]));}
return array;},'linestring':function(linestring){var array=[];for(var i=0,len=linestring.components.length;i<len;++i){array.push(this.extract.point.apply(this,[linestring.components[i]]));}
return array;},'multilinestring':function(multilinestring){var array=[];for(var i=0,len=multilinestring.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[multilinestring.components[i]]));}
return array;},'polygon':function(polygon){var array=[];for(var i=0,len=polygon.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[polygon.components[i]]));}
return array;},'multipolygon':function(multipolygon){var array=[];for(var i=0,len=multipolygon.components.length;i<len;++i){array.push(this.extract.polygon.apply(this,[multipolygon.components[i]]));}
return array;},'collection':function(collection){var len=collection.components.length;var array=new Array(len);for(var i=0;i<len;++i){array[i]=this.extract.geometry.apply(this,[collection.components[i]]);}
return array;}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Format.ArcXML.Features=OpenLayers.Class(OpenLayers.Format.XML,{initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){var axl=new OpenLayers.Format.ArcXML();var parsed=axl.read(data);return parsed.features.feature;}});if(!OpenLayers.Format.GML){OpenLayers.Format.GML={};}
OpenLayers.Format.GML.Base=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs"},defaultPrefix:"gml",schemaLocation:null,featureType:null,featureNS:null,geometryName:"geometry",extractAttributes:true,srsName:null,xy:true,geometryTypes:null,singleFeatureType:null,regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.setGeometryTypes();if(options&&options.featureNS){this.setNamespace("feature",options.featureNS);}
this.singleFeatureType=!options||(typeof options.featureType==="string");},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var features=[];this.readNode(data,{features:features});if(features.length==0){var elements=this.getElementsByTagNameNS(data,this.namespaces.gml,"featureMember");if(elements.length){for(var i=0,len=elements.length;i<len;++i){this.readNode(elements[i],{features:features});}}else{var elements=this.getElementsByTagNameNS(data,this.namespaces.gml,"featureMembers");if(elements.length){this.readNode(elements[0],{features:features});}}}
return features;},readers:{"gml":{"featureMember":function(node,obj){this.readChildNodes(node,obj);},"featureMembers":function(node,obj){this.readChildNodes(node,obj);},"name":function(node,obj){obj.name=this.getChildValue(node);},"boundedBy":function(node,obj){var container={};this.readChildNodes(node,container);if(container.components&&container.components.length>0){obj.bounds=container.components[0];}},"Point":function(node,container){var obj={points:[]};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
container.components.push(obj.points[0]);},"coordinates":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");str=str.replace(this.regExes.trimComma,",");var pointList=str.split(this.regExes.splitSpace);var coords;var numPoints=pointList.length;var points=new Array(numPoints);for(var i=0;i<numPoints;++i){coords=pointList[i].split(",");if(this.xy){points[i]=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{points[i]=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}}
obj.points=points;},"coord":function(node,obj){var coord={};this.readChildNodes(node,coord);if(!obj.points){obj.points=[];}
obj.points.push(new OpenLayers.Geometry.Point(coord.x,coord.y,coord.z));},"X":function(node,coord){coord.x=this.getChildValue(node);},"Y":function(node,coord){coord.y=this.getChildValue(node);},"Z":function(node,coord){coord.z=this.getChildValue(node);},"MultiPoint":function(node,container){var obj={components:[]};this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.MultiPoint(obj.components)];},"pointMember":function(node,obj){this.readChildNodes(node,obj);},"LineString":function(node,container){var obj={};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
container.components.push(new OpenLayers.Geometry.LineString(obj.points));},"MultiLineString":function(node,container){var obj={components:[]};this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.MultiLineString(obj.components)];},"lineStringMember":function(node,obj){this.readChildNodes(node,obj);},"Polygon":function(node,container){var obj={outer:null,inner:[]};this.readChildNodes(node,obj);obj.inner.unshift(obj.outer);if(!container.components){container.components=[];}
container.components.push(new OpenLayers.Geometry.Polygon(obj.inner));},"LinearRing":function(node,obj){var container={};this.readChildNodes(node,container);obj.components=[new OpenLayers.Geometry.LinearRing(container.points)];},"MultiPolygon":function(node,container){var obj={components:[]};this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.MultiPolygon(obj.components)];},"polygonMember":function(node,obj){this.readChildNodes(node,obj);},"GeometryCollection":function(node,container){var obj={components:[]};this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.Collection(obj.components)];},"geometryMember":function(node,obj){this.readChildNodes(node,obj);}},"feature":{"*":function(node,obj){var name;var local=node.localName||node.nodeName.split(":").pop();if(obj.features){if(!this.singleFeatureType&&(OpenLayers.Util.indexOf(this.featureType,local)!==-1)){name="_typeName";}else if(local===this.featureType){name="_typeName";}}else{if(node.childNodes.length==0||(node.childNodes.length==1&&node.firstChild.nodeType==3)){if(this.extractAttributes){name="_attribute";}}else{name="_geometry";}}
if(name){this.readers.feature[name].apply(this,[node,obj]);}},"_typeName":function(node,obj){var container={components:[],attributes:{}};this.readChildNodes(node,container);if(container.name){container.attributes.name=container.name;}
var feature=new OpenLayers.Feature.Vector(container.components[0],container.attributes);if(!this.singleFeatureType){feature.type=node.nodeName.split(":").pop();feature.namespace=node.namespaceURI;}
var fid=node.getAttribute("fid")||this.getAttributeNS(node,this.namespaces["gml"],"id");if(fid){feature.fid=fid;}
if(this.internalProjection&&this.externalProjection&&feature.geometry){feature.geometry.transform(this.externalProjection,this.internalProjection);}
if(container.bounds){feature.bounds=container.bounds;}
obj.features.push(feature);},"_geometry":function(node,obj){this.readChildNodes(node,obj);},"_attribute":function(node,obj){var local=node.localName||node.nodeName.split(":").pop();var value=this.getChildValue(node);obj.attributes[local]=value;}},"wfs":{"FeatureCollection":function(node,obj){this.readChildNodes(node,obj);}}},write:function(features){var name;if(features instanceof Array){name="featureMembers";}else{name="featureMember";}
var root=this.writeNode("gml:"+name,features);this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},writers:{"gml":{"featureMember":function(feature){var node=this.createElementNSPlus("gml:featureMember");this.writeNode("feature:_typeName",feature,node);return node;},"MultiPoint":function(geometry){var node=this.createElementNSPlus("gml:MultiPoint");for(var i=0;i<geometry.components.length;++i){this.writeNode("pointMember",geometry.components[i],node);}
return node;},"pointMember":function(geometry){var node=this.createElementNSPlus("gml:pointMember");this.writeNode("Point",geometry,node);return node;},"MultiLineString":function(geometry){var node=this.createElementNSPlus("gml:MultiLineString");for(var i=0;i<geometry.components.length;++i){this.writeNode("lineStringMember",geometry.components[i],node);}
return node;},"lineStringMember":function(geometry){var node=this.createElementNSPlus("gml:lineStringMember");this.writeNode("LineString",geometry,node);return node;},"MultiPolygon":function(geometry){var node=this.createElementNSPlus("gml:MultiPolygon");for(var i=0;i<geometry.components.length;++i){this.writeNode("polygonMember",geometry.components[i],node);}
return node;},"polygonMember":function(geometry){var node=this.createElementNSPlus("gml:polygonMember");this.writeNode("Polygon",geometry,node);return node;},"GeometryCollection":function(geometry){var node=this.createElementNSPlus("gml:GeometryCollection");for(var i=0,len=geometry.components.length;i<len;++i){this.writeNode("geometryMember",geometry.components[i],node);}
return node;},"geometryMember":function(geometry){var node=this.createElementNSPlus("gml:geometryMember");var child=this.writeNode("feature:_geometry",geometry);node.appendChild(child.firstChild);return node;}},"feature":{"_typeName":function(feature){var node=this.createElementNSPlus("feature:"+this.featureType,{attributes:{fid:feature.fid}});if(feature.geometry){this.writeNode("feature:_geometry",feature.geometry,node);}
for(var name in feature.attributes){var value=feature.attributes[name];if(value!=null){this.writeNode("feature:_attribute",{name:name,value:value},node);}}
return node;},"_geometry":function(geometry){if(this.externalProjection&&this.internalProjection){geometry=geometry.clone().transform(this.internalProjection,this.externalProjection);}
var node=this.createElementNSPlus("feature:"+this.geometryName);var type=this.geometryTypes[geometry.CLASS_NAME];var child=this.writeNode("gml:"+type,geometry,node);if(this.srsName){child.setAttribute("srsName",this.srsName);}
return node;},"_attribute":function(obj){return this.createElementNSPlus("feature:"+obj.name,{value:obj.value});}},"wfs":{"FeatureCollection":function(features){var node=this.createElementNSPlus("wfs:FeatureCollection");for(var i=0,len=features.length;i<len;++i){this.writeNode("gml:featureMember",features[i],node);}
return node;}}},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":"LineString","OpenLayers.Geometry.MultiLineString":"MultiLineString","OpenLayers.Geometry.Polygon":"Polygon","OpenLayers.Geometry.MultiPolygon":"MultiPolygon","OpenLayers.Geometry.Collection":"GeometryCollection"};},CLASS_NAME:"OpenLayers.Format.GML.Base"});OpenLayers.Format.WFS=OpenLayers.Class(OpenLayers.Format.GML,{layer:null,wfsns:"http://www.opengis.net/wfs",ogcns:"http://www.opengis.net/ogc",initialize:function(options,layer){OpenLayers.Format.GML.prototype.initialize.apply(this,[options]);this.layer=layer;if(this.layer.featureNS){this.featureNS=this.layer.featureNS;}
if(this.layer.options.geometry_column){this.geometryName=this.layer.options.geometry_column;}
if(this.layer.options.typename){this.featureName=this.layer.options.typename;}},write:function(features){var transaction=this.createElementNS(this.wfsns,'wfs:Transaction');transaction.setAttribute("version","1.0.0");transaction.setAttribute("service","WFS");for(var i=0;i<features.length;i++){switch(features[i].state){case OpenLayers.State.INSERT:transaction.appendChild(this.insert(features[i]));break;case OpenLayers.State.UPDATE:transaction.appendChild(this.update(features[i]));break;case OpenLayers.State.DELETE:transaction.appendChild(this.remove(features[i]));break;}}
return OpenLayers.Format.XML.prototype.write.apply(this,[transaction]);},createFeatureXML:function(feature){var geometryNode=this.buildGeometryNode(feature.geometry);var geomContainer=this.createElementNS(this.featureNS,"feature:"+this.geometryName);geomContainer.appendChild(geometryNode);var featureContainer=this.createElementNS(this.featureNS,"feature:"+this.featureName);featureContainer.appendChild(geomContainer);for(var attr in feature.attributes){var attrText=this.createTextNode(feature.attributes[attr]);var nodename=attr;if(attr.search(":")!=-1){nodename=attr.split(":")[1];}
var attrContainer=this.createElementNS(this.featureNS,"feature:"+nodename);attrContainer.appendChild(attrText);featureContainer.appendChild(attrContainer);}
return featureContainer;},insert:function(feature){var insertNode=this.createElementNS(this.wfsns,'wfs:Insert');insertNode.appendChild(this.createFeatureXML(feature));return insertNode;},update:function(feature){if(!feature.fid){OpenLayers.Console.userError(OpenLayers.i18n("noFID"));}
var updateNode=this.createElementNS(this.wfsns,'wfs:Update');updateNode.setAttribute("typeName",this.featurePrefix+':'+this.featureName);updateNode.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var propertyNode=this.createElementNS(this.wfsns,'wfs:Property');var nameNode=this.createElementNS(this.wfsns,'wfs:Name');var txtNode=this.createTextNode(this.geometryName);nameNode.appendChild(txtNode);propertyNode.appendChild(nameNode);var valueNode=this.createElementNS(this.wfsns,'wfs:Value');var geometryNode=this.buildGeometryNode(feature.geometry);if(feature.layer){geometryNode.setAttribute("srsName",feature.layer.projection.getCode());}
valueNode.appendChild(geometryNode);propertyNode.appendChild(valueNode);updateNode.appendChild(propertyNode);for(var propName in feature.attributes){propertyNode=this.createElementNS(this.wfsns,'wfs:Property');nameNode=this.createElementNS(this.wfsns,'wfs:Name');nameNode.appendChild(this.createTextNode(propName));propertyNode.appendChild(nameNode);valueNode=this.createElementNS(this.wfsns,'wfs:Value');valueNode.appendChild(this.createTextNode(feature.attributes[propName]));propertyNode.appendChild(valueNode);updateNode.appendChild(propertyNode);}
var filterNode=this.createElementNS(this.ogcns,'ogc:Filter');var filterIdNode=this.createElementNS(this.ogcns,'ogc:FeatureId');filterIdNode.setAttribute("fid",feature.fid);filterNode.appendChild(filterIdNode);updateNode.appendChild(filterNode);return updateNode;},remove:function(feature){if(!feature.fid){OpenLayers.Console.userError(OpenLayers.i18n("noFID"));return false;}
var deleteNode=this.createElementNS(this.wfsns,'wfs:Delete');deleteNode.setAttribute("typeName",this.featurePrefix+':'+this.featureName);deleteNode.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var filterNode=this.createElementNS(this.ogcns,'ogc:Filter');var filterIdNode=this.createElementNS(this.ogcns,'ogc:FeatureId');filterIdNode.setAttribute("fid",feature.fid);filterNode.appendChild(filterIdNode);deleteNode.appendChild(filterNode);return deleteNode;},destroy:function(){this.layer=null;},CLASS_NAME:"OpenLayers.Format.WFS"});OpenLayers.Layer.ArcIMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{ClientVersion:"9.2",ServiceName:''},tileSize:null,featureCoordSys:"4326",filterCoordSys:"4326",layers:null,async:true,name:"ArcIMS",isBaseLayer:true,DEFAULT_OPTIONS:{tileSize:new OpenLayers.Size(512,512),featureCoordSys:"4326",filterCoordSys:"4326",layers:null,isBaseLayer:true,async:true,name:"ArcIMS"},initialize:function(name,url,options){this.tileSize=new OpenLayers.Size(512,512);this.params=OpenLayers.Util.applyDefaults({ServiceName:options.serviceName},this.DEFAULT_PARAMS);this.options=OpenLayers.Util.applyDefaults(options,this.DEFAULT_OPTIONS);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[name,url,this.params,options]);if(this.transparent){if(!this.isBaseLayer){this.isBaseLayer=false;}
if(this.format=="image/jpeg"){this.format=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}
if(this.options.layers===null){this.options.layers=[];}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},getURL:function(bounds){var url="";bounds=this.adjustBounds(bounds);var axlReq=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",envelope:bounds.toArray(),tileSize:this.tileSize}));var req=new OpenLayers.Request.POST({url:this.getFullRequestString(),data:axlReq.write(),async:false});if(req!=null){var doc=req.responseXML;if(!doc||!doc.documentElement){doc=req.responseText;}
var axlResp=new OpenLayers.Format.ArcXML();var arcxml=axlResp.read(doc);url=this.getUrlOrImage(arcxml.image.output);}
return url;},getURLasync:function(bounds,scope,prop,callback){bounds=this.adjustBounds(bounds);var axlReq=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",envelope:bounds.toArray(),tileSize:this.tileSize}));OpenLayers.Request.POST({url:this.getFullRequestString(),async:true,data:axlReq.write(),callback:function(req){var doc=req.responseXML;if(!doc||!doc.documentElement){doc=req.responseText;}
var axlResp=new OpenLayers.Format.ArcXML();var arcxml=axlResp.read(doc);scope[prop]=this.getUrlOrImage(arcxml.image.output);callback.apply(scope);},scope:this});},getUrlOrImage:function(output){var ret="";if(output.url){ret=output.url;}else if(output.data){ret="data:image/"+output.type+";base64,"+output.data;}
return ret;},setLayerQuery:function(id,querydef){for(var lyr=0;lyr<this.options.layers.length;lyr++){if(id==this.options.layers[lyr].id){this.options.layers[lyr].query=querydef;return;}}
this.options.layers.push({id:id,visible:true,query:querydef});},getFeatureInfo:function(geometry,layer,options){var buffer=options.buffer||1;var callback=options.callback||function(){};var scope=options.scope||window;var requestOptions={};OpenLayers.Util.extend(requestOptions,this.options);requestOptions.requesttype="feature";if(geometry instanceof OpenLayers.LonLat){requestOptions.polygon=null;requestOptions.envelope=[geometry.lon-buffer,geometry.lat-buffer,geometry.lon+buffer,geometry.lat+buffer];}else if(geometry instanceof OpenLayers.Geometry.Polygon){requestOptions.envelope=null;requestOptions.polygon=geometry;}
var arcxml=new OpenLayers.Format.ArcXML(requestOptions);OpenLayers.Util.extend(arcxml.request.get_feature,options);arcxml.request.get_feature.layer=layer.id;if(typeof layer.query.accuracy=="number"){arcxml.request.get_feature.query.accuracy=layer.query.accuracy;}else{var mapCenter=this.map.getCenter();var viewPx=this.map.getViewPortPxFromLonLat(mapCenter);viewPx.x++;var mapOffCenter=this.map.getLonLatFromPixel(viewPx);arcxml.request.get_feature.query.accuracy=mapOffCenter.lon-mapCenter.lon;}
arcxml.request.get_feature.query.where=layer.query.where;arcxml.request.get_feature.query.spatialfilter.relation="area_intersection";OpenLayers.Request.POST({url:this.getFullRequestString({'CustomService':'Query'}),data:arcxml.write(),callback:function(request){var response=arcxml.parseResponse(request.responseText);if(!arcxml.iserror()){callback.call(scope,response.features);}else{callback.call(scope,null);}}});},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.ArcIMS(this.name,this.url,this.getOptions());}
obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},CLASS_NAME:"OpenLayers.Layer.ArcIMS"});OpenLayers.Format.GML.v2=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",initialize:function(options){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[options]);},readers:{"gml":OpenLayers.Util.applyDefaults({"outerBoundaryIs":function(node,container){var obj={};this.readChildNodes(node,obj);container.outer=obj.components[0];},"innerBoundaryIs":function(node,container){var obj={};this.readChildNodes(node,obj);container.inner.push(obj.components[0]);},"Box":function(node,container){var obj={};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
var min=obj.points[0];var max=obj.points[1];container.components.push(new OpenLayers.Bounds(min.x,min.y,max.x,max.y));}},OpenLayers.Format.GML.Base.prototype.readers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.readers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.readers["wfs"]},write:function(features){var name;if(features instanceof Array){name="wfs:FeatureCollection";}else{name="gml:featureMember";}
var root=this.writeNode(name,features);this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},writers:{"gml":OpenLayers.Util.applyDefaults({"Point":function(geometry){var node=this.createElementNSPlus("gml:Point");this.writeNode("coordinates",[geometry],node);return node;},"coordinates":function(points){var numPoints=points.length;var parts=new Array(numPoints);var point;for(var i=0;i<numPoints;++i){point=points[i];if(this.xy){parts[i]=point.x+","+point.y;}else{parts[i]=point.y+","+point.x;}
if(point.z!=undefined){parts[i]+=","+point.z;}}
return this.createElementNSPlus("gml:coordinates",{attributes:{decimal:".",cs:",",ts:" "},value:(numPoints==1)?parts[0]:parts.join(" ")});},"LineString":function(geometry){var node=this.createElementNSPlus("gml:LineString");this.writeNode("coordinates",geometry.components,node);return node;},"Polygon":function(geometry){var node=this.createElementNSPlus("gml:Polygon");this.writeNode("outerBoundaryIs",geometry.components[0],node);for(var i=1;i<geometry.components.length;++i){this.writeNode("innerBoundaryIs",geometry.components[i],node);}
return node;},"outerBoundaryIs":function(ring){var node=this.createElementNSPlus("gml:outerBoundaryIs");this.writeNode("LinearRing",ring,node);return node;},"innerBoundaryIs":function(ring){var node=this.createElementNSPlus("gml:innerBoundaryIs");this.writeNode("LinearRing",ring,node);return node;},"LinearRing":function(ring){var node=this.createElementNSPlus("gml:LinearRing");this.writeNode("coordinates",ring.components,node);return node;},"Box":function(bounds){var node=this.createElementNSPlus("gml:Box");this.writeNode("coordinates",[{x:bounds.left,y:bounds.bottom},{x:bounds.right,y:bounds.top}],node);if(this.srsName){node.setAttribute("srsName",this.srsName);}
return node;}},OpenLayers.Format.GML.Base.prototype.writers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.writers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.writers["wfs"]},CLASS_NAME:"OpenLayers.Format.GML.v2"});OpenLayers.Format.GML.v3=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",curve:false,multiCurve:true,surface:false,multiSurface:true,initialize:function(options){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[options]);},readers:{"gml":OpenLayers.Util.applyDefaults({"featureMembers":function(node,obj){this.readChildNodes(node,obj);},"Curve":function(node,container){var obj={points:[]};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
container.components.push(new OpenLayers.Geometry.LineString(obj.points));},"segments":function(node,obj){this.readChildNodes(node,obj);},"LineStringSegment":function(node,container){var obj={};this.readChildNodes(node,obj);if(obj.points){Array.prototype.push.apply(container.points,obj.points);}},"pos":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");var coords=str.split(this.regExes.splitSpace);var point;if(this.xy){point=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{point=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}
obj.points=[point];},"posList":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");var coords=str.split(this.regExes.splitSpace);var dim=parseInt(node.getAttribute("dimension"))||2;var j,x,y,z;var numPoints=coords.length/dim;var points=new Array(numPoints);for(var i=0,len=coords.length;i<len;i+=dim){x=coords[i];y=coords[i+1];z=(dim==2)?undefined:coords[i+2];if(this.xy){points[i/dim]=new OpenLayers.Geometry.Point(x,y,z);}else{points[i/dim]=new OpenLayers.Geometry.Point(y,x,z);}}
obj.points=points;},"Surface":function(node,obj){this.readChildNodes(node,obj);},"patches":function(node,obj){this.readChildNodes(node,obj);},"PolygonPatch":function(node,obj){this.readers.gml.Polygon.apply(this,[node,obj]);},"exterior":function(node,container){var obj={};this.readChildNodes(node,obj);container.outer=obj.components[0];},"interior":function(node,container){var obj={};this.readChildNodes(node,obj);container.inner.push(obj.components[0]);},"MultiCurve":function(node,container){var obj={components:[]};this.readChildNodes(node,obj);if(obj.components.length>0){container.components=[new OpenLayers.Geometry.MultiLineString(obj.components)];}},"curveMember":function(node,obj){this.readChildNodes(node,obj);},"MultiSurface":function(node,container){var obj={components:[]};this.readChildNodes(node,obj);if(obj.components.length>0){container.components=[new OpenLayers.Geometry.MultiPolygon(obj.components)];}},"surfaceMember":function(node,obj){this.readChildNodes(node,obj);},"surfaceMembers":function(node,obj){this.readChildNodes(node,obj);},"pointMembers":function(node,obj){this.readChildNodes(node,obj);},"lineStringMembers":function(node,obj){this.readChildNodes(node,obj);},"polygonMembers":function(node,obj){this.readChildNodes(node,obj);},"geometryMembers":function(node,obj){this.readChildNodes(node,obj);},"Envelope":function(node,container){var obj={points:new Array(2)};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
var min=obj.points[0];var max=obj.points[1];container.components.push(new OpenLayers.Bounds(min.x,min.y,max.x,max.y));},"lowerCorner":function(node,container){var obj={};this.readers.gml.pos.apply(this,[node,obj]);container.points[0]=obj.points[0];},"upperCorner":function(node,container){var obj={};this.readers.gml.pos.apply(this,[node,obj]);container.points[1]=obj.points[0];}},OpenLayers.Format.GML.Base.prototype.readers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.readers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.readers["wfs"]},write:function(features){var name;if(features instanceof Array){name="featureMembers";}else{name="featureMember";}
var root=this.writeNode("gml:"+name,features);this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},writers:{"gml":OpenLayers.Util.applyDefaults({"featureMembers":function(features){var node=this.createElementNSPlus("gml:featureMembers");for(var i=0,len=features.length;i<len;++i){this.writeNode("feature:_typeName",features[i],node);}
return node;},"Point":function(geometry){var node=this.createElementNSPlus("gml:Point");this.writeNode("pos",geometry,node);return node;},"pos":function(point){var pos=(this.xy)?(point.x+" "+point.y):(point.y+" "+point.x);return this.createElementNSPlus("gml:pos",{value:pos});},"LineString":function(geometry){var node=this.createElementNSPlus("gml:LineString");this.writeNode("posList",geometry.components,node);return node;},"Curve":function(geometry){var node=this.createElementNSPlus("gml:Curve");this.writeNode("segments",geometry,node);return node;},"segments":function(geometry){var node=this.createElementNSPlus("gml:segments");this.writeNode("LineStringSegment",geometry,node);return node;},"LineStringSegment":function(geometry){var node=this.createElementNSPlus("gml:LineStringSegment");this.writeNode("posList",geometry.components,node);return node;},"posList":function(points){var len=points.length;var parts=new Array(len);var point;for(var i=0;i<len;++i){point=points[i];if(this.xy){parts[i]=point.x+" "+point.y;}else{parts[i]=point.y+" "+point.x;}}
return this.createElementNSPlus("gml:posList",{value:parts.join(" ")});},"Surface":function(geometry){var node=this.createElementNSPlus("gml:Surface");this.writeNode("patches",geometry,node);return node;},"patches":function(geometry){var node=this.createElementNSPlus("gml:patches");this.writeNode("PolygonPatch",geometry,node);return node;},"PolygonPatch":function(geometry){var node=this.createElementNSPlus("gml:PolygonPatch",{attributes:{interpolation:"planar"}});this.writeNode("exterior",geometry.components[0],node);for(var i=1,len=geometry.components.length;i<len;++i){this.writeNode("interior",geometry.components[i],node);}
return node;},"Polygon":function(geometry){var node=this.createElementNSPlus("gml:Polygon");this.writeNode("exterior",geometry.components[0],node);for(var i=1,len=geometry.components.length;i<len;++i){this.writeNode("interior",geometry.components[i],node);}
return node;},"exterior":function(ring){var node=this.createElementNSPlus("gml:exterior");this.writeNode("LinearRing",ring,node);return node;},"interior":function(ring){var node=this.createElementNSPlus("gml:interior");this.writeNode("LinearRing",ring,node);return node;},"LinearRing":function(ring){var node=this.createElementNSPlus("gml:LinearRing");this.writeNode("posList",ring.components,node);return node;},"MultiCurve":function(geometry){var node=this.createElementNSPlus("gml:MultiCurve");for(var i=0,len=geometry.components.length;i<len;++i){this.writeNode("curveMember",geometry.components[i],node);}
return node;},"curveMember":function(geometry){var node=this.createElementNSPlus("gml:curveMember");if(this.curve){this.writeNode("Curve",geometry,node);}else{this.writeNode("LineString",geometry,node);}
return node;},"MultiSurface":function(geometry){var node=this.createElementNSPlus("gml:MultiSurface");for(var i=0,len=geometry.components.length;i<len;++i){this.writeNode("surfaceMember",geometry.components[i],node);}
return node;},"surfaceMember":function(polygon){var node=this.createElementNSPlus("gml:surfaceMember");if(this.surface){this.writeNode("Surface",polygon,node);}else{this.writeNode("Polygon",polygon,node);}
return node;},"Envelope":function(bounds){var node=this.createElementNSPlus("gml:Envelope");this.writeNode("lowerCorner",bounds,node);this.writeNode("upperCorner",bounds,node);if(this.srsName){node.setAttribute("srsName",this.srsName);}
return node;},"lowerCorner":function(bounds){var pos=(this.xy)?(bounds.left+" "+bounds.bottom):(bounds.bottom+" "+bounds.left);return this.createElementNSPlus("gml:lowerCorner",{value:pos});},"upperCorner":function(bounds){var pos=(this.xy)?(bounds.right+" "+bounds.top):(bounds.top+" "+bounds.right);return this.createElementNSPlus("gml:upperCorner",{value:pos});}},OpenLayers.Format.GML.Base.prototype.writers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.writers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.writers["wfs"]},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":(this.curve===true)?"Curve":"LineString","OpenLayers.Geometry.MultiLineString":(this.multiCurve===false)?"MultiLineString":"MultiCurve","OpenLayers.Geometry.Polygon":(this.surface===true)?"Surface":"Polygon","OpenLayers.Geometry.MultiPolygon":(this.multiSurface===false)?"MultiPolygon":"MultiSurface","OpenLayers.Geometry.Collection":"GeometryCollection"};},CLASS_NAME:"OpenLayers.Format.GML.v3"});OpenLayers.Format.Atom=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{atom:"http://www.w3.org/2005/Atom",georss:"http://www.georss.org/georss"},feedTitle:"untitled",defaultEntryTitle:"untitled",gmlParser:null,xy:false,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(doc){if(typeof doc=="string"){doc=OpenLayers.Format.XML.prototype.read.apply(this,[doc]);}
return this.parseFeatures(doc);},write:function(features){var doc;if(features instanceof Array){doc=this.createElementNSPlus("atom:feed");doc.appendChild(this.createElementNSPlus("atom:title",{value:this.feedTitle}));for(var i=0,ii=features.length;i<ii;i++){doc.appendChild(this.buildEntryNode(features[i]));}}
else{doc=this.buildEntryNode(features);}
return OpenLayers.Format.XML.prototype.write.apply(this,[doc]);},buildContentNode:function(content){var node=this.createElementNSPlus("atom:content",{attributes:{type:content.type||null}});if(content.src){node.setAttribute("src",content.src);}else{if(content.type=="text"||content.type==null){node.appendChild(this.createTextNode(content.value));}else if(content.type=="html"){if(typeof content.value!="string"){throw"HTML content must be in form of an escaped string";}
node.appendChild(this.createTextNode(content.value));}else if(content.type=="xhtml"){node.appendChild(content.value);}else if(content.type=="xhtml"||content.type.match(/(\+|\/)xml$/)){node.appendChild(content.value);}
else{node.appendChild(this.createTextNode(content.value));}}
return node;},buildEntryNode:function(feature){var attrib=feature.attributes;var atomAttrib=attrib.atom||{};var entryNode=this.createElementNSPlus("atom:entry");if(atomAttrib.authors){var authors=atomAttrib.authors instanceof Array?atomAttrib.authors:[atomAttrib.authors];for(var i=0,ii=authors.length;i<ii;i++){entryNode.appendChild(this.buildPersonConstructNode("author",authors[i]));}}
if(atomAttrib.categories){var categories=atomAttrib.categories instanceof Array?atomAttrib.categories:[atomAttrib.categories];var category;for(var i=0,ii=categories.length;i<ii;i++){category=categories[i];entryNode.appendChild(this.createElementNSPlus("atom:category",{attributes:{term:category.term,scheme:category.scheme||null,label:category.label||null}}));}}
if(atomAttrib.content){entryNode.appendChild(this.buildContentNode(atomAttrib.content));}
if(atomAttrib.contributors){var contributors=atomAttrib.contributors instanceof Array?atomAttrib.contributors:[atomAttrib.contributors];for(var i=0,ii=contributors.length;i<ii;i++){entryNode.appendChild(this.buildPersonConstructNode("contributor",contributors[i]));}}
if(feature.fid){entryNode.appendChild(this.createElementNSPlus("atom:id",{value:feature.fid}));}
if(atomAttrib.links){var links=atomAttrib.links instanceof Array?atomAttrib.links:[atomAttrib.links];var link;for(var i=0,ii=links.length;i<ii;i++){link=links[i];entryNode.appendChild(this.createElementNSPlus("atom:link",{attributes:{href:link.href,rel:link.rel||null,type:link.type||null,hreflang:link.hreflang||null,title:link.title||null,length:link.length||null}}));}}
if(atomAttrib.published){entryNode.appendChild(this.createElementNSPlus("atom:published",{value:atomAttrib.published}));}
if(atomAttrib.rights){entryNode.appendChild(this.createElementNSPlus("atom:rights",{value:atomAttrib.rights}));}
if(atomAttrib.summary||attrib.description){entryNode.appendChild(this.createElementNSPlus("atom:summary",{value:atomAttrib.summary||attrib.description}));}
entryNode.appendChild(this.createElementNSPlus("atom:title",{value:atomAttrib.title||attrib.title||this.defaultEntryTitle}));if(atomAttrib.updated){entryNode.appendChild(this.createElementNSPlus("atom:updated",{value:atomAttrib.updated}));}
if(feature.geometry){var whereNode=this.createElementNSPlus("georss:where");whereNode.appendChild(this.buildGeometryNode(feature.geometry));entryNode.appendChild(whereNode);}
return entryNode;},initGmlParser:function(){this.gmlParser=new OpenLayers.Format.GML.v3({xy:this.xy,featureNS:"http://example.com#feature",internalProjection:this.internalProjection,externalProjection:this.externalProjection});},buildGeometryNode:function(geometry){if(!this.gmlParser){this.initGmlParser();}
var node=this.gmlParser.writeNode("feature:_geometry",geometry);return node.firstChild;},buildPersonConstructNode:function(name,value){var oNames=["uri","email"];var personNode=this.createElementNSPlus("atom:"+name);personNode.appendChild(this.createElementNSPlus("atom:name",{value:value.name}));for(var i=0,ii=oNames.length;i<ii;i++){if(value[oNames[i]]){personNode.appendChild(this.createElementNSPlus("atom:"+oNames[i],{value:value[oNames[i]]}));}}
return personNode;},getFirstChildValue:function(node,nsuri,name,def){var value;var nodes=this.getElementsByTagNameNS(node,nsuri,name);if(nodes&&nodes.length>0){value=this.getChildValue(nodes[0],def);}else{value=def;}
return value;},parseFeature:function(node){var atomAttrib={};var value=null;var nodes=null;var attval=null;var atomns=this.namespaces.atom;this.parsePersonConstructs(node,"author",atomAttrib);nodes=this.getElementsByTagNameNS(node,atomns,"category");if(nodes.length>0){atomAttrib.categories=[];}
for(var i=0,ii=nodes.length;i<ii;i++){value={};value.term=nodes[i].getAttribute("term");attval=nodes[i].getAttribute("scheme");if(attval){value.scheme=attval;}
attval=nodes[i].getAttribute("label");if(attval){value.label=attval;}
atomAttrib.categories.push(value);}
nodes=this.getElementsByTagNameNS(node,atomns,"content");if(nodes.length>0){value={};attval=nodes[0].getAttribute("type");if(attval){value.type=attval;}
attval=nodes[0].getAttribute("src");if(attval){value.src=attval;}else{if(value.type=="text"||value.type=="html"||value.type==null){value.value=this.getFirstChildValue(node,atomns,"content",null);}else if(value.type=="xhtml"||value.type.match(/(\+|\/)xml$/)){value.value=this.getChildEl(nodes[0]);}else{value.value=this.getFirstChildValue(node,atomns,"content",null);}
atomAttrib.content=value;}}
this.parsePersonConstructs(node,"contributor",atomAttrib);atomAttrib.id=this.getFirstChildValue(node,atomns,"id",null);nodes=this.getElementsByTagNameNS(node,atomns,"link");if(nodes.length>0){atomAttrib.links=new Array(nodes.length);}
var oAtts=["rel","type","hreflang","title","length"];for(var i=0,ii=nodes.length;i<ii;i++){value={};value.href=nodes[i].getAttribute("href");for(var j=0,jj=oAtts.length;j<jj;j++){attval=nodes[i].getAttribute(oAtts[j]);if(attval){value[oAtts[j]]=attval;}}
atomAttrib.links[i]=value;}
value=this.getFirstChildValue(node,atomns,"published",null);if(value){atomAttrib.published=value;}
value=this.getFirstChildValue(node,atomns,"rights",null);if(value){atomAttrib.rights=value;}
value=this.getFirstChildValue(node,atomns,"summary",null);if(value){atomAttrib.summary=value;}
atomAttrib.title=this.getFirstChildValue(node,atomns,"title",null);atomAttrib.updated=this.getFirstChildValue(node,atomns,"updated",null);var featureAttrib={title:atomAttrib.title,description:atomAttrib.summary,atom:atomAttrib};var geometry=this.parseLocations(node)[0];var feature=new OpenLayers.Feature.Vector(geometry,featureAttrib);feature.fid=atomAttrib.id;return feature;},parseFeatures:function(node){var features=[];var entries=this.getElementsByTagNameNS(node,this.namespaces.atom,"entry");if(entries.length==0){entries=[node];}
for(var i=0,ii=entries.length;i<ii;i++){features.push(this.parseFeature(entries[i]));}
return features;},parseLocations:function(node){var georssns=this.namespaces.georss;var locations={components:[]};var where=this.getElementsByTagNameNS(node,georssns,"where");if(where&&where.length>0){if(!this.gmlParser){this.initGmlParser();}
for(var i=0,ii=where.length;i<ii;i++){this.gmlParser.readChildNodes(where[i],locations);}}
var components=locations.components;var point=this.getElementsByTagNameNS(node,georssns,"point");if(point&&point.length>0){for(var i=0,ii=point.length;i<ii;i++){var xy=OpenLayers.String.trim(point[i].firstChild.nodeValue).split(/\s+/);if(xy.length!=2){xy=OpenLayers.String.trim(point[i].firstChild.nodeValue).split(/\s*,\s*/);}
components.push(new OpenLayers.Geometry.Point(parseFloat(xy[1]),parseFloat(xy[0])));}}
var line=this.getElementsByTagNameNS(node,georssns,"line");if(line&&line.length>0){var coords;var p;var points;for(var i=0,ii=line.length;i<ii;i++){coords=OpenLayers.String.trim(line[i].firstChild.nodeValue).split(/\s+/);points=[];for(var j=0,jj=coords.length;j<jj;j+=2){p=new OpenLayers.Geometry.Point(parseFloat(coords[j+1]),parseFloat(coords[j]));points.push(p);}
components.push(new OpenLayers.Geometry.LineString(points));}}
var polygon=this.getElementsByTagNameNS(node,georssns,"polygon");if(polygon&&polygon.length>0){var coords;var p;var points;for(var i=0,ii=polygon.length;i<ii;i++){coords=OpenLayers.String.trim(polygon[i].firstChild.nodeValue).split(/\s+/);points=[];for(var j=0,jj=coords.length;j<jj;j+=2){p=new OpenLayers.Geometry.Point(parseFloat(coords[j+1]),parseFloat(coords[j]));points.push(p);}
components.push(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]));}}
if(this.internalProjection&&this.externalProjection){for(var i=0,ii=components.length;i<ii;i++){if(components[i]){components[i].transform(this.externalProjection,this.internalProjection);}}}
return components;},parsePersonConstructs:function(node,name,data){var persons=[];var atomns=this.namespaces.atom;var nodes=this.getElementsByTagNameNS(node,atomns,name);var oAtts=["uri","email"];for(var i=0,ii=nodes.length;i<ii;i++){var value={};value.name=this.getFirstChildValue(nodes[i],atomns,"name",null);for(var j=0,jj=oAtts.length;j<jj;j++){var attval=this.getFirstChildValue(nodes[i],atomns,oAtts[j],null);if(attval){value[oAtts[j]]=attval;}}
persons.push(value);}
if(persons.length>0){data[name+"s"]=persons;}},CLASS_NAME:"OpenLayers.Format.Atom"});OpenLayers.Format.Filter.v1_0_0=OpenLayers.Class(OpenLayers.Format.GML.v2,OpenLayers.Format.Filter.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",initialize:function(options){OpenLayers.Format.GML.v2.prototype.initialize.apply(this,[options]);},readers:{"ogc":OpenLayers.Util.applyDefaults({"PropertyIsEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsNotEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLike":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(node,filter);var wildCard=node.getAttribute("wildCard");var singleChar=node.getAttribute("singleChar");var esc=node.getAttribute("escape");filter.value2regex(wildCard,singleChar,esc);obj.filters.push(filter);}},OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),"gml":OpenLayers.Format.GML.v2.prototype.readers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.readers["feature"]},writers:{"ogc":OpenLayers.Util.applyDefaults({"PropertyIsEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsEqualTo");this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsNotEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsNotEqualTo");this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsLike":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{wildCard:"*",singleChar:".",escape:"!"}});this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.regex2value(),node);return node;},"BBOX":function(filter){var node=this.createElementNSPlus("ogc:BBOX");this.writeNode("PropertyName",filter,node);var box=this.writeNode("gml:Box",filter.value,node);if(filter.projection){box.setAttribute("srsName",filter.projection);}
return node;}},OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),"gml":OpenLayers.Format.GML.v2.prototype.writers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.writers["feature"]},writeSpatial:function(filter,name){var node=this.createElementNSPlus("ogc:"+name);this.writeNode("PropertyName",filter,node);var child;if(filter.value instanceof OpenLayers.Geometry){child=this.writeNode("feature:_geometry",filter.value).firstChild;}else{child=this.writeNode("gml:Box",filter.value);}
if(filter.projection){child.setAttribute("srsName",filter.projection);}
node.appendChild(child);return node;},CLASS_NAME:"OpenLayers.Format.Filter.v1_0_0"});OpenLayers.Format.Filter.v1_1_0=OpenLayers.Class(OpenLayers.Format.GML.v3,OpenLayers.Format.Filter.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.1.0/filter.xsd",initialize:function(options){OpenLayers.Format.GML.v3.prototype.initialize.apply(this,[options]);},readers:{"ogc":OpenLayers.Util.applyDefaults({"PropertyIsEqualTo":function(node,obj){var matchCase=node.getAttribute("matchCase");var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,matchCase:!(matchCase==="false"||matchCase==="0")});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsNotEqualTo":function(node,obj){var matchCase=node.getAttribute("matchCase");var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO,matchCase:!(matchCase==="false"||matchCase==="0")});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLike":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(node,filter);var wildCard=node.getAttribute("wildCard");var singleChar=node.getAttribute("singleChar");var esc=node.getAttribute("escapeChar");filter.value2regex(wildCard,singleChar,esc);obj.filters.push(filter);}},OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),"gml":OpenLayers.Format.GML.v3.prototype.readers["gml"],"feature":OpenLayers.Format.GML.v3.prototype.readers["feature"]},writers:{"ogc":OpenLayers.Util.applyDefaults({"PropertyIsEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsEqualTo",{attributes:{matchCase:filter.matchCase}});this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsNotEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsNotEqualTo",{attributes:{matchCase:filter.matchCase}});this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.value,node);return node;},"PropertyIsLike":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{wildCard:"*",singleChar:".",escapeChar:"!"}});this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.regex2value(),node);return node;},"BBOX":function(filter){var node=this.createElementNSPlus("ogc:BBOX");this.writeNode("PropertyName",filter,node);var box=this.writeNode("gml:Envelope",filter.value);if(filter.projection){box.setAttribute("srsName",filter.projection);}
node.appendChild(box);return node;}},OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),"gml":OpenLayers.Format.GML.v3.prototype.writers["gml"],"feature":OpenLayers.Format.GML.v3.prototype.writers["feature"]},writeSpatial:function(filter,name){var node=this.createElementNSPlus("ogc:"+name);this.writeNode("PropertyName",filter,node);var child;if(filter.value instanceof OpenLayers.Geometry){child=this.writeNode("feature:_geometry",filter.value).firstChild;}else{child=this.writeNode("gml:Envelope",filter.value);}
if(filter.projection){child.setAttribute("srsName",filter.projection);}
node.appendChild(child);return node;},CLASS_NAME:"OpenLayers.Format.Filter.v1_1_0"});OpenLayers.Format.SOSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.SOSCapabilities,{namespaces:{ows:"http://www.opengis.net/ows/1.1",sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.options=options;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var capabilities={};this.readNode(data,capabilities);return capabilities;},readers:{"gml":OpenLayers.Util.applyDefaults({"name":function(node,obj){obj.name=this.getChildValue(node);},"TimePeriod":function(node,obj){obj.timePeriod={};this.readChildNodes(node,obj.timePeriod);},"beginPosition":function(node,timePeriod){timePeriod.beginPosition=this.getChildValue(node);},"endPosition":function(node,timePeriod){timePeriod.endPosition=this.getChildValue(node);}},OpenLayers.Format.GML.v3.prototype.readers["gml"]),"sos":{"Capabilities":function(node,obj){this.readChildNodes(node,obj);},"Contents":function(node,obj){obj.contents={};this.readChildNodes(node,obj.contents);},"ObservationOfferingList":function(node,contents){contents.offeringList={};this.readChildNodes(node,contents.offeringList);},"ObservationOffering":function(node,offeringList){var id=this.getAttributeNS(node,this.namespaces.gml,"id");offeringList[id]={procedures:[],observedProperties:[],featureOfInterestIds:[],responseFormats:[],resultModels:[],responseModes:[]};this.readChildNodes(node,offeringList[id]);},"time":function(node,offering){offering.time={};this.readChildNodes(node,offering.time);},"procedure":function(node,offering){offering.procedures.push(this.getAttributeNS(node,this.namespaces.xlink,"href"));},"observedProperty":function(node,offering){offering.observedProperties.push(this.getAttributeNS(node,this.namespaces.xlink,"href"));},"featureOfInterest":function(node,offering){offering.featureOfInterestIds.push(this.getAttributeNS(node,this.namespaces.xlink,"href"));},"responseFormat":function(node,offering){offering.responseFormats.push(this.getChildValue(node));},"resultModel":function(node,offering){offering.resultModels.push(this.getChildValue(node));},"responseMode":function(node,offering){offering.responseModes.push(this.getChildValue(node));;}},"ows":OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"]},CLASS_NAME:"OpenLayers.Format.SOSCapabilities.v1_0_0"});OpenLayers.Format.SOSGetFeatureOfInterest=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",sa:"http://www.opengis.net/sampling/1.0",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd",defaultPrefix:"sos",regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var info={features:[]};this.readNode(data,info);var features=[];for(var i=0,len=info.features.length;i<len;i++){var container=info.features[i];if(this.internalProjection&&this.externalProjection&&container.components[0]){container.components[0].transform(this.externalProjection,this.internalProjection);}
var feature=new OpenLayers.Feature.Vector(container.components[0],container.attributes);features.push(feature);}
return features;},readers:{"sa":{"SamplingPoint":function(node,obj){if(!obj.attributes){var feature={attributes:{}};obj.features.push(feature);obj=feature;}
obj.attributes.id=this.getAttributeNS(node,this.namespaces.gml,"id");this.readChildNodes(node,obj);},"position":function(node,obj){this.readChildNodes(node,obj);}},"gml":OpenLayers.Util.applyDefaults({"FeatureCollection":function(node,obj){this.readChildNodes(node,obj);},"featureMember":function(node,obj){var feature={attributes:{}};obj.features.push(feature);this.readChildNodes(node,feature);},"name":function(node,obj){obj.attributes.name=this.getChildValue(node);},"pos":function(node,obj){if(!this.externalProjection){this.externalProjection=new OpenLayers.Projection(node.getAttribute("srsName"));}
OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[node,obj]);}},OpenLayers.Format.GML.v3.prototype.readers.gml)},writers:{"sos":{"GetFeatureOfInterest":function(options){var node=this.createElementNSPlus("GetFeatureOfInterest",{attributes:{version:this.VERSION,service:'SOS',"xsi:schemaLocation":this.schemaLocation}});for(var i=0,len=options.fois.length;i<len;i++){this.writeNode("FeatureOfInterestId",{foi:options.fois[i]},node);}
return node;},"FeatureOfInterestId":function(options){var node=this.createElementNSPlus("FeatureOfInterestId",{value:options.foi});return node;}}},CLASS_NAME:"OpenLayers.Format.SOSGetFeatureOfInterest"});OpenLayers.Format.SOSGetObservation=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows",gml:"http://www.opengis.net/gml",sos:"http://www.opengis.net/sos/1.0",ogc:"http://www.opengis.net/ogc",om:"http://www.opengis.net/om/1.0",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd",defaultPrefix:"sos",initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var info={measurements:[]};this.readNode(data,info);return info;},write:function(options){var node=this.writeNode("sos:GetObservation",options);node.setAttribute("xmlns:om",this.namespaces.om);this.setAttributeNS(node,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[node]);},readers:{"om":{"ObservationCollection":function(node,obj){obj.id=this.getAttributeNS(node,this.namespaces.gml,"id");this.readChildNodes(node,obj);},"member":function(node,observationCollection){this.readChildNodes(node,observationCollection);},"Measurement":function(node,observationCollection){var measurement={};observationCollection.measurements.push(measurement);this.readChildNodes(node,measurement);},"samplingTime":function(node,measurement){var samplingTime={};measurement.samplingTime=samplingTime;this.readChildNodes(node,samplingTime);},"observedProperty":function(node,measurement){measurement.observedProperty=this.getAttributeNS(node,this.namespaces.xlink,"href");this.readChildNodes(node,measurement);},"procedure":function(node,measurement){measurement.procedure=this.getAttributeNS(node,this.namespaces.xlink,"href");this.readChildNodes(node,measurement);},"result":function(node,measurement){var result={};measurement.result=result;if(this.getChildValue(node)!==''){result.value=this.getChildValue(node);result.uom=node.getAttribute("uom");}else{this.readChildNodes(node,result);}}},"gml":OpenLayers.Util.applyDefaults({"TimeInstant":function(node,samplingTime){var timeInstant={};samplingTime.timeInstant=timeInstant;this.readChildNodes(node,timeInstant);},"timePosition":function(node,timeInstant){timeInstant.timePosition=this.getChildValue(node);}},OpenLayers.Format.GML.v3.prototype.readers.gml)},writers:{"sos":{"GetObservation":function(options){var node=this.createElementNSPlus("GetObservation",{attributes:{version:this.VERSION,service:'SOS'}});this.writeNode("offering",options,node);this.writeNode("eventTime",options,node);this.writeNode("procedure",options,node);this.writeNode("observedProperty",options,node);this.writeNode("responseFormat",options,node);this.writeNode("resultModel",options,node);this.writeNode("responseMode",options,node);return node;},"responseFormat":function(options){return this.createElementNSPlus("responseFormat",{value:options.responseFormat});},"procedure":function(options){return this.createElementNSPlus("procedure",{value:options.procedure});},"offering":function(options){return this.createElementNSPlus("offering",{value:options.offering});},"observedProperty":function(options){return this.createElementNSPlus("observedProperty",{value:options.observedProperty});},"eventTime":function(options){var node=this.createElementNSPlus("eventTime");if(options.eventTime==='latest'){this.writeNode("ogc:TM_Equals",options,node);}
return node;},"resultModel":function(options){return this.createElementNSPlus("resultModel",{value:options.resultModel});},"responseMode":function(options){return this.createElementNSPlus("responseMode",{value:options.responseMode});}},"ogc":{"TM_Equals":function(options){var node=this.createElementNSPlus("ogc:TM_Equals");this.writeNode("ogc:PropertyName",{property:"urn:ogc:data:time:iso8601"},node);if(options.eventTime==='latest'){this.writeNode("gml:TimeInstant",{value:'latest'},node);}
return node;},"PropertyName":function(options){return this.createElementNSPlus("ogc:PropertyName",{value:options.property});}},"gml":{"TimeInstant":function(options){var node=this.createElementNSPlus("gml:TimeInstant");this.writeNode("gml:timePosition",options,node);return node;},"timePosition":function(options){var node=this.createElementNSPlus("gml:timePosition",{value:options.value});return node;}}},CLASS_NAME:"OpenLayers.Format.SOSGetObservation"});OpenLayers.Format.CSWGetRecords.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",csw:"http://www.opengis.net/cat/csw/2.0.2",dc:"http://purl.org/dc/elements/1.1/",dct:"http://purl.org/dc/terms/",ows:"http://www.opengis.net/ows"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",requestId:null,resultType:null,outputFormat:null,outputSchema:null,startPosition:null,maxRecords:null,DistributedSearch:null,ResponseHandler:null,Query:null,regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var obj={};this.readNode(data,obj);return obj;},readers:{"csw":{"GetRecordsResponse":function(node,obj){obj.records=[];this.readChildNodes(node,obj);var version=this.getAttributeNS(node,"",'version');if(version!=""){obj.version=version;}},"RequestId":function(node,obj){obj.RequestId=this.getChildValue(node);},"SearchStatus":function(node,obj){obj.SearchStatus={};var timestamp=this.getAttributeNS(node,"",'timestamp');if(timestamp!=""){obj.SearchStatus.timestamp=timestamp;}},"SearchResults":function(node,obj){this.readChildNodes(node,obj);var attrs=node.attributes;var SearchResults={};for(var i=0,len=attrs.length;i<len;++i){if((attrs[i].name=="numberOfRecordsMatched")||(attrs[i].name=="numberOfRecordsReturned")||(attrs[i].name=="nextRecord")){SearchResults[attrs[i].name]=parseInt(attrs[i].nodeValue);}else{SearchResults[attrs[i].name]=attrs[i].nodeValue;}}
obj.SearchResults=SearchResults;},"SummaryRecord":function(node,obj){var record={type:"SummaryRecord"};this.readChildNodes(node,record);obj.records.push(record);},"BriefRecord":function(node,obj){var record={type:"BriefRecord"};this.readChildNodes(node,record);obj.records.push(record);},"DCMIRecord":function(node,obj){var record={type:"DCMIRecord"};this.readChildNodes(node,record);obj.records.push(record);},"Record":function(node,obj){var record={type:"Record"};this.readChildNodes(node,record);obj.records.push(record);}},"dc":{"*":function(node,obj){var name=node.localName||node.nodeName.split(":").pop();if(!(obj[name]instanceof Array)){obj[name]=new Array();}
var dc_element={};var attrs=node.attributes;for(var i=0,len=attrs.length;i<len;++i){dc_element[attrs[i].name]=attrs[i].nodeValue;}
dc_element.value=this.getChildValue(node);obj[name].push(dc_element);}},"dct":{"*":function(node,obj){var name=node.localName||node.nodeName.split(":").pop();if(!(obj[name]instanceof Array)){obj[name]=new Array();}
obj[name].push(this.getChildValue(node));}},"ows":OpenLayers.Util.applyDefaults({"BoundingBox":function(node,obj){if(obj.bounds){obj.BoundingBox=[{crs:obj.projection,value:[obj.bounds.left,obj.bounds.bottom,obj.bounds.right,obj.bounds.top]}];delete obj.projection;delete obj.bounds;}
OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply(this,arguments);}},OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"])},write:function(options){var node=this.writeNode("csw:GetRecords",options);return OpenLayers.Format.XML.prototype.write.apply(this,[node]);},writers:{"csw":{"GetRecords":function(options){if(!options){options={};}
var node=this.createElementNSPlus("csw:GetRecords",{attributes:{service:"CSW",version:this.version,requestId:options.requestId||this.requestId,resultType:options.resultType||this.resultType,outputFormat:options.outputFormat||this.outputFormat,outputSchema:options.outputSchema||this.outputSchema,startPosition:options.startPosition||this.startPosition,maxRecords:options.maxRecords||this.maxRecords}});if(options.DistributedSearch||this.DistributedSearch){this.writeNode("csw:DistributedSearch",options.DistributedSearch||this.DistributedSearch,node);}
var ResponseHandler=options.ResponseHandler||this.ResponseHandler;if(ResponseHandler instanceof Array&&ResponseHandler.length>0){for(var i=0,len=ResponseHandler.length;i<len;i++){this.writeNode("csw:ResponseHandler",ResponseHandler[i],node);}}
this.writeNode("Query",options.Query||this.Query,node);return node;},"DistributedSearch":function(options){var node=this.createElementNSPlus("csw:DistributedSearch",{attributes:{hopCount:options.hopCount}});return node;},"ResponseHandler":function(options){var node=this.createElementNSPlus("csw:ResponseHandler",{value:options.value});return node;},"Query":function(options){if(!options){options={};}
var node=this.createElementNSPlus("csw:Query",{attributes:{typeNames:options.typeNames||"csw:Record"}});var ElementName=options.ElementName;if(ElementName instanceof Array&&ElementName.length>0){for(var i=0,len=ElementName.length;i<len;i++){this.writeNode("csw:ElementName",ElementName[i],node);}}else{this.writeNode("csw:ElementSetName",options.ElementSetName||{value:'summary'},node);}
if(options.Constraint){this.writeNode("csw:Constraint",options.Constraint,node);}
return node;},"ElementName":function(options){var node=this.createElementNSPlus("csw:ElementName",{value:options.value});return node;},"ElementSetName":function(options){var node=this.createElementNSPlus("csw:ElementSetName",{attributes:{typeNames:options.typeNames},value:options.value});return node;},"Constraint":function(options){var node=this.createElementNSPlus("csw:Constraint",{attributes:{version:options.version}});if(options.Filter){var format=new OpenLayers.Format.Filter({version:options.version});node.appendChild(format.write(options.Filter));}else if(options.CqlText){var child=this.createElementNSPlus("CqlText",{value:options.CqlText.value});node.appendChild(child);}
return node;}}},CLASS_NAME:"OpenLayers.Format.CSWGetRecords.v2_0_2"});OpenLayers.Format.SLD.v1=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,{namespaces:{sld:"http://www.opengis.net/sld",ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"sld",schemaLocation:null,multipleSymbolizers:false,featureTypeCounter:null,defaultSymbolizer:{fillColor:"#808080",fillOpacity:1,strokeColor:"#000000",strokeOpacity:1,strokeWidth:1,strokeDashstyle:"solid",pointRadius:3,graphicName:"square"},initialize:function(options){OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this,[options]);},read:function(data,options){options=OpenLayers.Util.applyDefaults(options,this.options);var sld={namedLayers:options.namedLayersAsArray===true?[]:{}};this.readChildNodes(data,sld);return sld;},readers:OpenLayers.Util.applyDefaults({"sld":{"StyledLayerDescriptor":function(node,sld){sld.version=node.getAttribute("version");this.readChildNodes(node,sld);},"Name":function(node,obj){obj.name=this.getChildValue(node);},"Title":function(node,obj){obj.title=this.getChildValue(node);},"Abstract":function(node,obj){obj.description=this.getChildValue(node);},"NamedLayer":function(node,sld){var layer={userStyles:[],namedStyles:[]};this.readChildNodes(node,layer);for(var i=0,len=layer.userStyles.length;i<len;++i){layer.userStyles[i].layerName=layer.name;}
if(sld.namedLayers instanceof Array){sld.namedLayers.push(layer);}else{sld.namedLayers[layer.name]=layer;}},"NamedStyle":function(node,layer){layer.namedStyles.push(this.getChildName(node.firstChild));},"UserStyle":function(node,layer){var obj={defaultsPerSymbolizer:true,rules:[]};this.featureTypeCounter=-1;this.readChildNodes(node,obj);var style;if(this.multipleSymbolizers){delete obj.defaultsPerSymbolizer;style=new OpenLayers.Style2(obj);}else{style=new OpenLayers.Style(this.defaultSymbolizer,obj);}
layer.userStyles.push(style);},"IsDefault":function(node,style){if(this.getChildValue(node)=="1"){style.isDefault=true;}},"FeatureTypeStyle":function(node,style){++this.featureTypeCounter;var obj={rules:this.multipleSymbolizers?style.rules:[]};this.readChildNodes(node,obj);if(!this.multipleSymbolizers){style.rules=obj.rules;}},"Rule":function(node,obj){var config;if(this.multipleSymbolizers){config={symbolizers:[]};}
var rule=new OpenLayers.Rule(config);this.readChildNodes(node,rule);obj.rules.push(rule);},"ElseFilter":function(node,rule){rule.elseFilter=true;},"MinScaleDenominator":function(node,rule){rule.minScaleDenominator=parseFloat(this.getChildValue(node));},"MaxScaleDenominator":function(node,rule){rule.maxScaleDenominator=parseFloat(this.getChildValue(node));},"TextSymbolizer":function(node,rule){var config={};this.readChildNodes(node,config);if(this.multipleSymbolizers){config.zIndex=this.featureTypeCounter;rule.symbolizers.push(new OpenLayers.Symbolizer.Text(config));}else{rule.symbolizer["Text"]=OpenLayers.Util.applyDefaults(config,rule.symbolizer["Text"]);}},"Label":function(node,symbolizer){var obj={};this.readChildNodes(node,obj);if(obj.property){symbolizer.label="${"+obj.property+"}";}else{var value=this.readOgcExpression(node);if(value){symbolizer.label=value;}}},"Font":function(node,symbolizer){this.readChildNodes(node,symbolizer);},"Halo":function(node,symbolizer){var obj={};this.readChildNodes(node,obj);symbolizer.haloRadius=obj.haloRadius;symbolizer.haloColor=obj.fillColor;symbolizer.haloOpacity=obj.fillOpacity;},"Radius":function(node,symbolizer){var radius=this.readOgcExpression(node);if(radius!=null){symbolizer.haloRadius=radius;}},"RasterSymbolizer":function(node,rule){var config={};this.readChildNodes(node,config);if(this.multipleSymbolizers){config.zIndex=this.featureTypeCounter;rule.symbolizers.push(new OpenLayers.Symbolizer.Raster(config));}else{rule.symbolizer["Raster"]=OpenLayers.Util.applyDefaults(config,rule.symbolizer["Raster"]);}},"Geometry":function(node,obj){obj.geometry={};this.readChildNodes(node,obj.geometry);},"ColorMap":function(node,symbolizer){symbolizer.colorMap=[];this.readChildNodes(node,symbolizer.colorMap);},"ColorMapEntry":function(node,colorMap){var q=node.getAttribute("quantity");var o=node.getAttribute("opacity");colorMap.push({color:node.getAttribute("color"),quantity:q!==null?parseFloat(q):undefined,label:node.getAttribute("label")||undefined,opacity:o!==null?parseFloat(o):undefined});},"LineSymbolizer":function(node,rule){var config={};this.readChildNodes(node,config);if(this.multipleSymbolizers){config.zIndex=this.featureTypeCounter;rule.symbolizers.push(new OpenLayers.Symbolizer.Line(config));}else{rule.symbolizer["Line"]=OpenLayers.Util.applyDefaults(config,rule.symbolizer["Line"]);}},"PolygonSymbolizer":function(node,rule){var config={fill:false,stroke:false};if(!this.multipleSymbolizers){config=rule.symbolizer["Polygon"]||config;}
this.readChildNodes(node,config);if(this.multipleSymbolizers){config.zIndex=this.featureTypeCounter;rule.symbolizers.push(new OpenLayers.Symbolizer.Polygon(config));}else{rule.symbolizer["Polygon"]=config;}},"PointSymbolizer":function(node,rule){var config={fill:false,stroke:false,graphic:false};if(!this.multipleSymbolizers){config=rule.symbolizer["Point"]||config;}
this.readChildNodes(node,config);if(this.multipleSymbolizers){config.zIndex=this.featureTypeCounter;rule.symbolizers.push(new OpenLayers.Symbolizer.Point(config));}else{rule.symbolizer["Point"]=config;}},"Stroke":function(node,symbolizer){symbolizer.stroke=true;this.readChildNodes(node,symbolizer);},"Fill":function(node,symbolizer){symbolizer.fill=true;this.readChildNodes(node,symbolizer);},"CssParameter":function(node,symbolizer){var cssProperty=node.getAttribute("name");var symProperty=this.cssMap[cssProperty];if(symProperty){var value=this.readOgcExpression(node);if(value){symbolizer[symProperty]=value;}}},"Graphic":function(node,symbolizer){symbolizer.graphic=true;var graphic={};this.readChildNodes(node,graphic);var properties=["stroke","strokeColor","strokeWidth","strokeOpacity","strokeLinecap","fill","fillColor","fillOpacity","graphicName","rotation","graphicFormat"];var prop,value;for(var i=0,len=properties.length;i<len;++i){prop=properties[i];value=graphic[prop];if(value!=undefined){symbolizer[prop]=value;}}
if(graphic.opacity!=undefined){symbolizer.graphicOpacity=graphic.opacity;}
if(graphic.size!=undefined){symbolizer.pointRadius=graphic.size/2;}
if(graphic.href!=undefined){symbolizer.externalGraphic=graphic.href;}
if(graphic.rotation!=undefined){symbolizer.rotation=graphic.rotation;}},"ExternalGraphic":function(node,graphic){this.readChildNodes(node,graphic);},"Mark":function(node,graphic){this.readChildNodes(node,graphic);},"WellKnownName":function(node,graphic){graphic.graphicName=this.getChildValue(node);},"Opacity":function(node,obj){var opacity=this.readOgcExpression(node);if(opacity){obj.opacity=opacity;}},"Size":function(node,obj){var size=this.readOgcExpression(node);if(size){obj.size=size;}},"Rotation":function(node,obj){var rotation=this.readOgcExpression(node);if(rotation){obj.rotation=rotation;}},"OnlineResource":function(node,obj){obj.href=this.getAttributeNS(node,this.namespaces.xlink,"href");},"Format":function(node,graphic){graphic.graphicFormat=this.getChildValue(node);}}},OpenLayers.Format.Filter.v1_0_0.prototype.readers),cssMap:{"stroke":"strokeColor","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","stroke-dasharray":"strokeDashstyle","fill":"fillColor","fill-opacity":"fillOpacity","font-family":"fontFamily","font-size":"fontSize","font-weight":"fontWeight","font-style":"fontStyle"},getCssProperty:function(sym){var css=null;for(var prop in this.cssMap){if(this.cssMap[prop]==sym){css=prop;break;}}
return css;},getGraphicFormat:function(href){var format,regex;for(var key in this.graphicFormats){if(this.graphicFormats[key].test(href)){format=key;break;}}
return format||this.defautlGraphicFormat;},defaultGraphicFormat:"image/png",graphicFormats:{"image/jpeg":/\.jpe?g$/i,"image/gif":/\.gif$/i,"image/png":/\.png$/i},write:function(sld){return this.writers.sld.StyledLayerDescriptor.apply(this,[sld]);},writers:OpenLayers.Util.applyDefaults({"sld":{"StyledLayerDescriptor":function(sld){var root=this.createElementNSPlus("sld:StyledLayerDescriptor",{attributes:{"version":this.VERSION,"xsi:schemaLocation":this.schemaLocation}});root.setAttribute("xmlns:ogc",this.namespaces.ogc);root.setAttribute("xmlns:gml",this.namespaces.gml);if(sld.name){this.writeNode("Name",sld.name,root);}
if(sld.title){this.writeNode("Title",sld.title,root);}
if(sld.description){this.writeNode("Abstract",sld.description,root);}
if(sld.namedLayers instanceof Array){for(var i=0,len=sld.namedLayers.length;i<len;++i){this.writeNode("NamedLayer",sld.namedLayers[i],root);}}else{for(var name in sld.namedLayers){this.writeNode("NamedLayer",sld.namedLayers[name],root);}}
return root;},"Name":function(name){return this.createElementNSPlus("sld:Name",{value:name});},"Title":function(title){return this.createElementNSPlus("sld:Title",{value:title});},"Abstract":function(description){return this.createElementNSPlus("sld:Abstract",{value:description});},"NamedLayer":function(layer){var node=this.createElementNSPlus("sld:NamedLayer");this.writeNode("Name",layer.name,node);if(layer.namedStyles){for(var i=0,len=layer.namedStyles.length;i<len;++i){this.writeNode("NamedStyle",layer.namedStyles[i],node);}}
if(layer.userStyles){for(var i=0,len=layer.userStyles.length;i<len;++i){this.writeNode("UserStyle",layer.userStyles[i],node);}}
return node;},"NamedStyle":function(name){var node=this.createElementNSPlus("sld:NamedStyle");this.writeNode("Name",name,node);return node;},"UserStyle":function(style){var node=this.createElementNSPlus("sld:UserStyle");if(style.name){this.writeNode("Name",style.name,node);}
if(style.title){this.writeNode("Title",style.title,node);}
if(style.description){this.writeNode("Abstract",style.description,node);}
if(style.isDefault){this.writeNode("IsDefault",style.isDefault,node);}
if(this.multipleSymbolizers&&style.rules){var rulesByZ={0:[]};var zValues=[0];var rule,ruleMap,symbolizer,zIndex,clone;for(var i=0,ii=style.rules.length;i<ii;++i){rule=style.rules[i];if(rule.symbolizers){ruleMap={};for(var j=0,jj=rule.symbolizers.length;j<jj;++j){symbolizer=rule.symbolizers[j];zIndex=symbolizer.zIndex;if(!(zIndex in ruleMap)){clone=rule.clone();clone.symbolizers=[];ruleMap[zIndex]=clone;}
ruleMap[zIndex].symbolizers.push(symbolizer.clone());}
for(zIndex in ruleMap){if(!(zIndex in rulesByZ)){zValues.push(zIndex);rulesByZ[zIndex]=[];}
rulesByZ[zIndex].push(ruleMap[zIndex]);}}else{rulesByZ[0].push(rule.clone());}}
zValues.sort();var rules;for(var i=0,ii=zValues.length;i<ii;++i){rules=rulesByZ[zValues[i]];if(rules.length>0){clone=style.clone();clone.rules=rulesByZ[zValues[i]];this.writeNode("FeatureTypeStyle",clone,node);}}}else{this.writeNode("FeatureTypeStyle",style,node);}
return node;},"IsDefault":function(bool){return this.createElementNSPlus("sld:IsDefault",{value:(bool)?"1":"0"});},"FeatureTypeStyle":function(style){var node=this.createElementNSPlus("sld:FeatureTypeStyle");for(var i=0,len=style.rules.length;i<len;++i){this.writeNode("Rule",style.rules[i],node);}
return node;},"Rule":function(rule){var node=this.createElementNSPlus("sld:Rule");if(rule.name){this.writeNode("Name",rule.name,node);}
if(rule.title){this.writeNode("Title",rule.title,node);}
if(rule.description){this.writeNode("Abstract",rule.description,node);}
if(rule.elseFilter){this.writeNode("ElseFilter",null,node);}else if(rule.filter){this.writeNode("ogc:Filter",rule.filter,node);}
if(rule.minScaleDenominator!=undefined){this.writeNode("MinScaleDenominator",rule.minScaleDenominator,node);}
if(rule.maxScaleDenominator!=undefined){this.writeNode("MaxScaleDenominator",rule.maxScaleDenominator,node);}
var type,symbolizer;if(this.multipleSymbolizers&&rule.symbolizers){var symbolizer;for(var i=0,ii=rule.symbolizers.length;i<ii;++i){symbolizer=rule.symbolizers[i];type=symbolizer.CLASS_NAME.split(".").pop();this.writeNode(type+"Symbolizer",symbolizer,node);}}else{var types=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var i=0,len=types.length;i<len;++i){type=types[i];symbolizer=rule.symbolizer[type];if(symbolizer){this.writeNode(type+"Symbolizer",symbolizer,node);}}}
return node;},"ElseFilter":function(){return this.createElementNSPlus("sld:ElseFilter");},"MinScaleDenominator":function(scale){return this.createElementNSPlus("sld:MinScaleDenominator",{value:scale});},"MaxScaleDenominator":function(scale){return this.createElementNSPlus("sld:MaxScaleDenominator",{value:scale});},"LineSymbolizer":function(symbolizer){var node=this.createElementNSPlus("sld:LineSymbolizer");this.writeNode("Stroke",symbolizer,node);return node;},"Stroke":function(symbolizer){var node=this.createElementNSPlus("sld:Stroke");if(symbolizer.strokeColor!=undefined){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"strokeColor"},node);}
if(symbolizer.strokeOpacity!=undefined){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"strokeOpacity"},node);}
if(symbolizer.strokeWidth!=undefined){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"strokeWidth"},node);}
if(symbolizer.strokeDashstyle!=undefined&&symbolizer.strokeDashstyle!=="solid"){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"strokeDashstyle"},node);}
if(symbolizer.strokeLinecap!=undefined){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"strokeLinecap"},node);}
return node;},"CssParameter":function(obj){return this.createElementNSPlus("sld:CssParameter",{attributes:{name:this.getCssProperty(obj.key)},value:obj.symbolizer[obj.key]});},"TextSymbolizer":function(symbolizer){var node=this.createElementNSPlus("sld:TextSymbolizer");if(symbolizer.label!=null){this.writeNode("Label",symbolizer.label,node);}
if(symbolizer.fontFamily!=null||symbolizer.fontSize!=null||symbolizer.fontWeight!=null||symbolizer.fontStyle!=null){this.writeNode("Font",symbolizer,node);}
if(symbolizer.haloRadius!=null||symbolizer.haloColor!=null||symbolizer.haloOpacity!=null){this.writeNode("Halo",symbolizer,node);}
if(symbolizer.fillColor!=null||symbolizer.fillOpacity!=null){this.writeNode("Fill",symbolizer,node);}
return node;},"Font":function(symbolizer){var node=this.createElementNSPlus("sld:Font");if(symbolizer.fontFamily){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"fontFamily"},node);}
if(symbolizer.fontSize){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"fontSize"},node);}
if(symbolizer.fontWeight){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"fontWeight"},node);}
if(symbolizer.fontStyle){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"fontStyle"},node);}
return node;},"Label":function(label){var node=this.createElementNSPlus("sld:Label");var tokens=label.split("${");node.appendChild(this.createTextNode(tokens[0]));var item,last;for(var i=1,len=tokens.length;i<len;i++){item=tokens[i];last=item.indexOf("}");if(last>0){this.writeNode("ogc:PropertyName",{property:item.substring(0,last)},node);node.appendChild(this.createTextNode(item.substring(++last)));}else{node.appendChild(this.createTextNode("${"+item));}}
return node;},"Halo":function(symbolizer){var node=this.createElementNSPlus("sld:Halo");if(symbolizer.haloRadius){this.writeNode("Radius",symbolizer.haloRadius,node);}
if(symbolizer.haloColor||symbolizer.haloOpacity){this.writeNode("Fill",{fillColor:symbolizer.haloColor,fillOpacity:symbolizer.haloOpacity},node);}
return node;},"Radius":function(value){return this.createElementNSPlus("sld:Radius",{value:value});},"RasterSymbolizer":function(symbolizer){var node=this.createElementNSPlus("sld:RasterSymbolizer");if(symbolizer.geometry){this.writeNode("Geometry",symbolizer.geometry,node);}
if(symbolizer.opacity){this.writeNode("Opacity",symbolizer.opacity,node);}
if(symbolizer.colorMap){this.writeNode("ColorMap",symbolizer.colorMap,node);}
return node;},"Geometry":function(geometry){var node=this.createElementNSPlus("sld:Geometry");if(geometry.property){this.writeNode("ogc:PropertyName",geometry,node);}
return node;},"ColorMap":function(colorMap){var node=this.createElementNSPlus("sld:ColorMap");for(var i=0,len=colorMap.length;i<len;++i){this.writeNode("ColorMapEntry",colorMap[i],node);}
return node;},"ColorMapEntry":function(colorMapEntry){var node=this.createElementNSPlus("sld:ColorMapEntry");var a=colorMapEntry;node.setAttribute("color",a.color);a.opacity!==undefined&&node.setAttribute("opacity",parseFloat(a.opacity));a.quantity!==undefined&&node.setAttribute("quantity",parseFloat(a.quantity));a.label!==undefined&&node.setAttribute("label",a.label);return node;},"PolygonSymbolizer":function(symbolizer){var node=this.createElementNSPlus("sld:PolygonSymbolizer");if(symbolizer.fill!==false){this.writeNode("Fill",symbolizer,node);}
if(symbolizer.stroke!==false){this.writeNode("Stroke",symbolizer,node);}
return node;},"Fill":function(symbolizer){var node=this.createElementNSPlus("sld:Fill");if(symbolizer.fillColor){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"fillColor"},node);}
if(symbolizer.fillOpacity!=null){this.writeNode("CssParameter",{symbolizer:symbolizer,key:"fillOpacity"},node);}
return node;},"PointSymbolizer":function(symbolizer){var node=this.createElementNSPlus("sld:PointSymbolizer");this.writeNode("Graphic",symbolizer,node);return node;},"Graphic":function(symbolizer){var node=this.createElementNSPlus("sld:Graphic");if(symbolizer.externalGraphic!=undefined){this.writeNode("ExternalGraphic",symbolizer,node);}else{this.writeNode("Mark",symbolizer,node);}
if(symbolizer.graphicOpacity!=undefined){this.writeNode("Opacity",symbolizer.graphicOpacity,node);}
if(symbolizer.pointRadius!=undefined){this.writeNode("Size",symbolizer.pointRadius*2,node);}
if(symbolizer.rotation!=undefined){this.writeNode("Rotation",symbolizer.rotation,node);}
return node;},"ExternalGraphic":function(symbolizer){var node=this.createElementNSPlus("sld:ExternalGraphic");this.writeNode("OnlineResource",symbolizer.externalGraphic,node);var format=symbolizer.graphicFormat||this.getGraphicFormat(symbolizer.externalGraphic);this.writeNode("Format",format,node);return node;},"Mark":function(symbolizer){var node=this.createElementNSPlus("sld:Mark");if(symbolizer.graphicName){this.writeNode("WellKnownName",symbolizer.graphicName,node);}
if(symbolizer.fill!==false){this.writeNode("Fill",symbolizer,node);}
if(symbolizer.stroke!==false){this.writeNode("Stroke",symbolizer,node);}
return node;},"WellKnownName":function(name){return this.createElementNSPlus("sld:WellKnownName",{value:name});},"Opacity":function(value){return this.createElementNSPlus("sld:Opacity",{value:value});},"Size":function(value){return this.createElementNSPlus("sld:Size",{value:value});},"Rotation":function(value){return this.createElementNSPlus("sld:Rotation",{value:value});},"OnlineResource":function(href){return this.createElementNSPlus("sld:OnlineResource",{attributes:{"xlink:type":"simple","xlink:href":href}});},"Format":function(format){return this.createElementNSPlus("sld:Format",{value:format});}}},OpenLayers.Format.Filter.v1_0_0.prototype.writers),CLASS_NAME:"OpenLayers.Format.SLD.v1"});OpenLayers.Format.WFST.v1_0_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,OpenLayers.Format.WFST.v1,{version:"1.0.0",srsNameInQuery:false,schemaLocations:{"wfs":"http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"},initialize:function(options){OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this,[options]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[options]);},readers:{"wfs":OpenLayers.Util.applyDefaults({"WFS_TransactionResponse":function(node,obj){obj.insertIds=[];obj.success=false;this.readChildNodes(node,obj);},"InsertResult":function(node,container){var obj={fids:[]};this.readChildNodes(node,obj);container.insertIds.push(obj.fids[0]);},"TransactionResult":function(node,obj){this.readChildNodes(node,obj);},"Status":function(node,obj){this.readChildNodes(node,obj);},"SUCCESS":function(node,obj){obj.success=true;}},OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),"gml":OpenLayers.Format.GML.v2.prototype.readers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.readers["feature"],"ogc":OpenLayers.Format.Filter.v1_0_0.prototype.readers["ogc"]},writers:{"wfs":OpenLayers.Util.applyDefaults({"Query":function(options){options=OpenLayers.Util.extend({featureNS:this.featureNS,featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName,srsNameInQuery:this.srsNameInQuery},options);var node=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(options.featureNS?options.featurePrefix+":":"")+
options.featureType}});if(options.srsNameInQuery&&options.srsName){node.setAttribute("srsName",options.srsName);}
if(options.featureNS){node.setAttribute("xmlns:"+options.featurePrefix,options.featureNS);}
if(options.propertyNames){for(var i=0,len=options.propertyNames.length;i<len;i++){this.writeNode("ogc:PropertyName",{property:options.propertyNames[i]},node);}}
if(options.filter){this.setFilterProperty(options.filter);this.writeNode("ogc:Filter",options.filter,node);}
return node;}},OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),"gml":OpenLayers.Format.GML.v2.prototype.writers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.writers["feature"],"ogc":OpenLayers.Format.Filter.v1_0_0.prototype.writers["ogc"]},CLASS_NAME:"OpenLayers.Format.WFST.v1_0_0"});OpenLayers.Format.WFST.v1_1_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_1_0,OpenLayers.Format.WFST.v1,{version:"1.1.0",schemaLocations:{"wfs":"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"},initialize:function(options){OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this,[options]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[options]);},readers:{"wfs":OpenLayers.Util.applyDefaults({"FeatureCollection":function(node,obj){obj.numberOfFeatures=parseInt(node.getAttribute("numberOfFeatures"));OpenLayers.Format.WFST.v1.prototype.readers["wfs"]["FeatureCollection"].apply(this,arguments);},"TransactionResponse":function(node,obj){obj.insertIds=[];obj.success=false;this.readChildNodes(node,obj);},"TransactionSummary":function(node,obj){obj.success=true;},"InsertResults":function(node,obj){this.readChildNodes(node,obj);},"Feature":function(node,container){var obj={fids:[]};this.readChildNodes(node,obj);container.insertIds.push(obj.fids[0]);}},OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),"gml":OpenLayers.Format.GML.v3.prototype.readers["gml"],"feature":OpenLayers.Format.GML.v3.prototype.readers["feature"],"ogc":OpenLayers.Format.Filter.v1_1_0.prototype.readers["ogc"]},writers:{"wfs":OpenLayers.Util.applyDefaults({"GetFeature":function(options){var node=OpenLayers.Format.WFST.v1.prototype.writers["wfs"]["GetFeature"].apply(this,arguments);options&&options.resultType&&this.setAttributes(node,{resultType:options.resultType});return node;},"Query":function(options){options=OpenLayers.Util.extend({featureNS:this.featureNS,featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName},options);var node=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(options.featureNS?options.featurePrefix+":":"")+
options.featureType,srsName:options.srsName}});if(options.featureNS){node.setAttribute("xmlns:"+options.featurePrefix,options.featureNS);}
if(options.propertyNames){for(var i=0,len=options.propertyNames.length;i<len;i++){this.writeNode("wfs:PropertyName",{property:options.propertyNames[i]},node);}}
if(options.filter){this.setFilterProperty(options.filter);this.writeNode("ogc:Filter",options.filter,node);}
return node;},"PropertyName":function(obj){return this.createElementNSPlus("wfs:PropertyName",{value:obj.property});}},OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),"gml":OpenLayers.Format.GML.v3.prototype.writers["gml"],"feature":OpenLayers.Format.GML.v3.prototype.writers["feature"],"ogc":OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"]},CLASS_NAME:"OpenLayers.Format.WFST.v1_1_0"});OpenLayers.Protocol.SOS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol,{fois:null,formatOptions:null,initialize:function(options){OpenLayers.Protocol.prototype.initialize.apply(this,[options]);if(!options.format){this.format=new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions);}},destroy:function(){if(this.options&&!this.options.format){this.format.destroy();}
this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this);},read:function(options){options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options||{});var response=new OpenLayers.Protocol.Response({requestType:"read"});var format=this.format;var data=OpenLayers.Format.XML.prototype.write.apply(format,[format.writeNode("sos:GetFeatureOfInterest",{fois:this.fois})]);response.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleRead,response,options),data:data});return response;},handleRead:function(response,options){if(options.callback){var request=response.priv;if(request.status>=200&&request.status<300){response.features=this.parseFeatures(request);response.code=OpenLayers.Protocol.Response.SUCCESS;}else{response.code=OpenLayers.Protocol.Response.FAILURE;}
options.callback.call(options.scope,response);}},parseFeatures:function(request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
if(!doc||doc.length<=0){return null;}
return this.format.read(doc);},CLASS_NAME:"OpenLayers.Protocol.SOS.v1_0_0"});OpenLayers.Format.SLD.v1_0_0=OpenLayers.Class(OpenLayers.Format.SLD.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",initialize:function(options){OpenLayers.Format.SLD.v1.prototype.initialize.apply(this,[options]);},CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0"});OpenLayers.Protocol.WFS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.0.0",CLASS_NAME:"OpenLayers.Protocol.WFS.v1_0_0"});OpenLayers.Protocol.WFS.v1_1_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.1.0",CLASS_NAME:"OpenLayers.Protocol.WFS.v1_1_0"});OpenLayers.Format.OWSContext.v0_3_1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{owc:"http://www.opengis.net/ows-context",gml:"http://www.opengis.net/gml",kml:"http://www.opengis.net/kml/2.2",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},VERSION:"0.3.1",schemaLocation:"http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd",defaultPrefix:"owc",extractAttributes:true,xy:true,regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},featureNS:"http://mapserver.gis.umn.edu/mapserver",featureType:'vector',geometryName:'geometry',nestingLayerLookup:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this);},setNestingPath:function(l){if(l.layersContext){for(var i=0,len=l.layersContext.length;i<len;i++){var layerContext=l.layersContext[i];var nPath=[];var nTitle=l.title||"";if(l.metadata&&l.metadata.nestingPath){nPath=l.metadata.nestingPath.slice();}
if(nTitle!=""){nPath.push(nTitle);}
layerContext.metadata.nestingPath=nPath;if(layerContext.layersContext){this.setNestingPath(layerContext);}}}},decomposeNestingPath:function(nPath){var a=[];if(nPath instanceof Array){while(nPath.length>0){a.push(nPath.slice());nPath.pop();}
a.reverse();}
return a;},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
if(data&&data.nodeType==9){data=data.documentElement;}
var context={};this.readNode(data,context);this.setNestingPath({layersContext:context.layersContext});var layers=[];this.processLayer(layers,context);delete context.layersContext;context.layersContext=layers;return context;},processLayer:function(layerArray,layer){if(layer.layersContext){for(var i=0,len=layer.layersContext.length;i<len;i++){var l=layer.layersContext[i];layerArray.push(l);if(l.layersContext){this.processLayer(layerArray,l);}}}},write:function(context,options){var name="OWSContext";this.nestingLayerLookup={};options=options||{};OpenLayers.Util.applyDefaults(options,context);var root=this.writeNode(name,options);this.nestingLayerLookup=null;this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},readers:{"kml":{"Document":function(node,obj){obj.features=new OpenLayers.Format.KML({kmlns:this.namespaces.kml,extractStyles:true}).read(node);}},"owc":{"OWSContext":function(node,obj){this.readChildNodes(node,obj);},"General":function(node,obj){this.readChildNodes(node,obj);},"ResourceList":function(node,obj){this.readChildNodes(node,obj);},"Layer":function(node,obj){var layerContext={metadata:{},visibility:(node.getAttribute("hidden")!="1"),queryable:(node.getAttribute("queryable")=="1"),opacity:((node.getAttribute("opacity")!=null)?parseFloat(node.getAttribute("opacity")):null),name:node.getAttribute("name"),categoryLayer:(node.getAttribute("name")==null),formats:[],styles:[]};if(!obj.layersContext){obj.layersContext=[];}
obj.layersContext.push(layerContext);this.readChildNodes(node,layerContext);},"InlineGeometry":function(node,obj){obj.features=[];var elements=this.getElementsByTagNameNS(node,this.namespaces.gml,"featureMember");var el;if(elements.length>=1){el=elements[0];}
if(el&&el.firstChild){var featurenode=(el.firstChild.nextSibling)?el.firstChild.nextSibling:el.firstChild;this.setNamespace("feature",featurenode.namespaceURI);this.featureType=featurenode.localName||featurenode.nodeName.split(":").pop();this.readChildNodes(node,obj);}},"Server":function(node,obj){if((!obj.service&&!obj.version)||(obj.service!=OpenLayers.Format.Context.serviceTypes.WMS)){obj.service=node.getAttribute("service");obj.version=node.getAttribute("version");this.readChildNodes(node,obj);}},"Name":function(node,obj){obj.name=this.getChildValue(node);this.readChildNodes(node,obj);},"Title":function(node,obj){obj.title=this.getChildValue(node);this.readChildNodes(node,obj);},"StyleList":function(node,obj){this.readChildNodes(node,obj.styles);},"Style":function(node,obj){var style={};obj.push(style);this.readChildNodes(node,style);},"LegendURL":function(node,obj){var legend={};obj.legend=legend;this.readChildNodes(node,legend);},"OnlineResource":function(node,obj){obj.url=this.getAttributeNS(node,this.namespaces.xlink,"href");this.readChildNodes(node,obj);}},"ows":OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows,"gml":OpenLayers.Format.GML.v2.prototype.readers.gml,"sld":OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld,"feature":OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{"owc":{"OWSContext":function(options){var node=this.createElementNSPlus("OWSContext",{attributes:{version:this.VERSION,id:options.id||OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_")}});this.writeNode("General",options,node);this.writeNode("ResourceList",options,node);return node;},"General":function(options){var node=this.createElementNSPlus("General");this.writeNode("ows:BoundingBox",options,node);this.writeNode("ows:Title",options.title||'OpenLayers OWSContext',node);return node;},"ResourceList":function(options){var node=this.createElementNSPlus("ResourceList");for(var i=0,len=options.layers.length;i<len;i++){var layer=options.layers[i];var decomposedPath=this.decomposeNestingPath(layer.metadata.nestingPath);this.writeNode("_Layer",{layer:layer,subPaths:decomposedPath},node);}
return node;},"Server":function(options){var node=this.createElementNSPlus("Server",{attributes:{version:options.version,service:options.service}});this.writeNode("OnlineResource",options,node);return node;},"OnlineResource":function(options){var node=this.createElementNSPlus("OnlineResource",{attributes:{"xlink:href":options.url}});return node;},"InlineGeometry":function(layer){var node=this.createElementNSPlus("InlineGeometry");this.writeNode("gml:boundedBy",layer.getDataExtent(),node);for(var i=0,len=layer.features.length;i<len;i++){this.writeNode("gml:featureMember",layer.features[i],node);}
return node;},"StyleList":function(styles){var node=this.createElementNSPlus("StyleList");for(var i=0,len=styles.length;i<len;i++){this.writeNode("Style",styles[i],node);}
return node;},"Style":function(style){var node=this.createElementNSPlus("Style");this.writeNode("Name",style,node);this.writeNode("Title",style,node);this.writeNode("LegendURL",style,node);return node;},"Name":function(obj){var node=this.createElementNSPlus("Name",{value:obj.name});return node;},"Title":function(obj){var node=this.createElementNSPlus("Title",{value:obj.title});return node;},"LegendURL":function(style){var node=this.createElementNSPlus("LegendURL");this.writeNode("OnlineResource",style.legend,node);return node;},"_WMS":function(layer){var node=this.createElementNSPlus("Layer",{attributes:{name:layer.params.LAYERS,queryable:layer.queryable?"1":"0",hidden:layer.visibility?"0":"1",opacity:layer.opacity?layer.opacity:null}});this.writeNode("ows:Title",layer.name,node);this.writeNode("ows:OutputFormat",layer.params.FORMAT,node);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WMS,version:layer.params.VERSION,url:layer.url},node);if(layer.metadata.styles&&layer.metadata.styles.length>0){this.writeNode("StyleList",layer.metadata.styles,node);}
return node;},"_Layer":function(options){var layer,subPaths,node,title;layer=options.layer;subPaths=options.subPaths;node=null;title=null;if(subPaths.length>0){var path=subPaths[0].join("/");var index=path.lastIndexOf("/");node=this.nestingLayerLookup[path];title=(index>0)?path.substring(index+1,path.length):path;if(!node){node=this.createElementNSPlus("Layer");this.writeNode("ows:Title",title,node);this.nestingLayerLookup[path]=node;}
options.subPaths.shift();this.writeNode("_Layer",options,node);return node;}else{if(layer instanceof OpenLayers.Layer.WMS){node=this.writeNode("_WMS",layer);}else if(layer instanceof OpenLayers.Layer.Vector){if(layer.protocol instanceof OpenLayers.Protocol.WFS.v1){node=this.writeNode("_WFS",layer);}else if(layer.protocol instanceof OpenLayers.Protocol.HTTP){if(layer.protocol.format instanceof OpenLayers.Format.GML){layer.protocol.format.version="2.1.2";node=this.writeNode("_GML",layer);}else if(layer.protocol.format instanceof OpenLayers.Format.KML){layer.protocol.format.version="2.2";node=this.writeNode("_KML",layer);}}else{this.setNamespace("feature",this.featureNS);node=this.writeNode("_InlineGeometry",layer);}}
if(layer.options.maxScale){this.writeNode("sld:MinScaleDenominator",layer.options.maxScale,node);}
if(layer.options.minScale){this.writeNode("sld:MaxScaleDenominator",layer.options.minScale,node);}
this.nestingLayerLookup[layer.name]=node;return node;}},"_WFS":function(layer){var node=this.createElementNSPlus("Layer",{attributes:{name:layer.protocol.featurePrefix+":"+layer.protocol.featureType,hidden:layer.visibility?"0":"1"}});this.writeNode("ows:Title",layer.name,node);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WFS,version:layer.protocol.version,url:layer.protocol.url},node);return node;},"_InlineGeometry":function(layer){var node=this.createElementNSPlus("Layer",{attributes:{name:this.featureType,hidden:layer.visibility?"0":"1"}});this.writeNode("ows:Title",layer.name,node);this.writeNode("InlineGeometry",layer,node);return node;},"_GML":function(layer){var node=this.createElementNSPlus("Layer");this.writeNode("ows:Title",layer.name,node);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.GML,url:layer.protocol.url,version:layer.protocol.format.version},node);return node;},"_KML":function(layer){var node=this.createElementNSPlus("Layer");this.writeNode("ows:Title",layer.name,node);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.KML,version:layer.protocol.format.version,url:layer.protocol.url},node);return node;}},"gml":OpenLayers.Util.applyDefaults({"boundedBy":function(bounds){var node=this.createElementNSPlus("gml:boundedBy");this.writeNode("gml:Box",bounds,node);return node;}},OpenLayers.Format.GML.v2.prototype.writers.gml),"ows":OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows,"sld":OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld,"feature":OpenLayers.Format.GML.v2.prototype.writers.feature},CLASS_NAME:"OpenLayers.Format.OWSContext.v0_3_1"});
define.unordered = true;define('ripple', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var omgwtf = require('ripple/omgwtf'),
    db = require('ripple/db'),
    xhr = require('ripple/xhr'),
    geo = require('ripple/geo'),
    fileSystem = require('ripple/fileSystem'),
    fs = require('ripple/dbfs'),
    platform = require('ripple/platform'),
    emulatorBridge = require('ripple/emulatorBridge'),
    devices = require('ripple/devices'),
    widgetConfig = require('ripple/widgetConfig'),
    deviceSettings = require('ripple/deviceSettings'),
    sensorSettings = require('ripple/sensorSettings'),
    ui = require('ripple/ui'),
    appcache = require('ripple/appcache'),
    _self = {
        boot: function (booted) {
            // techdebt (event registration timing)
            // require('ripple/platform/webworks.core/2.0.0/fsCache');

            window.addEventListener("keydown", function (event) {
                var hasMetaOrAltPressed = (event.metaKey || event.ctrlKey),
                    key = parseInt(event.keyCode, 10);

                if (key === 37 && hasMetaOrAltPressed) { // cmd/ctrl + left arrow
                    event.preventDefault();
                    emulatorBridge.window().history.back();
                }

                if (key === 39 && hasMetaOrAltPressed) { // cmd/ctrl + right arrow
                    event.preventDefault();
                    emulatorBridge.window().history.forward();
                }

                if (key === 82 && hasMetaOrAltPressed) { // cmd/ctrl + r
                    event.preventDefault();
                    window.tinyHipposReload = true;
                    emulatorBridge.window().location.reload();
                }

                if (key === 116) { // F5
                    event.preventDefault();
                    window.tinyHipposReload = true;
                    emulatorBridge.window().location.reload();
                }
            });

            window.onbeforeunload = function () { 
                if (!window.tinyHipposReload) {
                    return "Are you sure you want to exit Ripple?";
                }
            };

            jWorkflow.order(omgwtf.initialize, omgwtf)
                 .andThen(appcache.initialize, appcache)
                 .andThen(db.initialize, db)
                 .andThen(xhr.initialize, xhr)
                 .andThen(geo.initialize, geo)
                 .andThen(fileSystem.initialize, fileSystem)
                 .andThen(fs.initialize, fs)
                 .andThen(platform.initialize, platform)
                 .andThen(devices.initialize, devices)
                 .andThen(widgetConfig.initialize, widgetConfig)
                 .andThen(deviceSettings.initialize, deviceSettings)
                 .andThen(ui.initialize, ui)
                 .start(booted);
        }
    };

module.exports = _self;

});
define('ripple/xhr/jsonp', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    helpers = require('ripple/xhr/helpers'),
    _console = require('ripple/console'),
    XHR = require('ripple/xhr/base');

function _XMLHttpRequest() {
    var xhr = new XHR(),
        origMethods = {
            setRequestHeader: xhr.setRequestHeader,
            getResponseHeader: xhr.getResponseHeader,
            getAllResponseHeaders: xhr.getAllResponseHeaders,
            open: xhr.open,
            send: xhr.send,
            abort: xhr.abort
        },
        _jxhr = new window.jXHR(),
        _sendFlag = false,
        _headers = [],
        _errorFlag = false,
        _url,
        _async;

    function _localURI() {
        return _url && helpers.isLocalRequest(_url);
    }

    function _set(prop, value) {
        xhr.__defineGetter__(prop, function () {
            return value;
        });
    }

    function _reset() {
        _set("response", "");
        _set("responseText", "");
        _set("responseXML", null);
    }

    xhr.setRequestHeader = function (header, value) {
        if (_localURI()) {
            origMethods.setRequestHeader.apply(xhr, Array.prototype.slice.call(arguments));
        } else {
            _console.error("XMLHttpRequest :: setRequestHeader does not work with JSONP.");
        }
    };

    xhr.getResponseHeader = function (header) {
        return _localURI() ?
                origMethods.getAllResponseHeaders.apply(xhr, [header]) :
                _headers[header] || null;
    };

    xhr.getAllResponseHeaders = function () {
        return _localURI() ?
                origMethods.getAllResponseHeaders.apply(xhr) :
                utils.reduce(_headers, function (str, value, key) {
                    return str + key + ": " + value + '\n';
                }, "").replace(/\n$/, '');
    };

    xhr.open = function (method, url, async) {
        _url = url;
        _async = async !== false ? true : false;

        if (_localURI()) {
            origMethods.open.apply(xhr, Array.prototype.slice.call(arguments));
        } else {
            _reset();
            method = method.toUpperCase();

            if (method === "POST") {
                //HACK: Switch the method to get for now to simulate post
                method = "GET";
            }

            if (method !== "GET") {
                exception.raise(exception.types.MethodNotImplemented, "Method: " + method + " not supported!");
            }

            _jxhr.onreadystatechange = function (data) {
                var response;

                try {
                    _set("readyState", _jxhr.readyState);

                    if (xhr.readyState === xhr.DONE) {
                        _sendFlag = false;
                        _set("status", data.status);
                        _set("statusText", data.statusText);
                        _headers = data.headers;

                        if (data.responseXML) {
                            response = new DOMParser().parseFromString(unescape(data.responseXML), "text/xml");
                            _set("responseXML", response);
                        } else {
                            response = unescape(data.responseText);
                            _set("responseText", response);
                        }

                        _set("response", response);
                    }

                    if (typeof xhr.onreadystatechange === "function") {
                        xhr.onreadystatechange.apply(xhr);
                    }
                } catch (e) {
                    exception.handle(e);
                }
            };

            _jxhr.onerror = xhr.onerror;
            _jxhr.open(method, constants.API_URL + "/jsonp_xhr_proxy?callback=?&tinyhippos_apikey=ABC&tinyhippos_rurl=" + escape(url));
        }
    };

    xhr.send = function (data) {
        if (_localURI()) {
            origMethods.send(data);
            return;
        }

        if (!_async) {
            exception.raise(exception.types.MethodNotImplemented, "Synchronous not supported.");
        }

        if (xhr.readyState !== xhr.OPENED || _sendFlag === true) {
            exception.raise(exception.types.InvalidState, "Ready state should be OPENED (1)");
        }

        _errorFlag = false;
        _sendFlag = true;
        data = null;

        _jxhr.send();
    };

    xhr.abort = function () {
        if (_localURI()) {
            origMethods.abort();
            return;
        }

        _reset();

        _errorFlag = true;

        if (xhr.readyState === xhr.UNSENT ||
                (xhr.readyState === xhr.OPENED && _sendFlag === false) ||
                xhr.readyState === xhr.DONE) {
            _set("readyState", xhr.UNSENT);
        } else {
            _set("readyState", xhr.DONE);
            _sendFlag = false;

            if (typeof xhr.onreadystatechange === "function") {
                xhr.onreadystatechange.apply(xhr);
            }
        }

        _jxhr.onreadystatechange = null;

        if (xhr.onabort) {
            xhr.onabort.apply(xhr, arguments);
        }
    };

    return xhr;
}

module.exports = _XMLHttpRequest;

});
define('ripple/xhr/cors', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var helpers = require('ripple/xhr/helpers'),
    constants = require('ripple/constants'),
    XHR = require('ripple/xhr/base');

function _XMLHttpRequest() {
    var xhr = new XHR(),
        origMethods = {
            setRequestHeader: xhr.setRequestHeader,
            open: xhr.open
        };

    xhr.setRequestHeader = function (header, value) {
        // This is done to get around jQuery 1.3.2 setting a header that it shouldn't
        if (header && header.toUpperCase() !== "X-REQUESTED-WITH") {
            origMethods.setRequestHeader.apply(xhr, Array.prototype.slice.call(arguments));
        }
    };

    xhr.open = function (method, url, async, user, password) {
        if (!helpers.isLocalRequest(url)) {
            url = constants.API_URL + "/xhr_proxy?tinyhippos_apikey=ABC&tinyhippos_rurl=" + escape(url);
        }

        origMethods.open.apply(xhr, Array.prototype.slice.call(arguments));
    };

    return xhr;
}

module.exports = _XMLHttpRequest;

});
define('ripple/xhr/helpers', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    db = require('ripple/db');

module.exports = {
    isLocalRequest: function (url) {
        return (!!(url.match(constants.REGEX.LOCAL_URI)) || !url.match(constants.REGEX.EXTERNAL_URI)) || 
                !!(location.host && url.match(location.host));
    },

    proxyEnabled: function () {
        var isDisabled = db.retrieve(constants.XHR.PROXY_DISABLED_BUTTON);
        return !isDisabled || isDisabled === "false" ? true : false;
    }
};

});
define('ripple/xhr/base', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var XHR = window.XMLHttpRequest;

function _handle(object, key) {
    return function () {
        return object[key].apply(object, Array.prototype.slice.call(arguments));
    };
}

function _getter(object, key) {
    return function () {
        return object[key];
    };
}

function _setter(object, key) {
    return function (val) {
        object[key] = val;
    };
}

function _writeable(obj) {
    var newObj = {},
        key;

    // need prototypes
    for (key in obj) {
        //HACK: don't even know what to say bout this, resonseBlob can go fly a kite: related to this issue:
        //https://github.com/blackberry/Ripple-UI/issues/394
        if (key !== "responseBlob" && typeof obj[key] === "function") {
            newObj[key] = _handle(obj, key);
        } else {
            newObj.__defineGetter__(key, _getter(obj, key));
            newObj.__defineSetter__(key, _setter(obj, key));
        }
    }

    return newObj;
}

function _XMLHttpRequest() {
    var Xhr = require('ripple/emulatorBridge').xhr() || XHR;
    return _writeable(new Xhr());
}

module.exports = _XMLHttpRequest;

});
define('ripple/devices/custom', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {
    "id": "CUSTOM",
    "name": "Custom",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",
    "firmware": "Generic",

    "screen": {
        "width": 600,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 600,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 600,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "browser": ["Generic"],
    "platforms": [],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/QVGA', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "QVGA",
    "name": "Generic - QVGA (240X320)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",

    "screen": {
        "width": 240,
        "height": 320
    },
    "viewPort": {
        "portrait": {
            "width": 240,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 320,
            "height": 240,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "platforms": ["web", "phonegap", "cordova", "tizen"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/Nexus7', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id" : "Nexus7",
    "name": "Nexus 7 (Tablet)",
    "manufacturer": "Asus",
    "model": "Nexus 7 8/16 GB",
    "osName": "Android",
    "uuid" : "903802EA-1786-4175-B0F1-1FDF87813CAA",
    "osVersion": "4.x.x",

    "screen": {
        "width": 800,
        "height": 1280
    },
    "viewPort": {
        "portrait": {
            "width": 800,
            "height": 1280,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 1280,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 215,
    "userAgent": "Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19",
    "platforms": ["web", "phonegap", "cordova"],

    "notes": {
        "1": "<a href=\"http://www.google.com/nexus/#/7/specs\" target=\"_blank\">Specs</a>"
    }

};

});
define('ripple/devices/Legend', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "Legend",
    "name": "HTC Legend",
    "osName": "Android",
    "osVersion": "1.6",
    "manufacturer": "HTC",
    "model": "Legend",
    "uuid": "6F196F23-FD0D-4F62-B27B-730147FCC5A3",

    "screen": {
        "width": 320,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 180.3,
    "userAgent": "Mozilla/5.0 (Linux; U; Android 2.1; fr-fr; HTC Legend 1.32.163.1 Build/ERD79) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
    "platforms": ["web", "phonegap"]
};

});
define('ripple/devices/NokiaN8', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "NokiaN8",
    "name": "Nokia N8",
    "model": "N8",
    "osName": "SymbianOS",
    "uuid": "42",
    "osVersion": "3",
    "manufacturer": "Nokia",

    "screen": {
        "width": 360,
        "height": 640
    },
    "viewPort": {
        "portrait": {
            "width": 360,
            "height": 640,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 640,
            "height": 360,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 209.8,
    "userAgent": "(Symbian/3; S60/5.2 Mozilla/5.0; NokiaN8-00/10.0.000; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.2",
    "platforms": ["web", "phonegap"],

    "notes": {
        "1": "<a href=\"http://www.forum.nokia.com/Devices/Device_specifications/N8-00/\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/Nexus', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "Nexus",
    "name": "Nexus One",
    "manufacturer": "HTC",
    "model": "Nexux One",
    "osName": "Android",
    "uuid": "6F196F23-FD0D-4F62-B27B-730147FCC5A3",
    "osVersion": "2.x.x",

    "screen": {
        "width": 480,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 800,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 252.15,
    "userAgent": "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
    "platforms": ["web", "phonegap"],

    "notes": {
        "1": "<a href=\"http://www.google.com/phone/static/en_US-nexusone_tech_specs.html\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/Playbook', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Playbook",
    "name": "BlackBerry Playbook",
    "model": "100669958",
    "osName": "BlackBerry PlayBook OS",
    "uuid": "42",
    "osVersion": "BlackBerry PlayBook OS",
    "manufacturer": "Research In Motion",

    "skin": "Playbook",

    "capabilities": [
        "input.touch",
        "location.gps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "network.bluetooth",
        "network.wlan"
    ],

    "screen": {
        "width": 1024,
        "height": 600
    },
    "viewPort": {
        "portrait": {
            "width": 1024,
            "height": 600,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 600,
            "height": 1024,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "defaultOrientation": "landscape",

    "ppi": 169.55,
    "userAgent": "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+",
    "platforms": ["web", "webworks.tablet", "phonegap", "cordova"]
};

});
define('ripple/devices/NokiaN97', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "NokiaN97",
    "name": "Nokia N97/5800 (touch)",
    "manufacturer": "Nokia",
    "model": "N97",
    "osName": "S60",
    "osVersion": "v5",
    "uuid": "42",

    "screen": {
        "width": 360,
        "height": 640
    },
    "viewPort": {
        "portrait": {
            "width": 360,
            "height": 640,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 640,
            "height": 360,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 232,
    "userAgent": "?",
    "platforms": ["web", "phonegap"]
};

});
define('ripple/devices/Torch9800', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Torch9800",
    "name": "BlackBerry Torch 9800",
    "model": "9800",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "6",
    "manufacturer": "Research In Motion",

    "skin": "Torch9800",

    "capabilities": [
        "input.touch",
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 360,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 360,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 360,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 188.68,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/6.0.0.141 Mobile Safari/534.1",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/G1', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "G1",
    "name": "HTC G1",
    "model": "G1",
    "osName": "Android",
    "osVersion": "1.6",
    "uuid": "6F196F23-FD0D-4F62-B27B-730147FCC5A3",
    "manufacturer": "HTC",

    "screen": {
        "width": 320,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 180.28,
    "platforms": ["web", "phonegap"],
    "userAgent": "Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",

    "notes": {
        "1": "<a href=\"http://www.htc.com/www/product/g1/specification.html\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/Bold9900', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Bold9900",
    "name": "BlackBerry Bold 9900",
    "model": "9900",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "7",
    "manufacturer": "Research In Motion",

    "skin": "Bold9900",

    "capabilities": [
        "input.touch",
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 640,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 640,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 287.00,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/7.0.0.141 Mobile Safari/534.1",
    "platforms": ["web", "phonegap", "webworks.handset", "cordova"]
};

});
define('ripple/devices/Style9670', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Style9670",
    "name": "BlackBerry Style 9670",
    "model": "9670",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "6",
    "manufacturer": "Research In Motion",

    "skin": "Style9670",

    "capabilities": [
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 360,
        "height": 400
    },
    "viewPort": {
        "portrait": {
            "width": 360,
            "height": 400,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 200,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9670; en) AppleWebKit/534.3+ (KHTML, like Gecko) Version/6.0.0.286 Mobile Safari/534.3+",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/Torch9860-9850', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Torch9860-9850",
    "name": "BlackBerry Torch 9860/9850",
    "model": "9860-9850",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "7",
    "manufacturer": "Research In Motion",

    "skin": "Torch9860-9850",

    "capabilities": [
        "input.touch",
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 480,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 800,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 253,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9860; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/7.0.0.0 Mobile Safari/534.1",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/PalmPre', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "PalmPre",
    "name": "Palm Pre",
    "manufacturer": "Palm",
    "model": "Pre",
    "osName": "WebOS",
    "osVersion": "1.x",

    "screen": {
        "width": 320,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 186.09,
    "userAgent": "Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0",
    "platforms": ["web", "phonegap"],

    "notes": {
        "1": "<a href=\"http://www.palm.com/us/products/phones/pre/#tab2\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/Bold9700', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Bold9700",
    "name": "BlackBerry Bold 9700",
    "model": "9700",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "6",
    "manufacturer": "Research In Motion",

    "skin": "Bold9700",

    "capabilities": [
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 480,
        "height": 360
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 360,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 245.00,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/6.0.0.141 Mobile Safari/534.1",
    "platforms": ["web", "phonegap", "webworks.handset", "cordova"]
};

});
define('ripple/devices/Colt', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Colt",
    "name": "BlackBerry 10 Dev Alpha",
    "model": "Colt",
    "osName": "BlackBerry",
    "uuid": "42",
    "osVersion": "10.0.6.99",
    "manufacturer": "Research In Motion",
    "hardwareId": "0x8500240a",

    "skin": "Colt",

    "capabilities": [
        "input.touch",
        "location.gps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "network.bluetooth",
        "network.wlan"
    ],

    "screen": {
        "width": 768,
        "height": 1280
    },
    "viewPort": {
        "portrait": {
            "width": 768,
            "height": 1280,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 1280,
            "height": 768,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "defaultOrientation": "portrait",

    "ppi": 355,
    "userAgent": "Mozilla/5.0 (BlackBerry) AppleWebKit/536.2+ (KHTML, like Gecko) Version/10.0.4.182 Mobile Safari/536.2+",
    "platforms": ["web", "webworks.bb10", "cordova"]
};

});
define('ripple/devices/HVGA', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "group": "Generic Devices",

    "id": "HVGA",
    "name": "HVGA (320x480)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",

    "screen": {
        "width": 320,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "platforms": ["wac", "web", "phonegap", "tizen", "cordova"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/FWVGA', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "group": "Generic Devices",

    "id": "FWVGA",
    "name": "Generic - FWVGA (480x854)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",

    "screen": {
        "width": 480,
        "height": 854
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 854,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 854,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "platforms": ["web", "phonegap", "cordova"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/Curve9300', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Curve9300",
    "name": "BlackBerry Curve 9300",
    "model": "9300",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "6",
    "manufacturer": "Research In Motion",

    "skin": "Curve9300",

    "capabilities": [
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 320,
        "height": 240
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 240,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 163,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9300; en) AppleWebKit/534.3+ (KHTML, like Gecko) Version/6.0.0.286 Mobile Safari/534.3+",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/HD', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {
    "id": "HD",
    "name": "HD (720x1280)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",
    "firmware": "Generic",

    "screen": {
        "width": 720,
        "height": 1280
    },
    "viewPort": {
        "portrait": {
            "width": 720,
            "height": 1280,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 1280,
            "height": 720,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "browser": ["Generic"],
    "platforms": ["wac", "web", "phonegap", "tizen", "cordova"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/NexusGalaxy', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id" : "NexusGalaxy",
    "name": "Nexus (Galaxy)",
    "manufacturer": "Samsung",
    "model": "Galaxy Nexus (generic)",
    "osName": "Android",
    "uuid" : "3D0AD03B-8B46-431A-BEF5-FF01B96BA990",
    "osVersion": "4.x.x",

    "screen": {
        "width": 720,
        "height": 1280
    },
    "viewPort": {
        "portrait": {
            "width": 720,
            "height": 1280,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 1280,
            "height": 720,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 315,
    "userAgent": "Mozilla/5.0 (Linux; Android 4.0.1; Galaxy Nexus Build/ITL41F) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
    "platforms": ["web", "phonegap", "cordova"],

    "notes": {
        "1": "<a href=\"http://www.google.com/nexus/#/tech-specs\" target=\"_blank\">Specs</a>"
    }

};

});
define('ripple/devices/WQVGA', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "WQVGA",
    "name": "Generic - WQVGA (240x480)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",

    "screen": {
        "width": 240,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 240,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 240,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "browser": ["Generic"],
    "platforms": ["web", "phonegap", "tizen"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/WSVGA', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "WSVGA",
    "name": "WSVGA (600x1024)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",
    "firmware": "Generic",

    "screen": {
        "width": 600,
        "height": 1024
    },
    "viewPort": {
        "portrait": {
            "width": 600,
            "height": 1024,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 1024,
            "height": 600,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "browser": ["Generic"],
    "platforms": ["wac", "web", "phonegap", "tizen", "cordova"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/WVGA', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "WVGA",
    "name": "WVGA (480x800)",
    "osName": "Generic",
    "osVersion": "Generic",
    "manufacturer": "Generic",
    "model": "Generic",
    "uuid": "42",

    "screen": {
        "width": 480,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 800,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 96,
    "browser": ["Generic"],
    "platforms": ["web", "phonegap", "tizen", "cordova"],
    "userAgent": "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2"
};

});
define('ripple/devices/Wave', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "Wave",
    "name": "Samsung Wave",
    "manufacturer": "Samsung",
    "model": "Wave",
    "osName": "Bada",
    "osVersion": "n/a",

    "screen": {
        "width": 480,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 800,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 283,
    "userAgent": "?",
    "platforms": ["web"]
};

});
define('ripple/devices/iPhone3', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "iPhone3",
    "name": "iPhone 3G/3Gs/4/4s",
    "model": "3G",
    "osName": "iPhone",
    "osVersion": "3",
    "uuid": "e0101010d38bde8e6740011221af335301010333",
    "manufacturer": "Apple",

    "screen": {
        "width": 320,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 164.8,
    "userAgent": "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/1A542a Safari/419.3",
    "platforms": ["web", "phonegap", "cordova"]
};

});
define('ripple/devices/PalmPre2', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "PalmPre2",
    "name": "Palm Pre 2",
    "manufacturer": "Palm",
    "model": "Pre",
    "osName": "WebOS",
    "osVersion": "2.x",

    "screen": {
        "width": 320,
        "height": 480
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 480,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 186.09,
    // TODO :: not exactly the correct userAgent webkit version is probably different
    "userAgent": "Mozilla/5.0 (webOS/2.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/2.0",
    "platforms": ["web", "phonegap"],

    "notes": {
        "1": "<a href=\"http://www.palm.com/us/products/phones/pre2/#tab2\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/Curve9350-9360-9370', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Curve9350-9360-9370",
    "name": "BlackBerry Curve 9350/9360/9370",
    "model": "9350-9360-9370",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "7",
    "manufacturer": "Research In Motion",

    "skin": "Curve9350-9360-9370",

    "capabilities": [
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 480,
        "height": 360
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 360,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 246.00,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9350; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/7.0.0.0 Mobile Safari/534.1",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/iPad', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "iPad",
    "name": "iPad",
    "model": "iPad",
    "osName": "iOS",
    "uuid": "e0101010d38bde8e6740011221af335301010333",
    "osVersion": "1.6",
    "manufacturer": "Apple",

    "screen": {
        "width": 768,
        "height": 1024
    },
    "viewPort": {
        "portrait": {
            "width": 768,
            "height": 1024,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 1024,
            "height": 768,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 132,
    "userAgent": "Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10",
    "platforms": ["web", "phonegap", "cordova"],

    "notes": {
        "1": "<a href=\"http://www.apple.com/ipad/specs/\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/NexusS', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id" : "NexusS",
    "name": "Nexus S",
    "manufacturer": "Samsung",
    "model": "Nexux S",
    "osName": "Android",
    "uuid" : "F54E13F1-C1B7-4212-BFA8-AB3C9C3F088F",
    "osVersion": "2.3.x",

    "screen": {
        "width": 480,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 800,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 235,
    "userAgent": "Mozilla/5.0 (Linux; U; Android 2.3.2; en-us; Nexus S Build/GRH78C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
    "platforms": ["web", "phonegap", "cordova"],

    "notes": {
        "1": "<a href=\"http://www.google.com/nexus/#/tech-specs\" target=\"_blank\">Specs</a>"
    }

};

});
define('ripple/devices/Torch9810', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Torch9810",
    "name": "BlackBerry Torch 9810",
    "model": "9810",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "7",
    "manufacturer": "Research In Motion",

    "skin": "Torch9810",

    "capabilities": [
        "input.touch",
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 480,
        "height": 640
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 640,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 640,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 253,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9810; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/7.0.0.0 Mobile Safari/534.1",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/Tattoo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "Tattoo",
    "name": "HTC Tattoo",
    "manufacturer": "HTC",
    "model": "Tattoo",
    "osVersion": "1.6",
    "uuid": "6F196F23-FD0D-4F62-B27B-730147FCC5A3",
    "osName": "Android",

    "screen": {
        "width": 240,
        "height": 320
    },
    "viewPort": {
        "portrait": {
            "width": 240,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 142.9,
    "userAgent": "Mozilla/5.0 (Linux; U; Android 1.6; en-us; HTC_TATTOO_A3288 Build/DRC79) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
    "platforms": ["web", "phonegap"]
};

});
define('ripple/devices/Pearl9100', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    "id": "Pearl9100",
    "name": "BlackBerry Pearl 9100",
    "model": "9100",
    "osName": "BlackBerry OS",
    "uuid": "42",
    "osVersion": "6",
    "manufacturer": "Research In Motion",

    "skin": "Pearl9100",

    "capabilities": [
        "input.keyboard.issuretype",
        "location.gps",
        "location.maps",
        "media.audio.capture",
        "media.video.capture",
        "media.recording",
        "storage.memorycard",
        "network.bluetooth",
        "network.wlan",
        "network.3gpp"
    ],

    "screen": {
        "width": 360,
        "height": 400
    },
    "viewPort": {
        "portrait": {
            "width": 360,
            "height": 400,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 239,
    "userAgent": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9100; en) AppleWebKit/534.3+ (KHTML, like Gecko) Version/6.0.0.286 Mobile Safari/534.3+",
    "platforms": ["web", "phonegap", "webworks.handset"]
};

});
define('ripple/devices/HPPre3', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "HPPre3",
    "name": "HP Pre 3",
    "manufacturer": "HP",
    "model": "Pre",
    "osName": "WebOS",
    "osVersion": "2.x",

    "screen": {
        "width": 480,
        "height": 800
    },
    "viewPort": {
        "portrait": {
            "width": 480,
            "height": 800,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 800,
            "height": 480,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 260,
    // TODO :: not exactly the correct userAgent webkit version is probably different
    "userAgent": "Mozilla/5.0 (webOS/2.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/2.0",
    "platforms": ["web", "phonegap"],

    "notes": {
        "1": "<a href=\"http://www.palm.com/us/products/phones/pre3/index.html\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/devices/HPVeer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "id": "HPVeer",
    "name": "HP Veer",
    "manufacturer": "HP",
    "model": "Veer",
    "osName": "WebOS",
    "osVersion": "2.x",

    "screen": {
        "width": 320,
        "height": 400
    },
    "viewPort": {
        "portrait": {
            "width": 320,
            "height": 400,
            "paddingTop": 0,
            "paddingLeft": 0
        },
        "landscape": {
            "width": 400,
            "height": 320,
            "paddingTop": 0,
            "paddingLeft": 0
        }
    },

    "ppi": 197,
    // TODO :: not exactly the correct userAgent webkit version is probably different
    "userAgent": "Mozilla/5.0 (webOS/2.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/2.0",
    "platforms": ["web", "phonegap"],

    "notes": {
        "1": "<a href=\"http://www.palm.com/us/products/phones/veer/index.html\" target=\"_blank\">Specs</a>"
    }
};

});
define('ripple/fileSystem', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    db = require('ripple/db'),
    exception = require('ripple/exception'),
    event = require('ripple/event'),
    _console = require('ripple/console'),
    utils = require('ripple/utils'),
    _fileSystemPaths = {
        "photos": { "uri": "" },
        "videos": { "uri": "" },
        "music": { "uri": "" },
        "downloads": { "uri": "" },
        "widgethome": { "uri": "" }
    },
    _fileSystemRegex = {
        "photos": { "virtualPathRegex": /^\/virtual\/photos\//i },
        "videos": { "virtualPathRegex": /^\/virtual\/videos\//i },
        "music": { "virtualPathRegex": /^\/virtual\/music\//i },
        "downloads": { "virtualPathRegex": /^\/virtual\/downloads\//i },
        "widgethome": { "virtualPathRegex": /^\/virtual\/widgethome\//i }
    },
    _overrides = {};

module.exports = {
    initialize: function () {
        _fileSystemPaths = db.retrieveObject(constants.FILESYSTEM.PERSISTENCE_KEY) || _fileSystemPaths;
        _fileSystemPaths.widgethome.uri = window.location.protocol + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/') + 1);
    },

    getURI: function getURI(origURI) {
        var newURI = origURI,
            found = false;

        if (_overrides[origURI]) {
            return _overrides[origURI];
        }

        utils.forEach(_fileSystemPaths, function (value, key) {
            if (found) {
                return;
            }

            var uri = value.uri.replace(/\/$/, "");
            if (origURI.match(_fileSystemRegex[key].virtualPathRegex)) {
                newURI = origURI.replace(_fileSystemRegex[key].virtualPathRegex, uri + "/");
                found = true;
            }
        });

        return newURI;
    },

    exists: function (path) {
        try {
            var scrubbedUri = this.getURI(path),
                xhr = new XMLHttpRequest();

            xhr.open("GET", scrubbedUri, false);
            xhr.send();

            //HACK: this should return maybe for 403
            return xhr.status !== 404;
        }
        catch (e) {
            exception.handle(e);
            _console.log("failed to check if [" + path + "] exists");
            return false;
        }
    },


    getFileSystemPaths: function getFileSystemPaths() {
        return utils.copy(_fileSystemPaths);
    },

    updateFileSystemPaths: function updateFileSystemPaths(filePathsObject) {
        _fileSystemPaths = utils.copy(filePathsObject);
        _fileSystemPaths.widgethome.uri = window.location.protocol + "//" + window.location.host + window.location.pathname;
        db.saveObject(constants.FILESYSTEM.PERSISTENCE_KEY, filePathsObject);
    },

    override : function (from, to) {
        _overrides[from] = to;
    }
};

});
define('ripple/deviceSettings', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* DeviceSettings
 *  A per object store for a platform's settings.
 *  For example, RadioInfo object in WAC has isRadioEnabled that can be true/false
 *  setting => {key: {key1: "test"}}
 */
var _PERSISTENCE_KEY = "devicesettings",
    db = require('ripple/db'),
    platform = require('ripple/platform'),
    _currentDeviceSettings = {},
    _self;

function _default(key) {
    var keys = key.split("."),
        defaults = platform.current().device;
    if (keys.length === 1)
        return defaults[key];
    return keys.length === 2 &&
           defaults[keys[0]] &&
           defaults[keys[0]][keys[1]] &&
           defaults[keys[0]][keys[1]].control ?
           defaults[keys[0]][keys[1]].control.value : undefined;
}

_self = {
    initialize: function () {
        // TODO: remove deprecated DeviceSettings from persisted ones.
        _currentDeviceSettings = db.retrieveObject(_PERSISTENCE_KEY) || {};
    },
    register: function (key, obj) {
        _currentDeviceSettings[key] = obj;
    },

    persist: function (key, obj) {
        if (key) {
            _currentDeviceSettings[key] = obj;
        }

        db.saveObject(_PERSISTENCE_KEY, _currentDeviceSettings);
    },

    retrieve: function (key) {
        return _currentDeviceSettings.hasOwnProperty(key) ?
               _currentDeviceSettings[key] : _default(key);
    },

    retrieveAsInt: function (key) {
        return parseInt(_self.retrieve(key), 10);
    },

    retrieveAsBoolean: function (key) {
        return !!_self.retrieve(key);
    }
};

module.exports = _self;

});
define('ripple/appcache', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    initialize: function () {
        window.addEventListener('load', function (e) {
            window.applicationCache.addEventListener('updateready', function (e) {
                if (window.applicationCache.status === window.applicationCache.UPDATEREADY) {
                    window.applicationCache.swapCache();
                    window.location.reload();
                }
            }, false);
        }, false);
    }
};

});
define('ripple/devices', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    db = require('ripple/db'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    platform = require('ripple/platform'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    _devices = {};

event.on("HardwareKeyDefault", function (key) {
    if (key === 0 || key === "0") { //back button key
        require('ripple/emulatorBridge').window().history.back();
    }
});

_self = module.exports = {
    initialize: function () {
        _devices = [
/* 
           "Bold9700",
            "Bold9900",
            "Colt",
            "Curve9300",
            "Curve9350-9360-9370",
            "FWVGA",
            "G1",
*/
            "HD",
/*
            "HPPre3",
            "HPVeer",
*/
            "HVGA",
/*
            "iPad",
            "iPhone3",
            "Legend",
            "Nexus",
            "NexusS",
            "NexusGalaxy",
            "Nexus7",
            "NokiaN8",
            "NokiaN97",
            "PalmPre",
            "PalmPre2",
            "Pearl9100",
            "Playbook",
            "QVGA",
            "Style9670",
            "Tattoo",
            "Torch9800",
            "Torch9810",
            "Torch9860-9850",
            "Wave",
            "WQVGA",
*/
            "WSVGA",
            "WVGA",
            "custom"
        ].reduce(function (hash, deviceID) {
            hash[deviceID] = require('ripple/devices/' + deviceID);
            return hash;
        }, {});

        var current = this.getCurrentDevice();
        require('ripple/bus').send('userAgent', current.userAgent);
    },

    getCurrentDevice: function () {
        var deviceId = db.retrieve("device-key"),
            device = this.getDevice(deviceId),
            platformId = platform.current().id,
            does = function (device) {
                return {
                    include: function (platformId) {
                        return device.platforms.some(function (id) {
                            return platformId === id;
                        });
                    }
                };
            };

        if (deviceId !== "custom" && (!device || !does(device).include(platformId))) {
            deviceId = utils.reduce(_devices, function (current, device, id) {
                return does(device).include(platformId) ? id : current;
            });
            device = this.getDevice(deviceId);
        }

        return device;
    },

    getDevice: function (deviceId) {
        var device, width, height;

        device = _devices[deviceId] ? utils.copy(_devices[deviceId]) : null;
        width = db.retrieve("custom_width");
        height = db.retrieve("custom_height");

        if (width === undefined) {
            width = 600;
        } else {
            width =  parseInt(width, 10);
        }

        if (height === undefined) {
            height = 800;
        } else {
            height =  parseInt(height, 10);
        }

        $('#resolution-custom-width').val(width);
        $('#resolution-custom-height').val(height);
        if (deviceId === "custom") {
            device.screen.width = device.viewPort.portrait.width = width;
            device.screen.height = device.viewPort.portrait.height = height;
            device.viewPort.landscape.height = width;
            device.viewPort.landscape.width = height;
            $('input:radio[name="resolution-type"][value="custom"]').click();
        }
        return device;
    },

    getDevicesForPlatform: function (platformId) {
        return utils.filter(_devices, function (device) {
            return device.platforms.indexOf(platformId) > -1;
        });
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/server/audioPlayer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//create my dom collection node in UI

var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    notifications = require('ripple/notifications'),
    Player = require('ripple/platform/webworks.handset/2.0.0/client/AudioPlayer'),
    _handlers = {
        loadstart: {},
        canplaythrough: {},
        durationchange: {},
        ended: {},
        error: {},
        play: {},
        pause: {},
        volumechange: {},
        close: {}
    },
    extract = {
        time: function (audio) {
            return audio.currentTime;
        },
        duration: function (audio) {
            return audio.duration;
        },
        error: function (audio) {
            return audio.error;
        },
        nothing: function (audio) {
            return null;
        }
    },
    container;

container = utils.createElement("section", {
    id: "webworks-audio-players"
});

document.getElementById("ui").appendChild(container);

function _errClosed(method) {
    notifications.openNotification("error",
       "attempted to call " + method + " on a player that is already closed. This is a very bad thing to do :)");
    return false;
}

function _removeHandler(type, id) {
    var audio = document.getElementById(id);

    if (audio && _handlers[type][id]) {
        audio.removeEventListener(type, _handlers[type][id]);
        delete _handlers[type][id];
    }
}

function _addHandler(type, id, callback) {
    var audio = document.getElementById(id);

    if (audio) {
        _removeHandler(type, id);
        audio.addEventListener(type, callback);
        _handlers[type][id] = callback;
    }
}

function proxyEvent(from, map) {
    var audio = document.getElementById(map.id);

    if (audio) {
        map.baton.take();
        _addHandler(from, map.id, function () {
            _removeHandler(from, map.id);
            map.baton.pass({code: 1, data: {
                event: map.target,
                eventData: map.data(this)
            }});
        });
    }
    else {
        return {code: -1, data: {event: "EVENT_ERROR", eventData: 5}};
    }
}

module.exports = {

    create: function (args) {
        var id = Math.uuid(),
            audio = utils.createElement("audio", {
                id: id
            });

        audio.setAttribute("src", args.locator);

        if (args.type) {
            audio.setAttribute("type", args.type);
        }

        container.appendChild(audio);
        audio.load();

        if (audio.error) {
            throw "there was a problem opening the audio file";
        }

        return {code: 1, data: id};
    },

    play: function (args) {
        var audio = document.getElementById(args.id),
            playing;

        if (audio) {
            audio.play();
            audio.rimState = Player.STARTED;
            playing = !!!audio.error;
        }
        else {
            playing = _errClosed("play");
        }

        return {code: 1, data: playing};
    },

    pause: function (args) {
        var audio = document.getElementById(args.id),
            paused;

        if (audio) {
            audio.pause();
            paused = !!!audio.error;
        } else {
            paused = _errClosed("pause");
        }

        return {code: 1, data: paused};
    },

    close: function (args) {
        var audio = document.getElementById(args.id),
            callback = _handlers["close"][args.id],
            closed = true;

        if (audio) {
            if (callback) {
                callback();
            }
            container.removeChild(audio);
        }
        else {
            closed = _errClosed("close");
        }

        return {code: 1, data: closed};
    },

    onStart: function (args, post, baton) {
        return proxyEvent("play", {
            id: args.id,
            baton: baton,
            target: "EVENT_START",
            data: extract.time
        });
    },

    onStopped: function (args, post, baton) {
        return proxyEvent("pause", {
            id: args.id,
            baton: baton,
            target: "EVENT_STOPPED",
            data: extract.time
        });
    },

    onBufferingStarted: function (args, post, baton) {
        return proxyEvent("loadstart", {
            id: args.id,
            baton: baton,
            target: "EVENT_BUFFERING_STARTED",
            data: extract.time
        });
    },

    onBufferingStopped: function (args, post, baton) {
        return proxyEvent("canplaythrough", {
            id: args.id,
            baton: baton,
            target: "EVENT_BUFFERING_STOPPED",
            data: extract.time
        });
    },

    onDurationUpdated: function (args, post, baton) {
        return proxyEvent("durationchange", {
            id: args.id,
            baton: baton,
            target: "EVENT_DURATION_UPDATED",
            data: extract.duration
        });
    },

    onEnd: function (args, post, baton) {
        return proxyEvent("ended", {
            id: args.id,
            baton: baton,
            target: "EVENT_END_OF_MEDIA",
            data: extract.duration
        });
    },

    onError: function (args, post, baton) {
        return proxyEvent("error", {
            id: args.id,
            baton: baton,
            target: "EVENT_ERROR",
            data: extract.error
        });
    },

    onVolumeChange: function (args, post, baton) {
        return proxyEvent("volumechange", {
            id: args.id,
            baton: baton,
            target: "EVENT_VOLUME_CHANGED",
            data: extract.nothing
        });
    },

    onClose: function (args, post, baton) {
        return proxyEvent("close", {
            id: args.id,
            baton: baton,
            target: "EVENT_CLOSED",
            data: extract.nothing
        });
    },

    getDuration: function (args) {
        var audio = document.getElementById(args.id),
            duration;

        if (audio) {
            duration = audio.duration;
        }
        else {
            _errClosed("getDuration");
            duration = -1;
        }

        return {code: 1, data: duration};
    },

    getMediaTime: function (args) {
        var audio = document.getElementById(args.id),
            time;

        if (audio) {
            time = audio.currentTime;
        }
        else {
            _errClosed("getMediaTime");
            time = -1;
        }

        return {code: 1, data: time};
    },

    setMediaTime: function (args) {
        var audio = document.getElementById(args.id);

        if (audio) {
            audio.currentTime = args.value;
        }
        else {
            _errClosed("setMediaTime");
        }

        return {code: 1};
    },

    getVolumeLevel: function (args) {
        var audio = document.getElementById(args.id),
            level;

        if (audio) {
            level = audio.volume * 100;
        }
        else {
            _errClosed("getVolumeLevel");
            level = -1;
        }

        return {code: 1, data: level};
    },

    setVolumeLevel: function (args) {
        var audio = document.getElementById(args.id);

        if (audio) {
            audio.volume = args.value / 100;
        }
        else {
            _errClosed("setVolumeLevel");
        }

        return {code: 1};
    },

    getState: function (args) {
        var audio = document.getElementById(args.id),
            state = audio ? audio.rimState || Player.PREFETCHED : Player.CLOSED;
        return {code: 1, data: state};
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/server/appEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    notifications = require('ripple/notifications'),
    _bg,
    _fg,
    _exit;

event.on("AppRequestBackground", function () {
    var baton = _bg;
    _bg = null;
    return baton && baton.pass({code: 1});
});

event.on("AppRequestForeground", function () {
    var baton = _fg;
    _fg = null;
    return baton && baton.pass({code: 1});
});

event.on("AppExit", function () {
    var baton = _exit;
    _exit = null;
    notifications.openNotification("normal", "blackberry.app.exit() as called, in the real world your app will exit, here... you get this notification");
    return baton && baton.pass({code: 1});
});

module.exports = {
    onBackground: function (get, post, baton) {
        baton.take();
        _bg = baton;
        return {code: 1};
    },

    onForeground: function (get, post, baton) {
        baton.take();
        _fg = baton;
        return {code: 1};
    },

    onExit: function (get, post, baton) {
        baton.take();
        _exit = baton;
        return {code: 1};
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/server/phone', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var PhoneCall = require('ripple/platform/webworks.handset/2.0.0/client/PhoneCall'),
    PhoneLogs = require('ripple/platform/webworks.handset/2.0.0/client/PhoneLogs'),
    CallLog = require('ripple/platform/webworks.handset/2.0.0/client/CallLog'),
    select = require('ripple/platform/webworks.core/2.0.0/select'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    _KEY = "blackberry-phone-logs",
    _onPhoneEventListeners = {},
    _activeCalls = {},
    _onCallLogAdded,
    _onCallLogRemoved,
    _onCallLogUpdated,
    _onCallLogReset,
    _self;

function _defaultLogs() {
    var n1 = new CallLog(),
        n2 = new CallLog(),
        m1 = new CallLog(),
        m2 = new CallLog();

    n1.number = "12344567";
    n1.name = "larry";
    n1.type = CallLog.TYPE_PLACED_CALL;
    n1.status = CallLog.STATUS_NORMAL;

    n2.number = "14567890";
    n2.name = "curly";
    n2.type = CallLog.TYPE_RECEIVED_CALL;
    n2.status = CallLog.STATUS_NORMAL;

    m1.number = "17659800";
    m1.name = "moe";
    m1.type = CallLog.TYPE_MISSED_CALL_UNOPENED;
    m1.status = CallLog.STATUS_NORMAL;

    m2.number = "14567896";
    m2.name = "snarf";
    m2.type = CallLog.TYPE_MISSED_CALL_OPENED;
    m2.status = CallLog.STATUS_NORMAL;

    return {
        normal: [n1, n2],
        missed: [m1, m2]
    };
}

function _getLogs(folderID) {
    var logs = db.retrieveObject(_KEY) || _defaultLogs();
    return folderID === undefined || folderID === null ?
        logs : logs[folderID !== PhoneLogs.FOLDER_NORMAL_CALLS ? "missed" : "normal"];
}

function _saveLogs(logs) {
    db.saveObject(_KEY, logs);
}

function _isMissedCall(log) {
    return (log.type === CallLog.TYPE_MISSED_CALL_UNOPENED ||
            log.type === CallLog.TYPE_MISSED_CALL_OPENED) ? true : false;
}

function _isNormalCall(log) {
    return (log.type === CallLog.TYPE_RECEIVED_CALL ||
            log.type === CallLog.TYPE_PLACED_CALL) ? true : false;
}

event.on("PhoneEvent", function (type, callId, error) {
    var baton = _onPhoneEventListeners[type];
    delete _onPhoneEventListeners[type];

    return baton && baton.pass({code: 1, data: {callId: callId, error: error}});
});

event.on("PhoneCallLogAdded", function (log) {
    var logs = _getLogs(),
        baton = _onCallLogAdded;

    logs[_isMissedCall(log) ? "missed" : "normal"].push(log);
    _saveLogs(logs);

    _onCallLogAdded = null;
    return baton && baton.pass({code: 1, data: {log: log}});
});

event.on("PhoneCallLogRemoved", function (log) {
    // TODO: make this be the only one responsible for deletion (instead of triggering internally)
    var baton = _onCallLogRemoved;
    _onCallLogRemoved = null;
    return baton && baton.pass({code: 1, data: {log: log}});
});

event.on("PhoneCallLogUpdated", function (newLog, oldLog) {
    // TODO: implement way to update with just this event
    var baton = _onCallLogUpdated;
    _onCallLogUpdated = null;
    return baton && baton.pass({code: 1, data: {
        newLog: newLog,
        oldLog: oldLog
    }});
});

event.on("PhoneCallLogReset", function () {
    _saveLogs(_defaultLogs());
    var baton = _onCallLogReset;
    _onCallLogReset = null;
    return baton && baton.pass({code: 1});
});

event.on("PhoneCallInitiated", function (call) {
    _activeCalls[call.id] = call;
});

event.on("PhoneCallEnded", function (call) {
    delete _activeCalls[call.id];
});

_self = {
    logs: {
        onCallLogAdded: function (get, post, baton) {
            baton.take();
            _onCallLogAdded = baton;
        },

        onCallLogRemoved: function (get, post, baton) {
            baton.take();
            _onCallLogRemoved = baton;
        },

        onCallLogUpdated: function (get, post, baton) {
            baton.take();
            _onCallLogUpdated = baton;
        },

        onCallLogReset: function (get, post, baton) {
            baton.take();
            _onCallLogReset = baton;
        },

        callAt: function (get) {
            var logs = _getLogs(get.folderID !== null && get.folderID !== undefined ?
                                        get.folderID : PhoneLogs.FOLDER_MISSED_CALLS);
            return {code: 1, data: logs.length > get.index ? logs[get.index] : null};
        },

        deleteCallAt: function (get) {
            var logs = _getLogs(),
                subLog = _getLogs(get.folderID),
                deleted = false,
                type, log;

            if (subLog.length > get.index &&
               (type = _isNormalCall(subLog[get.index]) ? "normal" : "missed") &&
               (log = logs[type].splice(get.index, 1))) {
                event.trigger("PhoneCallLogRemoved", [log]);
                _saveLogs(logs);
                deleted = true;
            }

            return {code: 1, data: deleted};
        },

        find: function (get, post) {
            var data = select.from(_getLogs(post.folderID !== null && post.folderID !== undefined ?
                                        post.folderID : PhoneLogs.FOLDER_MISSED_CALLS))
                    .orderBy(post.orderBy, post.isAscending === false ? "desc" : "asc")
                    .max(post.maxReturn)
                    .where(post.filter, select.ops.phone);
            return {code: 1, data: data};
        },

        numberOfCalls: function (get) {
            return {code: 1, data: _getLogs(get.folderID !== null && get.folderID !== undefined ?
                                        get.folderID : PhoneLogs.FOLDER_MISSED_CALLS).length};
        }
    },

    onPhoneEvent: function (get, post, baton) {
        baton.take();
        _onPhoneEventListeners[get.eventType] = baton;
    },

    activeCalls: function () {
        var data = utils.map(_activeCalls, function (callItem) {
            var call = new PhoneCall(callItem.onhold);
            call.outgoing = callItem.outgoing;
            call.recipientName = callItem.recipient.name;
            call.recipientNumber = callItem.recipient.number;
            return call;
        });
        return {code: 1, data: data};
    },

    inActiveCall: function () {
        return {code: 1, data: utils.count(_activeCalls) > 0 ? true : false};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    app = require('ripple/app'),
    notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    ui = require('ripple/ui'),
    _isForeground = true,
    _self;

_self = {
    event: require('ripple/platform/webworks.handset/2.0.0/server/appEvent'),

    exit: function () {
        event.trigger("AppExit");
        return {code: 1};
    },

    author: function () {
        return {code: 1, data: app.getInfo().author};
    },

    authorEmail: function () {
        return {code: 1, data: app.getInfo().authorEmail};
    },

    authorURL: function () {
        return {code: 1, data: app.getInfo().authorURL};
    },

    copyright: function () {
        return {code: 1, data: app.getInfo().copyright};
    },

    description: function () {
        return {code: 1, data: app.getInfo().description};
    },

    isForeground: function () {
        return {code: 1, data: _isForeground};
    },

    id: function () {
        return {code: 1, data: app.getInfo().id};
    },

    license: function () {
        return {code: 1, data: app.getInfo().license};
    },

    licenseURL: function () {
        return {code: 1, data: app.getInfo().licenseURL};
    },

    name: function () {
        return {code: 1, data: app.getInfo().name};
    },

    version: function () {
        return {code: 1, data: app.getInfo().version};
    },

    requestBackground: function () {
        ui.showOverlay("background-window", function (background) {
            var button = background.children["background-return"];

            if (button) {
                button.addEventListener("click", _self.requestForeground);
            }
            _isForeground = false;
            event.trigger("AppRequestBackground");
        });

        return {code: 1};
    },

    requestForeground: function () {
        ui.hideOverlay("background-window", function (background) {
            var button = background.children["background-return"];

            if (button) {
                button.removeEventListener("click", _self.requestForeground);
            }
            _isForeground = true;
            event.trigger("AppRequestForeground");
        });

        return {code: 1};
    },

    setHomeScreenIcon: function (args) {
        if (args.uri) {
            var msg = "The application set the home screen" +
               (args.hover ? " hover " : " ") +
               "icon to " + args.uri;

            notifications.openNotification("normal", msg);
            return {code: 1};
        }
        else {
            return {code: 0};
        }
    },

    setHomeScreenName: function (args) {
        if (args.text) {
            var msg = "The application set the home screen name to " + args.text;
            notifications.openNotification("normal", msg);
            return {code: 1};
        }
        else {
            return {code: 1};
        }
    },

    removeBannerIndicator: function () {
        event.trigger("BannerUpdated", ["", 0]);
        return {code: 1};
    },

    showBannerIndicator: function (args) {
        event.trigger("BannerUpdated", [args.icon, args.count]);
        return {code: 1};
    },

};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/sms', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _listener,
    _isListening = false,
    notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    _console = require('ripple/console'),
    _onReceive,
    _self;

event.on("MessageReceived", function (message) {
    if (!_isListening || message.type !== 'sms') {
        return;
    }

    var baton = _onReceive;
    _onReceive = null;
    _isListening = false;
    return baton && baton.pass({code: 1, data: message});
});

_self = {
    onReceive: function (args, post, baton) {
        baton.take();
        _onReceive = baton;
        _isListening = !!_onReceive;
    },

    send: function (args) {
        var msg = "To " + args.address + ": " + args.message;
        notifications.openNotification("normal", msg);
        _console.log(msg);
        return {code: 1};
    },

    isListeningForMessage: function (get, post, baton) {
        if (get && typeof get.isListeningForMessage === "boolean") {
            _isListening = get.isListeningForMessage;
        }

        return {code: 1, data: _isListening};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/message', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    utils = require('ripple/utils'),
    select = require('ripple/platform/webworks.core/2.0.0/select'),
    Message = require('ripple/platform/webworks.handset/2.0.0/client/Message'),
    _self;

function _get() {
    return db.retrieveObject("webworks-message-list") || {};
}

function _do(func) {
    var messages = _get();
    func(messages);
    db.saveObject("webworks-message-list", messages);
}

_self = {
    find: function (get, post) {
        var data = select
                .from(_get())
                .max(post.maxReturn)
                .where(post.filter);
        return {code: 1, data: data};
    },

    remove: function (get, post) {
        _do(function (messages) {
            if (!messages[get.uid]) {
                throw "attempting to delete a non existant message with uid: " + get.uid;
            }
            delete messages[get.uid];
        });
        return {code: 1};
    },

    save: function (get, post) {
        _do(function (messages) {
            var orig = messages[post.message.uid],
                updated = utils.copy(post.message);

            updated.folder = orig ? orig.folder : Message.FOLDER_DRAFT;
            updated.status = orig ? orig.status : Message.STATUS_DRAFT;

            messages[post.message.uid] = updated;
        });
        return {code: 1};
    },

    send: function (get, post) {
        _do(function (messages) {
            var updated = utils.copy(get.message);

            updated.folder = Message.FOLDER_SENT;
            updated.status = Message.STATUS_SENT;

            messages[updated.uid] = updated;
        });
        return {code: 1};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/io/dir', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var cache = require('ripple/platform/webworks.core/2.0.0/fsCache'),
    dir = require('ripple/platform/webworks.core/2.0.0/server/io/dir'),
    utils = require('ripple/utils'),
    _self = {};

function _packet(data) {
    return {
        code: 1,
        data: data
    };
}

utils.mixin({
    getFreeSpaceForRoot: function (get, post, baton) {
        return _packet(cache.dir.getFreeSpaceForRoot(post.path));
    },
    getRootDirs: function (get, post, baton) {
        return _packet(cache.dir.getRootDirs());
    }
}, _self);

utils.mixin(dir, _self);

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/push', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    utils = require('ripple/utils'),
    _handlers = {},
    _self;

function listenersChanged() {
    var ports = utils.map(_handlers, function (handler) {
        return handler.port;
    });
    event.trigger("PushListenersChanged", [ports]);
}

event.on("Push", function (data, port) {
    var handler = _handlers["port_" + port];
    delete _handlers["port_" + port];
    window.setTimeout(function () {
        if (!_handlers["port_" + port]) {
            //doesn't look like they are coming back ;)
            listenersChanged();
        }
    }, 100);
    return handler && handler.baton.pass({code: 1, data: data});
});

_self = {

    onPush: function (args, post, baton) {
        if (!args.port) {
            throw "no port specified";
        }
        else if (typeof args.port !== 'number') {
            throw "port is not a number";
        }
        baton.take();
        _handlers["port_" + args.port] = {
            port: args.port,
            baton: baton
        };
        listenersChanged();
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/invoke', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    type = "normal",
    name = {
        "0": "Address Book",
        "1": "Bluetooth Config",
        "2": "Calculator",
        "3": "Calendar",
        "camera://": "Camera",
        "camera://video": "Video Camera",
        "map://": "Maps",
        "6": "Memopad",
        "7": "Messages",
        "8": "Phone",
        "9": "Search",
        "10": "Tasks",
        "11": "Browser",
        "http://": "Browser",
        "12": "Java",
    };

module.exports = {
    invoke: function (opts) {
        var app = name[opts.appType];
        if (app === undefined && opts.appType && opts.appType.match(/^http/i)) {
            app = "Browser";
        }

        notifications.openNotification(type,
           "Requested to launch: " + app + " application.");
        return {code: 1};
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/server/contact', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var select = require('ripple/platform/webworks.core/2.0.0/select'),
    db = require('ripple/db'),
    utils = require('ripple/utils'),
    _KEY = "blackberry-pim-contacts",
    _self;

function _defaultContacts() {
    var id1 = Math.uuid(null, 16),
        id2 = Math.uuid(null, 16),
        id3 = Math.uuid(null, 16),
        id4 = Math.uuid(null, 16),
        contacts = {};

    contacts[id1] = {
        uuid: id1,
        firstName: "Leonardo",
        homePhone: "4567892345",
        email1: "leo@underground.com"
    };
    contacts[id2] = {
        uuid: id2,
        firstName: "Raphael",
        homePhone: "4563457890",
        email1: "raph@underground.com"
    };
    contacts[id3] = {
        uuid: id3,
        firstName: "Michelangelo",
        homePhone: "4563453425",
        email1: "mike@underground.com"
    };
    contacts[id4] = {
        uuid: id4,
        firstName: "Donatello",
        homePhone: "4563453425",
        email1: "don@undergound.com"
    };

    return contacts;
}

function _get() {
    return db.retrieveObject(_KEY) || _defaultContacts();
}

function _save(contacts) {
    db.saveObject(_KEY, contacts);
}

_self = {
    save: function (get, post) {
        var contacts = _get();

        contacts[post.contact.uid] = post.contact;
        _save(contacts);
        return {code: 1};
    },
    remove: function (get, post) {
        var contacts = _get(),
            id = get.id;

        delete contacts[id];
        _save(contacts);
        return {code: 1};
    },
    find: function (get, post) {
        var contacts = _get(),
            match = select.from(contacts);

        if (post.orderBy) {
            match.orderBy(post.orderBy, post.isAscending === false ? "desc" : "asc");
        }

        if (post.maxReturn) {
            match.max(post.maxReturn);
        }

        return {code: 1, data: match.where(post.fieldFilter)};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/Task', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var select = require('ripple/platform/webworks.core/2.0.0/select'),
    db = require('ripple/db'),
    utils = require('ripple/utils'),
    _KEY = "blackberry-pim-task",
    _self;

function _get() {
    return db.retrieveObject(_KEY) || {};
}

function _save(tasks) {
    db.saveObject(_KEY, tasks);
}

_self = {
    save: function (get, post) {
        var tasks = _get(),
            properties = post.task,
            id = properties.uid;

        if (tasks[id]) {
            utils.mixin(properties, tasks[id]);
        } else {
            tasks[id] = properties;
        }

        _save(tasks);

        return {code: 1};
    },

    remove: function (get, post) {
        var tasks = _get(),
            id = get.id;

        delete tasks[id];

        _save(tasks);

        return {code: 1};
    },

    find: function (get, post) {
        var tasks = _get(),
            match = select.from(tasks);

        if (post.orderBy) {
            match.orderBy(post.orderBy, post.isAscending === false ? "desc" : "asc");
        }

        if (post.maxReturn) {
            match.max(post.maxReturn);
        }

        return {code: 1, data: match.where(post.filter)};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/appointment', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    select = require('ripple/platform/webworks.core/2.0.0/select'),
    _self;

function _get() {
    return db.retrieveObject("webworks-pim-appointment-list") || {};
}

function _do(func) {
    var appointments = _get();
    func(appointments);
    db.saveObject("webworks-pim-appointment-list", appointments);
}

_self = {
    find: function (get, post) {
        var appointments = _get(),
            data = select.from(appointments)
                    .orderBy(post.orderBy, post.isAscending === false ? "desc" : "asc")
                    .max(post.maxReturn)
                    .where(post.filter);

        return {code: 1, data: data};
    },

    remove: function (get) {
        _do(function (appointments) {
            if (!appointments[get.uid]) {
                throw "attempting to delete a non existant appointment with uid: " + get.uid;
            }
            delete appointments[get.uid];
        });

        return {code: 1};
    },

    save: function (get, post) {
        _do(function (appointments) {
            appointments[post.appointment.uid] = post.appointment;
        });

        return {code: 1};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/menu', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _menuItems = {},
    event = require('ripple/event'),
    events = require('ripple/platform/webworks.core/2.0.0/client/events'),
    ui = require('ripple/ui'),
    devices = require('ripple/devices'),
    utils = require('ripple/utils'),
    tooltip = require('ripple/ui/plugins/tooltip'),
    _self,
    isMenuOpen = false,
    _baton,
    menuWindow = document ? document.getElementById("menu-window") : undefined;

if (menuWindow) {
    menuWindow.addEventListener("click", function () {
        _self.close();
    });
}

event.on("LayoutChanged", function () {
    if (isMenuOpen) {
        _self.close();
        //Used to resize menu on orientation change
        _self.open();
    }
});

event.on("HardwareKeyDefault", function (key) {
    if (key === 1 || key === "1") { //menu button key
        if (isMenuOpen) {
            _self.close();
        }
        else {
            _self.open();
        }
    }
});

event.on("MenuItemSelected", function (menuItem) {
    var baton = _baton;
    _baton = null;
    return baton && baton.pass({code: 1, data: menuItem});
});

event.on("MenuItemChanged", function (menuItem) {
    _menuItems[menuItem.id] = menuItem;
});

_self = {

    onSelect : function (args, post, baton) {
        baton.take();
        _baton = baton;
    },

    addMenuItem: function (args) {
        if (!args) {
            throw "item not found";
        }
        _menuItems[args.item.id] = args.item;
        event.trigger("MenuChanged", [_menuItems]);
        return {code: 1};
    },

    clearMenuItems: function () {
        _menuItems = {};
        event.trigger("MenuChanged", [utils.copy(_menuItems)]);
        return {code: 1};
    },

    open: function () {
        function _return() {
            return {code: 1};
        }

        if (utils.count(_menuItems) === 0) {
            _return();
        }

        ui.showOverlay("menu-window", function (menu) {
            var container = document.getElementById("viewport-container"),
                height = window.getComputedStyle(container, null).getPropertyValue("height"),
                width = window.getComputedStyle(container, null).getPropertyValue("width"),
                menuButtons = document.getElementById("menu-buttons"),
                sorted,
                menuItem;

            if (!menuButtons) {
                _return();
            }

            menu.setAttribute("style", "display:block;height:" + height + "; width:" + width + ";");
            isMenuOpen = true;

            sorted = utils.map(_menuItems, function (item) {
                return item;
            }).sort(function (a, b) {
                return a.ordinal - b.ordinal;
            });

            menuButtons.innerHTML = "";
            sorted.forEach(function (item) {
                if (!item.isSeparator) {
                    if (item.isDefault) {
                        menuItem = utils.createElement("div", {
                            "class": "overlay-menu-item-default",
                            "id": "default-menu-item"
                        });
                    }
                    else {
                        menuItem = utils.createElement("div", {
                            "class": "overlay-menu-item"
                        });
                    }
                    menuItem.innerHTML = item.caption;

                    menuItem.addEventListener("click", function () {
                        _baton.pass({code: 1, data: item.id});
                    });
                }
                else {
                    menuItem = utils.createElement("hr", {});
                }
                menuButtons.appendChild(menuItem);
                tooltip.create("#default-menu-item", "Default Item");
            });
        }, true);

        event.trigger("MenuOpened", []);

        _return();
    },

    close: function () {
        ui.hideOverlay("menu-window", function (menu) {
            var menuButtons = document.getElementById("menu-buttons");
            menuButtons.innerHTML = "";
            isMenuOpen = false;
            menu.setAttribute("style", "display:none;");

        });
        return {code: 1};
    },

    removeMenuItem: function (args) {
        delete _menuItems[args.item.id];
        event.trigger("MenuChanged", [_menuItems]);
        return {code: 1};
    },

    setDefaultMenuItem: function (args) {

        utils.forEach(_menuItems, function (item) {
            item.isDefault = false;
        });

        _menuItems[args.id].isDefault = true;

        event.trigger("DefaultItemChanged", [_menuItems[args.id]]);
        return {code: 1};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/identity', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    Service = require('ripple/platform/webworks.handset/2.0.0/client/identity/Service'),
    Transport = require('ripple/platform/webworks.handset/2.0.0/client/identity/Transport'),
    utils = require('ripple/utils'),
    platform = require('ripple/platform'),
    deviceSettings = require('ripple/deviceSettings'),
    _transportTypes = [
        {name: "TCP Cellular", type: "TCP Cellular"},
        {name: "Wap", type: "Wap"},
        {name: "Wap 2.0", type: "Wap 2.0"},
        {name: "MDS", type: "MDS"},
        {name: "BIS B", type: "Bis B"},
        {name: "Unite!", type: "Unite!"},
        {name: "TCP Wifi", type: "TCP Wifi"},
    ],
    _services = [
        new Service(),
        new Service()
    ];

function _isTransportAvailable(transport) {
    return deviceSettings.retrieveAsBoolean("transports." + transport.type);
}

utils.mixin({
    name: "Super Dave Osborne",
    emailAddress: "dave@stunt.com",
    isDefault: true,
    type: Service.TYPE_EMAIL
}, _services[0]);

utils.mixin({
    name: "Fred Penner",
    emailAddress: "fred@fredpenner.com",
    isDefault: false,
    type: Service.TYPE_CONTACT
}, _services[1]);

_self = {
    getDefaultService: function () {
        var serices = _services.filter(function (service) {
            return service.isDefault === true;
        });
        return {code: 1, data: serices};
    },
    getServiceList: function () {
        return {code: 1, data: _services};
    },
    getTransportList: function () {
        var transports = _transportTypes.filter(function (transport) {
            return _isTransportAvailable(transport);
        }).map(function (transport) {
            return new Transport(transport.name, transport.type);
        });
        return {code: 1, data: transports};
    },
    IMEI: function () {
        return {code: 1, data: deviceSettings.retrieve("identity.IMEI")};
    },
    IMSI: function () {
        return {code: 1, data: deviceSettings.retrieve("identity.IMSI")};
    },
    PIN: function () {
        return {code: 1, data: deviceSettings.retrieve("identity.PIN")};
    },
    phone: require('ripple/platform/webworks.handset/2.0.0/server/identity/phone')
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/memo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    select = require('ripple/platform/webworks.core/2.0.0/select'),
    _self;

function _get() {
    return db.retrieveObject("webworks-pim-memo-list") || {};
}

function _do(func) {
    var memos = _get();
    func(memos);
    db.saveObject("webworks-pim-memo-list", memos);
}

_self = {
    find: function (get, post) {
        var memos = select.from(_get())
                    .orderBy(post.orderBy, post.isAscending === false ? "desc" : "asc")
                    .max(post.maxReturn)
                    .where(post.filter);
        return {code: 1, data: memos};
    },
    remove: function (get, post) {
        _do(function (memos) {
            if (!memos[get.uid]) {
                throw "attempting to delete a non existant memo with uid: " + get.uid;
            }
            delete memos[get.uid];
        });
        return {code: 1};
    },
    save: function (get, post) {
        _do(function (memos) {
            memos[post.memo.uid] = post.memo;
        });
        return {code: 1};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/identity/phone', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _lines = [
        {id: 1, number: 12345678910, label: "rogers", type: 1},
        {id: 2, number: 10987654321, label: "mystery", type: 0}
    ],
    _self;

function _filterLines(args) {

    var result = _lines;

    if (args && typeof args.id === "number") {
        result = _lines.filter(function (line) {
            return line.id === args.id;
        });

        if (result.length === 0) {
            throw "invalid line id: " + args.id;
        }
    }

    return result;
}

_self = {
    getLineIds: function () {
        var lines = _lines.map(function (line) {
            return line.id;
        });
        return {
            code: 1,
            data: lines
        };
    },
    getLineLabel: function (args) {
        return {
            code: 1,
            data: _filterLines(args)[0].label
        };
    },
    getLineNumber: function (args) {
        return {
            code: 1,
            data: _filterLines(args)[0].number
        };
    },
    getLineType: function (args) {
        return {
            code: 1,
            data: _filterLines(args)[0].type
        };
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server/systemEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    _onCoverageChange,
    _onHardwareKey = {};

event.on("CoverageChange", function () {
    var baton = _onCoverageChange;
    _onCoverageChange = null;
    return baton && baton.pass({code: 1});
});

event.on("HardwareKey", function (key) {
    var baton = _onHardwareKey["key_" + key];
    delete _onHardwareKey["key_" + key];

    if (baton) {
        baton.pass({code: 1});
    }
    else {
        event.trigger("HardwareKeyDefault", [key]);
    }
});

module.exports = {
    onCoverageChange: function (args, post, baton) {
        baton.take();
        _onCoverageChange = baton;
    },

    onHardwareKey: function (args, post, baton) {
        baton.take();
        _onHardwareKey["key_" + args.key] = baton;
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/server/category', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    _KEY = "blackberry-pim-category",
    _self;

function _get() {
    return db.retrieveObject(_KEY) || [];
}

function _save(category) {
    var categories = _get();
    if (!categories.some(function (item) {
        return item === category;
    })) {
        categories.push(category);
        db.saveObject(_KEY, categories);
    }
}

function _remove(category) {
    var categories = _get(),
        index = categories.indexOf(category);

    if (index >= 0) {
        categories.splice(index, 1);
        db.saveObject(_KEY, categories);
    }
}

_self = {
    addCategory: function (args) {
        _save(args.categoryName);
        return {code: 1};
    },
    deleteCategory: function (args) {
        _remove(args.categoryName);
        return {code: 1};
    },
    getCategories: function () {
        return {code: 1, data: _get()};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/server', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    platform = "ripple/platform/webworks.handset/2.0.0/server/",
    core = "ripple/platform/webworks.core/2.0.0/server/",
    systemEvent = require(platform + 'systemEvent'),
    system = {};

// ugh, thanks to the spec...
system.event = systemEvent;
utils.mixin(require(core + "system"), system);

module.exports = {
    blackberry: {
        invoke: require(platform + "invoke"),
        system: system,
        app: require(platform + "app"),
        identity: require(platform + "identity"),
        message: {
            sms: require(platform + "sms"),
            message: require(platform + "message")
        },
        push: require(platform + "push"),
        pim: {
            Task: require(platform + "Task"),
            category: require(platform + "category"),
            memo: require(platform + "memo"),
            appointment: require(platform + "appointment"),
            contact: require(platform + "contact")
        },
        audio: {
            player: require(platform + "audioPlayer")
        },
        ui: {
            menu: require(platform + "menu"),
            dialog: require(core + "dialog")
        },
        phone: require(platform + "phone"),
        io: {
            dir: require(platform + "io/dir"),
            file: require(core + "io/file")
        }
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/XMLHttpRequest', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var xhr = require("ripple/platform/webworks.core/2.0.0/XMLHttpRequest");
module.exports = xhr.create("ripple/platform/webworks.handset/2.0.0/server");

});
define('ripple/platform/webworks.handset/2.0.0/client/CallLog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function CallLog() {
    // readwrite  property  String   addressBookNumber
    // readwrite  property  String   addressBookType
    // readwrite  property  Date   date
    // readwrite  property  Number   duration
    // readwrite  property  String   name
    // readwrite  property  String   notes
    // readwrite  property  String   number
    // readwrite  property  Number   status
    // readwrite  property  Number   type
    this.addressBookNumber = null;
    this.addressBookType = null;
    this.date = null;
    this.duration = null;
    this.name = null;
    this.notes = null;
    this.number = null;
    this.status = null;
    this.type = null;
}

function _get(val) {
    return function () {
        return val;
    };
}

CallLog.__defineGetter__("STATUS_NORMAL", _get(0));
CallLog.__defineGetter__("STATUS_BUSY", _get(1));
CallLog.__defineGetter__("STATUS_CONGESTION", _get(2));
CallLog.__defineGetter__("STATUS_PATH_UNAVAILABLE", _get(3));
CallLog.__defineGetter__("STATUS_NUMBER_UNOBTAINABLE", _get(4));
CallLog.__defineGetter__("STATUS_AUTHENTICATION_FAILURE", _get(5));
CallLog.__defineGetter__("STATUS_EMERGENCY_CALLS_ONLY", _get(6));
CallLog.__defineGetter__("STATUS_HOLD_ERROR", _get(7));
CallLog.__defineGetter__("STATUS_OUTGOING_CALLS_BARRED", _get(8));
CallLog.__defineGetter__("STATUS_GENERAL_ERROR", _get(9));
CallLog.__defineGetter__("STATUS_MAINTENANCE_REQUIRED", _get(10));
CallLog.__defineGetter__("STATUS_SERVICE_NOT_AVAILABLE", _get(11));
CallLog.__defineGetter__("STATUS_CALL_FAIL_DUE_TO_FADING", _get(12));
CallLog.__defineGetter__("STATUS_CALL_LOST_DUE_TO_FADING", _get(13));
CallLog.__defineGetter__("STATUS_CALL_FAILED_TRY_AGAIN", _get(14));
CallLog.__defineGetter__("STATUS_FDN_MISMATCH", _get(15));
CallLog.__defineGetter__("STATUS_CONNECTION_DENIED", _get(16));
CallLog.__defineGetter__("STATUS_INCOMING_CALL_BARRED", _get(17));
CallLog.__defineGetter__("TYPE_RECEIVED_CALL", _get(0));
CallLog.__defineGetter__("TYPE_PLACED_CALL", _get(1));
CallLog.__defineGetter__("TYPE_MISSED_CALL_UNOPENED", _get(2));
CallLog.__defineGetter__("TYPE_MISSED_CALL_OPENED", _get(3));

module.exports = CallLog;

});
define('ripple/platform/webworks.handset/2.0.0/client/AddressBookArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.AddressBookArguments ( [contact : blackberry.pim.Contact ] )
var _self = function (contact) {
    return {
        contact: contact,
        //readwrite  property  Number   view
        view: 0
    };
};

//const Number  VIEW_NEW  = 0
_self.__defineGetter__("VIEW_NEW", function () {
    return 0;
});
//const Number  VIEW_COMPOSE  = 1
_self.__defineGetter__("VIEW_COMPOSE", function () {
    return 1;
});
//const Number  VIEW_DISPLAY  = 2
_self.__defineGetter__("VIEW_DISPLAY", function () {
    return 2;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/blackberry', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var blackberry = {},
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport');

blackberry.__defineGetter__("network", function () {
    return transport.call("blackberry/system/network");
});

module.exports = blackberry;

});
define('ripple/platform/webworks.handset/2.0.0/client/FilterExpression', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.find.FilterExpression ( leftField  : object ,  operator  : object ,  rightField : object ,  [negate : Boolean ] )
var FilterExpression = function (leftField, operator, rightField, negate) {
    this.__defineGetter__("leftField", function () {
        return leftField;
    });

    this.__defineGetter__("operator", function () {
        return operator;
    });

    this.__defineGetter__("rightField", function () {
        return rightField;
    });

    this.__defineGetter__("negate", function () {
        return negate ? true : false;
    });
};

module.exports = FilterExpression;

});
define('ripple/platform/webworks.handset/2.0.0/client/BrowserArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.BrowserArguments ( url : String ,  [transport : blackberry.identity.Transport ] )
module.exports = function (url, transport) {
    return {
        url: url
    };
};

});
define('ripple/platform/webworks.handset/2.0.0/client/MapsArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.MapsArguments ( )
//blackberry.invoke.MapsArguments ( latitude : Number ,  longitude : Number )
//blackberry.invoke.MapsArguments ( locationDocument : Document ) - Supported in 5.0.0 only
//blackberry.invoke.MapsArguments ( locationDocument : String ) - Supported in 6.0.0 only
//blackberry.invoke.MapsArguments ( address : blackberry.pim.Address )
var _self = function () {
    return {};
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/appEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _callbacks = {},
    _self;

function _poll(evt, handler) {
    _callbacks[evt] = handler;

    transport.poll("blackberry/app/event/" + evt, {}, function () {
        var func = _callbacks[evt];

        if (func) {
            func();
        }

        return !!func;
    });
}

_self = {
    onBackground: function (handler) {
        _poll("onBackground", handler);
    },

    onForeground: function (handler) {
        _poll("onForeground", handler);
    },

    onExit: function (handler) {
        _poll("onExit", handler);
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/PhoneCall', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function PhoneCall(onhold) {
    return {
        //Boolean   isOnHold ( )
        //readonly  property  Boolean   outgoing
        //readonly  property  String   recipientName
        //readonly  property  String   recipientNumber

        outgoing: false,
        recipientName: null,
        recipientNumber: null,

        isOnHold: function () {
            return onhold;
        }
    };
}

module.exports = PhoneCall;

});
define('ripple/platform/webworks.handset/2.0.0/client/MemoArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.MemoArguments ( [memo : blackberry.pim.Memo ] )
var _self = function (memo) {
    return {
        memo: memo,
        view: 0
    };
};

//const Number  VIEW_NEW  = 0
_self.__defineGetter__("VIEW_NEW", function () {
    return 0;
});
//const Number  VIEW_EDIT  = 1
_self.__defineGetter__("VIEW_EDIT", function () {
    return 1;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Appointment', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    utils = require('ripple/utils'),
    _uri = "blackberry/pim/appointment/";

function Appointment(service) {
    var _self = {
        allDay: false,
        attendees: [],
        end: null,
        freeBusy: null,
        location: null,
        note: null,
        recurrence: null,
        reminder: null,
        start: null,
        summary: null,
        uid: null,
        remove: function () {
            transport.call(_uri + "remove", {get: {uid: _self.uid}});
        },
        save: function () {
            if (_self.uid === null) {
                _self.uid  = Number(Math.uuid(8, 10));
            }
            transport.call(_uri + "save", {post: {appointment: _self}});
        }
    };

    return _self;
}

function _massage(property, name) {
    if (name === "recurrence" && property) {
        if (property.end) {
            property.end = new Date(property.end);
        }
    }
    if (name === "reminder" && property) {
        if (property.date) {
            property.date = new Date(property.date);
        }
    }
    if ((name === "end" || name === "start") && property) {
        property = new Date(property);
    }
    return property;
}

Appointment.find = function (filter, orderBy, maxReturn, service, isAscending) {
    var opts = {
        post: {
            filter: filter,
            orderBy: orderBy,
            maxReturn: maxReturn,
            service: service,
            isAscending: isAscending
        }
    };

    return transport.call(_uri + "find", opts).map(function (obj) {
        var appt = new Appointment();
        appt.allDay = obj.allDay;
        appt.attendees = obj.attendees;
        appt.end = _massage(obj.end, "end");
        appt.freeBusy = obj.freeBusy;
        appt.location = obj.location;
        appt.note = obj.note;
        appt.recurrence = _massage(obj.recurrence, "recurrence");
        appt.reminder = _massage(obj.reminder, "reminder");
        appt.start = _massage(obj.start, "start");
        appt.summary = obj.summary;
        appt.uid = obj.uid;
        return appt;
    });
};

Appointment.__defineGetter__("FREE", function () {
    return 0;
});
Appointment.__defineGetter__("TENTATIVE", function () {
    return 1;
});
Appointment.__defineGetter__("BUSY", function () {
    return 2;
});
Appointment.__defineGetter__("OUT_OF_OFFICE", function () {
    return 3;
});

module.exports = Appointment;

});
define('ripple/platform/webworks.handset/2.0.0/client/Message', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/platform/webworks.core/2.0.0/client/utils'),
    identity = require('ripple/platform/webworks.handset/2.0.0/client/identity'),
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    Service = require('ripple/platform/webworks.handset/2.0.0/client/identity/Service'),
    select = require('ripple/platform/webworks.core/2.0.0/select'),
    _uri = "blackberry/message/message/";

function Message(service) {
    var _service = service,
        _msg = {
            uid: 0,
            status: Message.STATUS_DRAFT,
            from: "",
            folder: Message.FOLDER_DRAFT,
            replyTo: "",
            bccRecipients: "",
            body: "",
            ccRecipients: "",
            priority: Message.PRIORITY_MEDIUM, //default to med priority
            subject: "",
            toRecipients: "",

            remove: function () {
                _msg.folder = Message.FOLDER_DELETED;
                transport.call(_uri + "remove", {
                    get: {uid: _msg.uid}
                });
            },

            save: function () {
                if (_msg.uid === 0) {
                    _msg.uid = Number(Math.uuid(8, 10));
                }

                _msg.replyTo  = _msg.from = _service.emailAddress;
                _msg.status =  Message.STATUS_SAVED;
                transport.call(_uri + "save", {
                    post: {message: _msg}
                });
            },

            send: function () {
                if (_msg.toRecipients) {
                    if (_msg.uid === 0) {
                        _msg.uid = Number(Math.uuid(8, 10));
                    }

                    _msg.folder = Message.FOLDER_DRAFT;
                    _msg.status = Message.STATUS_UNKNOWN;
                    transport.call(_uri + "send", {
                        get: {message: _msg}
                    });
                } else {
                    throw "message has no recipients";
                }
            }
        };

    if (!_service) {
        _service = identity.getDefaultService().reduce(function (email, service) {
            return service.type === Service.TYPE_EMAIL ? service : email;
        }, null);
    }

    return _msg;
}

Message.find = function (filter, maxReturn, service) {
    var opts = {
        post: {
            filter: filter,
            maxReturn: maxReturn,
            service: service
        }
    };

    return transport.call(_uri + "find", opts).map(function (obj) {
        var msg = new Message();

        msg.uid = obj.uid;
        msg.status = obj.status;
        msg.from = obj.from;
        msg.folder = obj.folder;
        msg.replyTo = obj.replyTo;
        msg.bccRecipients = obj.bccRecipients;
        msg.body = obj.body;
        msg.ccRecipients = obj.ccRecipients;
        msg.priority = obj.priority;
        msg.subject = obj.subject;
        msg.toRecipients = obj.toRecipients;

        return msg;
    });
};


Message.__defineGetter__("STATUS_UNKNOWN", function () {
    return -1;
});
Message.__defineGetter__("STATUS_SAVED", function () {
    return 0;
});
Message.__defineGetter__("STATUS_DRAFT", function () {
    return 1;
});
Message.__defineGetter__("STATUS_SENT", function () {
    return 2;
});
Message.__defineGetter__("STATUS_ERROR_OCCURED", function () {
    return 3;
});
Message.__defineGetter__("PRIORITY_HIGH", function () {
    return 0;
});
Message.__defineGetter__("PRIORITY_MEDIUM", function () {
    return 1;
});
Message.__defineGetter__("PRIORITY_LOW", function () {
    return 2;
});
Message.__defineGetter__("FOLDER_INBOX", function () {
    return 0;
});
Message.__defineGetter__("FOLDER_SENT", function () {
    return 1;
});
Message.__defineGetter__("FOLDER_DRAFT", function () {
    return 2;
});
Message.__defineGetter__("FOLDER_OUTBOX", function () {
    return 3;
});
Message.__defineGetter__("FOLDER_DELETED", function () {
    return 4;
});
Message.__defineGetter__("FOLDER_OTHER", function () {
    return 5;
});

module.exports = Message;

});
define('ripple/platform/webworks.handset/2.0.0/client/MenuItem', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    event = require('ripple/event');

function MenuItem(isSeparator, ordinal, caption, callback) {
    var _isDefault = false,
	id = Math.uuid();

    if (ordinal < 0) {
        throw "Ordinal cannot be less than 0";
    } else if (isSeparator) {
        if (caption !== undefined) {
            throw "caption must not be supplied";
        } else if (callback !== undefined) {
            throw "callback must not be supplied";
        }
    } else if (!isSeparator) {
        if (caption === undefined) {
            throw "caption must be supplied";
        }
    }

    this.callback = callback;

    this.__defineSetter__("id", function (i) {
        id = i;
    });

    this.__defineGetter__("id", function () {
        return id;
    });

    this.__defineSetter__("caption", function (c) {
        caption = c;
        event.trigger("MenuItemChanged", [this]);
    });

    this.__defineGetter__("caption", function () {
        return caption;
    });

    this.__defineSetter__("ordinal", function (o) {
        ordinal = o;
        event.trigger("MenuItemChanged", [this]);
    });

    this.__defineGetter__("ordinal", function () {
        return ordinal;
    });

    this.__defineGetter__("isSeparator", function () {
        return isSeparator;
    });

    this.__defineSetter__("isDefault", function (d) {
        _isDefault = d;
        event.trigger("MenuItemChanged", [this]);
    });

    this.__defineGetter__("isDefault", function () {
        return _isDefault;
    });

    this.__defineGetter__("id", function () {
        return id;
    });
}

module.exports = MenuItem;

});
define('ripple/platform/webworks.handset/2.0.0/client/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/app/",
    _self;

_self = {
    exit: function () {
        transport.call(_uri + "exit", {async: true});
    },

    setHomeScreenIcon: function (uri, hover) {
        transport.call(_uri + "setHomeScreenIcon", {
            get: {
                uri: uri,
                hover: hover
            },
            async: true
        });

        return true;
    },

    setHomeScreenName: function (text) {
        transport.call(_uri + "setHomeScreenName", {
            get: {text: text},
            async: true
        });

        return true;
    },

    requestForeground: function () {
        transport.call(_uri + "requestForeground", {async: true});
    },

    requestBackground: function () {
        transport.call(_uri + "requestBackground", {async: true});
    },

    removeBannerIndicator: function () {
        transport.call(_uri + "removeBannerIndicator", {async: true});
    },

    showBannerIndicator: function (icon, count) {
        transport.call(_uri + "showBannerIndicator", {
            get: {
                icon: icon,
                count: count
            },
            async: true
        });
    },
};

_self.__defineGetter__("author", function () {
    return transport.call(_uri + "author");
});

_self.__defineGetter__("authorEmail", function () {
    return transport.call(_uri + "authorEmail");
});

_self.__defineGetter__("authorURL", function () {
    return transport.call(_uri + "authorURL");
});

_self.__defineGetter__("copyright", function () {
    return transport.call(_uri + "copyright");
});

_self.__defineGetter__("description", function () {
    return transport.call(_uri + "description");
});

_self.__defineGetter__("id", function () {
    return transport.call(_uri + "id");
});

_self.__defineGetter__("isForeground", function () {
    return transport.call(_uri + "isForeground");
});

_self.__defineGetter__("license", function () {
    return transport.call(_uri + "license");
});

_self.__defineGetter__("licenseURL", function () {
    return transport.call(_uri + "licenseURL");
});

_self.__defineGetter__("name", function () {
    return transport.call(_uri + "name");
});

_self.__defineGetter__("version", function () {
    return transport.call(_uri + "version");
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Memo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/pim/memo/";

function Memo() {
    var _self = {
        categories: [],
        note: null,
        title: null,
        uid: null,
        remove: function () {
            transport.call(_uri + "remove", {
                get: {uid: _self.uid}
            });
        },
        save: function () {
            if (_self.uid  === null) {
                _self.uid  = Number(Math.uuid(8, 10));
            }
            transport.call(_uri + "save", {
                post: {memo: _self}
            });
        }
    };

    return _self;
}

Memo.find = function (filter, orderBy, maxReturn, service, isAscending) {
    var opts = {
        post: {
            filter: filter,
            orderBy: orderBy,
            maxReturn: maxReturn,
            isAscending: isAscending,
            service: service
        }
    };

    return transport.call(_uri + "find", opts).map(function (obj) {
        var memo = new Memo();
        memo.uid = obj.uid;
        memo.categories = obj.categories || [];
        memo.note = obj.note;
        memo.title = obj.title;
        return memo;
    });
};

module.exports = Memo;

});
define('ripple/platform/webworks.handset/2.0.0/client/TaskArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.TaskArguments ( [task : blackberry.pim.Task ] )
var _self = function (task) {
    return {
        view: 0,
        task: task
    };
};

//const Number  VIEW_NEW  = 0
_self.__defineGetter__("VIEW_NEW", function () {
    return 0;
});
//const Number  VIEW_EDIT  = 1
_self.__defineGetter__("VIEW_EDIT", function () {
    return 1;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Contact', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/pim/contact/";

function Contact(service) {
    var _self = {
        anniversary: null,
        birthday: null,
        categories: [],
        company: null,
        email1: "",
        email2: "",
        email3: "",
        faxPhone: null,
        firstName: null,
        homeAddress: null,
        homePhone: null,
        homePhone2: null,
        jobTitle: null,
        lastName: null,
        mobilePhone: null,
        note: null,
        otherPhone: null,
        pagerPhone: null,
        picture: null,
        pin: null,
        title: null,
        uid: null,
        user1: null,
        user2: null,
        user3: null,
        user4: null,
        webpage: null,
        workAddress: null,
        workPhone: null,
        workPhone2: null,
        remove: function () {
            if (!_self.uid) {
                throw "task has not yet been saved (has no uid)";
            }
            transport.call(_uri + "remove", {
                get: { id: _self.uid }
            });
        },
        save: function () {
            if (!_self.uid) {
                _self.uid = Math.uuid(null, 16);
            }
            transport.call(_uri + "save", {
                post: { contact: _self }
            });
        },
        setPicture: function (picture) {
            throw "not implemented";
        }
    };

    return _self;
}

function _massage(property, name) {
    if ((name === "anniversary" || name === "birthday") && property) {
        return new Date(property);
    }
    return property;
}

Contact.find = function (fieldFilter, orderBy, maxReturn, service, isAscending) {
    return transport.call(_uri + "find", {
        post: {
            fieldFilter: fieldFilter,
            orderBy: orderBy,
            maxReturn: maxReturn,
            service: service,
            isAscending: isAscending
        }
    }).map(function (properties) {
        var contact = new Contact(),
            key;
        for (key in properties) {
            if (contact.hasOwnProperty(key)) {
                contact[key] = _massage(properties[key], key);
            }
        }
        return contact;
    });
};

module.exports = Contact;

});
define('ripple/platform/webworks.handset/2.0.0/client/sms', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/message/sms/",
    onReceive,
    _self;

_self = {
    addReceiveListener: function (callback) {
        onReceive = callback;
        transport.poll(_uri + "onReceive", {}, function (response) {
            if (onReceive) {
                onReceive(response.body, response.from, response.time);
            }
            return !!onReceive;
        });
    },

    removeReceiveListener: function () {
        if (onReceive) {
            onReceive = null;
            return true;
        }

        return false;
    },

    send: function (message, address) {
        transport.call(_uri + "send", {
            get: {
                message: message,
                address: address
            },
            async: true
        });
    }
};

_self.__defineGetter__("isListeningForMessage", function () {
    return transport.call(_uri + "isListeningForMessage", {async: false});
});

_self.__defineSetter__("isListeningForMessage", function (value) {
    transport.call(_uri + "isListeningForMessage", {
        async: false,
        get: {isListeningForMessage: value}
    });
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/pim', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {};

});
define('ripple/platform/webworks.handset/2.0.0/client/io/dir', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    dir = require('ripple/platform/webworks.core/2.0.0/client/io/dir'),
    utils = require('ripple/utils'),
    _uri = "blackberry/io/dir/",
    FILE = "file://",
    _self = {};

function _prunePrefix(path) {
    return path.replace(new RegExp("^" + FILE), '');
}

utils.mixin({
    getFreeSpaceForRoot: function (path) {
        return transport.call(_uri + "getFreeSpaceForRoot", {
            post: {path: _prunePrefix(path)}
        });
    },
    getRootDirs: function () {
        return transport.call(_uri + "getRootDirs", {}).map(function (dir) {
            return FILE + dir;
        });
    }
}, _self);

utils.mixin(dir, _self);

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/push', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _self,
    _uri = "blackberry/push/onPush",
    callbacks = {},
    PushData = require('ripple/platform/webworks.handset/2.0.0/client/PushData');

_self = {
    openPushListener: function (callback, port, bbTransport, maxQueueCap) {
        callbacks["onPush" + port] = callback;

        transport.poll(_uri, {
            get: {
                port: port,
                bbTransport: bbTransport,
                maxQueueCap: maxQueueCap
            }
        }, function (response) {
            var func = callbacks["onPush" + port];

            if (func) {
                func(new PushData(response, port));
            }

            return !!func;
        });
    },

    closePushListener: function (port) {
        delete callbacks["onPush" + port];
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Recurrence', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function Recurrence() {
    return {
        //readwrite  property  Number   count
        //readwrite  property  Number   dayInMonth
        //readwrite  property  Number   dayInWeek
        //readwrite  property  Number   dayInYear
        //readwrite  property  Date   end
        //readwrite  property  Number   frequency
        //readwrite  property  Number   interval
        //readwrite  property  Number   monthInYear
        //readwrite  property  Number   weekInMonth

        count: null,
        dayInMonth: null,
        dayInWeek: null,
        dayInYear: null,
        end: null,
        frequency: null,
        interval: null,
        monthInYear: null,
        weekInMonth: null
    };
}

Recurrence.__defineGetter__("NO_REPEAT", function () {
    return 0;
});
Recurrence.__defineGetter__("DAILY", function () {
    return 1;
});
Recurrence.__defineGetter__("WEEKLY", function () {
    return 2;
});
Recurrence.__defineGetter__("MONTHLY", function () {
    return 3;
});
Recurrence.__defineGetter__("YEARLY", function () {
    return 4;
});
Recurrence.__defineGetter__("JANUARY", function () {
    return 0x20000;
});
Recurrence.__defineGetter__("FEBRUARY", function () {
    return 0x40000;
});
Recurrence.__defineGetter__("MARCH", function () {
    return 0x80000;
});
Recurrence.__defineGetter__("APRIL", function () {
    return 0x100000;
});
Recurrence.__defineGetter__("MAY", function () {
    return 0x200000;
});
Recurrence.__defineGetter__("JUNE", function () {
    return 0x400000;
});
Recurrence.__defineGetter__("JULY", function () {
    return 0x800000;
});
Recurrence.__defineGetter__("AUGUST", function () {
    return 0x1000000;
});
Recurrence.__defineGetter__("SEPTEMBER", function () {
    return 0x2000000;
});
Recurrence.__defineGetter__("OCTOBER", function () {
    return 0x4000000;
});
Recurrence.__defineGetter__("NOVEMBER", function () {
    return 0x8000000;
});
Recurrence.__defineGetter__("DECEMBER", function () {
    return 0x10000000;
});
Recurrence.__defineGetter__("FIRST", function () {
    return 0x1;
});
Recurrence.__defineGetter__("SECOND", function () {
    return 0x2;
});
Recurrence.__defineGetter__("THIRD", function () {
    return 0x4;
});
Recurrence.__defineGetter__("FOURTH", function () {
    return 0x8;
});
Recurrence.__defineGetter__("FIFTH", function () {
    return 0x10;
});
Recurrence.__defineGetter__("LAST", function () {
    return 0x20;
});
Recurrence.__defineGetter__("SECONDLAST", function () {
    return 0x40;
});
Recurrence.__defineGetter__("THIRDLAST", function () {
    return 0x80;
});
Recurrence.__defineGetter__("FOURTHLAST", function () {
    return 0x100;
});
Recurrence.__defineGetter__("FIFTHLAST", function () {
    return 0x200;
});
Recurrence.__defineGetter__("SUNDAY", function () {
    return 0x10000;
});
Recurrence.__defineGetter__("MONDAY", function () {
    return 0x8000;
});
Recurrence.__defineGetter__("TUESDAY", function () {
    return 0x4000;
});
Recurrence.__defineGetter__("WEDNESDAY", function () {
    return 0x2000;
});
Recurrence.__defineGetter__("THURSDAY", function () {
    return 0x1000;
});
Recurrence.__defineGetter__("FRIDAY", function () {
    return 0x800;
});
Recurrence.__defineGetter__("SATURDAY", function () {
    return 0x400;
});

module.exports = Recurrence;

});
define('ripple/platform/webworks.handset/2.0.0/client/system', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    system = require('ripple/platform/webworks.core/2.0.0/client/system'),
    _uri = "blackberry/system/",
    _self;

_self = {
    setHomeScreenBackground: function (filePath) {
        transport.call(_uri + "setHomeScreenBackground", {
            get: {filePath: filePath},
            async: true
        });
    },
};

(function () {
    // HACK: can't type check if system[key] is a function, sets off getters
    // also can't use utils.mixin or forEach for the same reason
    function get(i) {
        return function () {
            return system[i];
        };
    }

    for (var key in system) {
        if (system.hasOwnProperty(key)) {
            _self.__defineGetter__(key, get(key));
        }
    }
}());

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/invoke', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _uri = "blackberry/invoke/invoke",
    APP_URL_CAMERA = "camera://",
    APP_URL_CAMERA_VIDEO = "camera://video",
    APP_URL_MAP = "map://",
    APP_URL_MUSIC = "music://",
    APP_URL_PHOTOS = "photos://",
    APP_URL_VIDEOS = "videos://",
    APP_URL_APPWORLD = "appworld://",
    APP_URL_UPDATE = "update://",
    APP_BROWSER_ERROR = "Protocol specified in the url is not supported.",
    APP_ADDRESSBOOK_ERROR = "Invalid arguments specified",
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _self;

_self = {
    invoke: function (appType, args) {
        var get = {};

        switch (appType) {

        //AddressBook
        case 0:
            if (args) {
                if (args.view === 1 && args.contact) {
                    throw APP_ADDRESSBOOK_ERROR; //contact cannot be used with this view
                }
                else if (args.view === 2 && !args.contact) {
                    throw APP_ADDRESSBOOK_ERROR; //need contact for this view
                }
            }

            get.appType = appType;
            break;

        //Bluetooth Config
        case 1:
            get.appType = appType;
            break;

        //Calculator
        case 2:
            get.appType = appType;
            break;

        //Calendar
        case 3:
            get.appType = appType;
            break;

        //Camera
        case 4:
            if (!args || args.view === 1) {
                get.appType = APP_URL_CAMERA_VIDEO;
            } else {
                get.appType = APP_URL_CAMERA;
            }
            break;

        //Maps
        case 5:
            get.appType = APP_URL_MAP;
            break;

        //Memopad
        case 6:
            get.appType = appType;
            break;

        //Messages
        case 7:
            get.appType = appType;
            break;

        //Phone
        case 8:
            get.appType = appType;
            break;

        //Search
        case 9:
            get.appType = appType;
            break;

        //Tasks
        case 10:
            get.appType = appType;
            break;

        //Browser
        case 11:

            if (!args) {
                get.appType = "http://";
            } else {
                if (args.url && !args.url.match(/^https?:\/\//)) {
                    throw APP_BROWSER_ERROR;
                }
                get.appType = args.url;
            }

            break;

        //Java
        case 12:
            get.appType = appType;
            break;

        default:
            throw "appType not supported";
        }

        transport.call(_uri, {
            get: get,
            async: true
        });
    }
};

_self.__defineGetter__("APP_ADDRESSBOOK", function () {
    return 0;
});
_self.__defineGetter__("APP_BLUETOOTH_CONFIG", function () {
    return 1;
});
_self.__defineGetter__("APP_CALCULATOR", function () {
    return 2;
});
_self.__defineGetter__("APP_CALENDAR", function () {
    return 3;
});
_self.__defineGetter__("APP_CAMERA", function () {
    return 4;
});
_self.__defineGetter__("APP_MAPS", function () {
    return 5;
});
_self.__defineGetter__("APP_MEMOPAD", function () {
    return 6;
});
_self.__defineGetter__("APP_MESSAGES", function () {
    return 7;
});
_self.__defineGetter__("APP_PHONE", function () {
    return 8;
});
_self.__defineGetter__("APP_SEARCH", function () {
    return 9;
});
_self.__defineGetter__("APP_TASKS", function () {
    return 10;
});
_self.__defineGetter__("APP_BROWSER", function () {
    return 11;
});
_self.__defineGetter__("APP_JAVA", function () {
    return 12;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Phone', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/phone/",
    _listeners = {},
    _self;

_self = {
    activeCalls: function () {
        return transport.call(_uri + "activeCalls");
    },

    addPhoneListener: function (callback, eventType) {
        var assigned = false;

        if (callback && typeof eventType === "number") {
            _listeners[eventType] = callback;
            assigned = true;
        } else if (eventType && callback === null) {
            delete _listeners[eventType];
        } else {
            _listeners = {};
        }

        transport.poll(_uri + "onPhoneEvent", {
            get: {eventType: eventType}
        }, function (response) {
            var func = _listeners[eventType];

            if (func) {
                func(response.callId, response.error);
            }

            return !!func;
        });

        // hackish (return true that event was assigned, this is a disconnect between transport poll api and server)
        return assigned;
    },

    inActiveCall: function () {
        return transport.call(_uri + "inActiveCall");
    }
};

_self.__defineGetter__("CB_CALL_INITIATED", function () {
    return 0;
});
_self.__defineGetter__("CB_CALL_WAITING", function () {
    return 1;
});
_self.__defineGetter__("CB_CALL_INCOMING", function () {
    return 2;
});
_self.__defineGetter__("CB_CALL_ANSWERED", function () {
    return 3;
});
_self.__defineGetter__("CB_CALL_CONNECTED", function () {
    return 4;
});
_self.__defineGetter__("CB_CALL_CONFERENCECALL_ESTABLISHED", function () {
    return 5;
});
_self.__defineGetter__("CB_CONFERENCECALL_DISCONNECTED", function () {
    return 6;
});
_self.__defineGetter__("CB_CALL_DISCONNECTED", function () {
    return 7;
});
_self.__defineGetter__("CB_CALL_DIRECTCONNECT_CONNECTED", function () {
    return 8;
});
_self.__defineGetter__("CB_CALL_DIRECTCONNECT_DISCONNECTED", function () {
    return 9;
});
_self.__defineGetter__("CB_CALL_ENDED_BYUSER", function () {
    return 10;
});
_self.__defineGetter__("CB_CALL_FAILED", function () {
    return 11;
});
_self.__defineGetter__("CB_CALL_RESUMED", function () {
    return 12;
});
_self.__defineGetter__("CB_CALL_HELD", function () {
    return 13;
});
_self.__defineGetter__("CB_CALL_ADDED", function () {
    return 14;
});
_self.__defineGetter__("CB_CALL_REMOVED", function () {
    return 15;
});
_self.__defineGetter__("CALL_ERROR_SUBSCRIBER_BUSY", function () {
    return 1;
});
_self.__defineGetter__("CALL_ERROR_CONGESTION", function () {
    return 2;
});
_self.__defineGetter__("CALL_ERROR_RADIO_PATH_UNAVAILABLE", function () {
    return 3;
});
_self.__defineGetter__("CALL_ERROR_NUMBER_UNOBTAINABLE", function () {
    return 4;
});
_self.__defineGetter__("CALL_ERROR_AUTHORIZATION_FAILURE", function () {
    return 5;
});
_self.__defineGetter__("CALL_ERROR_EMERGENCY_CALLS_ONLY", function () {
    return 6;
});
_self.__defineGetter__("CALL_ERROR_HOLD_ERROR", function () {
    return 7;
});
_self.__defineGetter__("CALL_ERROR_OUTGOING_CALLS_BARRED", function () {
    return 8;
});
_self.__defineGetter__("CALL_ERROR_GENERAL", function () {
    return 9;
});
_self.__defineGetter__("CALL_ERROR_MAINTENANCE_REQUIRED", function () {
    return 10;
});
_self.__defineGetter__("CALL_ERROR_SERVICE_NOT_AVAILABLE", function () {
    return 11;
});
_self.__defineGetter__("CALL_ERROR_DUE_TO_FADING", function () {
    return 12;
});
_self.__defineGetter__("CALL_ERROR_LOST_DUE_TO_FADING", function () {
    return 13;
});
_self.__defineGetter__("CALL_ERROR_TRY_AGAIN", function () {
    return 14;
});
_self.__defineGetter__("CALL_ERROR_FDN_MISMATCH", function () {
    return 15;
});
_self.__defineGetter__("CALL_ERROR_CONNECTION_DENIED_BY_NETWORK", function () {
    return 16;
});
_self.__defineGetter__("CALL_ERROR_NUMBER_NOT_IN_SERVICE", function () {
    return 17;
});
_self.__defineGetter__("CALL_ERROR_PLEASE_TRY_LATER", function () {
    return 18;
});
_self.__defineGetter__("CALL_ERROR_SERVICE_CONFLICT", function () {
    return 19;
});
_self.__defineGetter__("CALL_ERROR_SYSTEM_BUSY_TRY_LATER", function () {
    return 20;
});
_self.__defineGetter__("CALL_ERROR_USER_BUSY_IN_PRIVATE", function () {
    return 21;
});
_self.__defineGetter__("CALL_ERROR_USER_BUSY_IN_DATA", function () {
    return 22;
});
_self.__defineGetter__("CALL_ERROR_USER_NOT_AUTHORIZED", function () {
    return 23;
});
_self.__defineGetter__("CALL_ERROR_USER_NOT_AVAILABLE", function () {
    return 24;
});
_self.__defineGetter__("CALL_ERROR_USER_UNKNOWN", function () {
    return 25;
});
_self.__defineGetter__("CALL_ERROR_USER_NOT_REACHABLE", function () {
    return 26;
});
_self.__defineGetter__("CALL_ERROR_INCOMING_CALL_BARRED", function () {
    return 27;
});
_self.__defineGetter__("CALL_ERROR_CALL_REPLACED_BY_STK", function () {
    return 28;
});
_self.__defineGetter__("CALL_ERROR_STK_CALL_NOT_ALLOWED", function () {
    return 29;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/PhoneLogs', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    CallLog = require('ripple/platform/webworks.handset/2.0.0/client/CallLog'),
    utils = require('ripple/utils'),
    _onCallLog = {
        Added: null,
        Removed: null,
        Updated: null,
        Reset: null,
    },
    _uri = "blackberry/phone/logs/",
    _self;

function _massage(property, name) {
    if (name === "date" && property) {
        return new Date(property);
    }
    return property;
}

function _toCallLog(log) {
    var callLog = new CallLog(),
        prop;
    for (prop in log) {
        if (log.hasOwnProperty(prop)) {
            callLog[prop] = _massage(log[prop], prop);
        }
    }
    return callLog;
}

function handle(evt) {
    return function (response) {
        var func = _onCallLog[evt], args;

        if (func) {
            args = utils.map(response, function (value) {
                return _toCallLog(value);
            });
            func.apply(null, args);
        }

        return !!func;
    };
}

function poll(path) {
    transport.poll(_uri + path, {}, handle(path.replace("onCallLog", "")));
}

_self = {
    addPhoneLogListener: function (onCallLogAdded, onCallLogRemoved, onCallLogUpdated, onCallLogReset) {
        _onCallLog.Added = onCallLogAdded;
        _onCallLog.Removed = onCallLogRemoved;
        _onCallLog.Updated = onCallLogUpdated;
        _onCallLog.Reset = onCallLogReset;

        if (onCallLogAdded) {
            poll("onCallLogAdded");
        }

        if (onCallLogRemoved) {
            poll("onCallLogRemoved");
        }

        if (onCallLogUpdated) {
            poll("onCallLogUpdated");
        }

        if (onCallLogReset) {
            poll("onCallLogReset");
        }

        return !!(onCallLogAdded || onCallLogRemoved ||
                  onCallLogUpdated || onCallLogRemoved);
    },

    callAt: function (index, folderID) {
        var log = transport.call(_uri + "callAt", {
            get: {
                index: index,
                folderID: folderID
            }
        });

        if (log && log.date) {
            log.date = new Date(log.date);
        }

        return log;
    },

    deleteCallAt: function (index, folderID) {
        return transport.call(_uri + "deleteCallAt", {
            get: {
                index: index,
                folderID: folderID
            }
        });
    },

    find: function (filter, folderID, orderBy, maxReturn, isAscending) {
        return transport.call(_uri + "find", {
            post: {
                filter: filter,
                folderID: folderID,
                orderBy: orderBy,
                maxReturn: maxReturn,
                isAscending: isAscending
            }
        }).map(_toCallLog);
    },

    numberOfCalls: function (folderID) {
        return transport.call(_uri + "numberOfCalls", {
            get: {
                folderID: folderID
            }
        });
    }
};

_self.__defineGetter__("FOLDER_MISSED_CALLS", function () {
    return 0;
});

_self.__defineGetter__("FOLDER_NORMAL_CALLS", function () {
    return 1;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/JavaArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.JavaArguments ( uri : String ,  [params : String [ ] ] )
var _self = function (uri, params) {
    return {
        uri: uri,
        params: params,
        args: arguments
    };
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/MessageArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.MessageArguments ( )
//blackberry.invoke.MessageArguments ( message : blackberry.message.Message )
//blackberry.invoke.MessageArguments ( to : String ,  subject : String ,  body : String )
var _self = function () {
    return {
        view: 1
    };
};

//const Number  VIEW_NEW  = 0
_self.__defineGetter__("VIEW_NEW", function () {
    return 0;
});
//const Number  VIEW_DEFAULT  = 1
_self.__defineGetter__("VIEW_DEFAULT", function () {
    return 1;
});
//const Number  VIEW_SAVED  = 2
_self.__defineGetter__("VIEW_SAVED", function () {
    return 2;
});
//const Number  VIEW_SEARCH  = 3
_self.__defineGetter__("VIEW_SEARCH", function () {
    return 3;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Address', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function Address() {
    return {
        //readwrite  property  String   address1
        //readwrite  property  String   address2
        //readwrite  property  String   city
        //readwrite  property  String   country
        //readwrite  property  String   stateProvince
        //readwrite  property  String   zipPostal

        address1: null,
        address2: null,
        city: null,
        country: null,
        stateProvince: null,
        zipPostal: null
    };
}

module.exports = Address;

});
define('ripple/platform/webworks.handset/2.0.0/client/SearchArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.SearchArguments ( )
//blackberry.invoke.SearchArguments ( text : String ,  name : String )
var _self = function (text, name) {

    return {
        text: text,
        name: name
    };

};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Task', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/pim/Task/";

function Task() {
    var _self = {
        save: function () {
            if (!_self.uid) {
                _self.uid = Math.uuid(null, 16);
            }
            transport.call(_uri + "save",  {
                post: {
                    task: _self
                }
            });
        },
        remove: function () {
            if (!_self.uid) {
                throw "task has not yet been saved (has no uid)";
            }
            transport.call(_uri + "remove", {
                get: {
                    id: _self.uid
                }
            });
        },
        uid: null,
        categories: [],
        due: null,
        note: "",
        priority: Task.PRIORITY_NORMAL,
        recurrence: null,
        reminder: null,
        status: Task.NOT_STARTED,
        summary: ""
    };

    return _self;
}

function _massage(property, name) {
    if (name === "recurrence" && property) {
        if (property.end) {
            property.end = new Date(property.end);
        }
    }
    if (name === "reminder" && property) {
        if (property.date) {
            property.date = new Date(property.date);
        }
    }
    if (name === "due" && property) {
        property = new Date(property);
    }
    return property;
}

Task.find = function (filter, orderBy, maxReturn, isAscending) {
    return transport.call(_uri + "find", {
        post: {
            filter: filter,
            orderBy: orderBy,
            maxReturn: maxReturn,
            isAscending: isAscending
        }
    }).map(function (properties) {
        var task = new Task(),
            key;
        for (key in properties) {
            if (task.hasOwnProperty(key)) {
                task[key] = _massage(properties[key], key);
            }
        }
        return task;
    });
};

Task.__defineGetter__("NOT_STARTED", function () {
    return 0;
});

Task.__defineGetter__("IN_PROGRESS", function () {
    return 1;
});

Task.__defineGetter__("COMPLETED", function () {
    return 2;
});

Task.__defineGetter__("WAITING", function () {
    return 3;
});

Task.__defineGetter__("DEFERRED", function () {
    return 4;
});

Task.__defineGetter__("PRIORITY_HIGH", function () {
    return 0;
});

Task.__defineGetter__("PRIORITY_NORMAL", function () {
    return 1;
});

Task.__defineGetter__("PRIORITY_LOW", function () {
    return 2;
});

module.exports = Task;

});
define('ripple/platform/webworks.handset/2.0.0/client/AudioPlayer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/audio/player/";

function Player(locator, type, async) {
    //we can't use the async prop since we need the ID before we can do anything else.
    var _id = transport.call(_uri + "create", {
            get: {locator: locator, type: type},
            async: false
        }),
        _listener,
        _closed,
        _self,
        _poll = function (path) {
            transport.poll(_uri + path, {
                get: {id: _id}
            }, function (response) {
                if (_listener) {
                    _listener(_self, response.event, response.eventData);
                }

                return !!_listener;
            });
        };

    _self = {
        addPlayerListener: function (callback) {
            if (!_closed && callback) {
                _listener = callback;
                _poll("onStart");
                _poll("onStopped");
                _poll("onBufferingStarted");
                _poll("onBufferingStopped");
                _poll("onDurationUpdated");
                _poll("onEnd");
                _poll("onError");
                _poll("onVolumeChange");
                _poll("onClose");
            }
            else {
                _listener = null;
            }

            return !_closed;
        },

        close: function () {
            _listener = null;
            _closed = true;
            return transport.call(_uri + "close", {get: {id: _id}});
        },

        pause: function () {
            return transport.call(_uri + "pause", {get: {id: _id}});
        },

        play: function () {
            return transport.call(_uri + "play", {get: {id: _id}});
        }
    };

    _self.__defineGetter__("duration", function () {
        return transport.call(_uri + "getDuration", {get: {id: _id}});
    });

    _self.__defineGetter__("mediaTime", function () {
        return transport.call(_uri + "getMediaTime", {get: {id: _id}});
    });

    _self.__defineSetter__("mediaTime", function (val) {
        transport.call(_uri + "setMediaTime", {get: {id: _id, value: val}});
    });

    _self.__defineGetter__("state", function () {
        return transport.call(_uri + "getState", {get: {id: _id}});
    });

    _self.__defineGetter__("volumeLevel", function () {
        return transport.call(_uri + "getVolumeLevel", {get: {id: _id}});
    });

    _self.__defineSetter__("volumeLevel", function (val) {
        transport.call(_uri + "setVolumeLevel", {get: {id: _id, value: val}});
    });

    _self.__defineGetter__("EVENT_BUFFERING_STARTED", function () {
        return "EVENT_BUFFERING_STARTED";
    });
    _self.__defineGetter__("EVENT_BUFFERING_STOPPED", function () {
        return "EVENT_BUFFERING_STOPPED";
    });
    _self.__defineGetter__("EVENT_CLOSED", function () {
        return "EVENT_CLOSED";
    });
    _self.__defineGetter__("EVENT_DEVICE_AVAILABLE", function () {
        return "EVENT_DEVICE_AVAILABLE";
    });
    _self.__defineGetter__("EVENT_DEVICE_UNAVAILABLE", function () {
        return "EVENT_DEVICE_UNAVAILABLE";
    });
    _self.__defineGetter__("EVENT_DURATION_UPDATED", function () {
        return "EVENT_DURATION_UPDATED";
    });
    _self.__defineGetter__("EVENT_END_OF_MEDIA", function () {
        return "EVENT_END_OF_MEDIA";
    });
    _self.__defineGetter__("EVENT_ERROR", function () {
        return "EVENT_ERROR";
    });
    _self.__defineGetter__("EVENT_RECORD_ERROR", function () {
        return "EVENT_ERROR";
    });
    _self.__defineGetter__("EVENT_RECORD_STARTED", function () {
        return "EVENT_RECORD_STARTED";
    });
    _self.__defineGetter__("EVENT_RECORD_STOPPED", function () {
        return "EVENT_RECORD_STOPPED";
    });
    _self.__defineGetter__("EVENT_SIZE_CHANGED", function () {
        return "EVENT_SIZE_CHANGED";
    });
    _self.__defineGetter__("EVENT_STARTED", function () {
        return "EVENT_STARTED";
    });
    _self.__defineGetter__("EVENT_STOPPED", function () {
        return "EVENT_STOPPED";
    });
    _self.__defineGetter__("EVENT_STOPPED_AT_TIME", function () {
        return "EVENT_STOPPED_AT_TIME";
    });
    _self.__defineGetter__("EVENT_VOLUME_CHANGED", function () {
        return "EVENT_VOLUME_CHANGED";
    });

    return _self;
}

Player.__defineGetter__("TIME_UNKNOWN", function () {
    return -1;
});
Player.__defineGetter__("CLOSED", function () {
    return 0;
});
Player.__defineGetter__("UNREALIZED", function () {
    return 100;
});
Player.__defineGetter__("REALIZED", function () {
    return 200;
});
Player.__defineGetter__("PREFETCHED", function () {
    return 300;
});
Player.__defineGetter__("STARTED", function () {
    return 400;
});

module.exports = Player;

});
define('ripple/platform/webworks.handset/2.0.0/client/menu', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    MenuItem = require('ripple/platform/webworks.handset/2.0.0/client/MenuItem'),
    utils = require('ripple/utils'),
    onSelect,
    _items = {},
    _uri = "blackberry/ui/menu/",
    _self;

_self = {
    addMenuItem: function (menuItem) {
        _items[menuItem.id] = menuItem;

        transport.call(_uri + "addMenuItem", {
            get: {"item": menuItem}
        });

        if (utils.count(_items) === 1) {
            transport.poll(_uri + "onSelect", {}, function (response) {
                var item = _items[response];

                if (item && item.callback) {
                    item.callback();
                }

                return !!utils.count(_items);
            });
        }
    },

    clearMenuItems: function () {
        _items = {};
        transport.call(_uri + "clearMenuItems");
    },

    getMenuItems: function () {
        return utils.map(_items, function (item) {
            var menuItem = new MenuItem(item.isSeparator, item.ordinal, item.caption, item.callback);
            menuItem.id = item.id;
            menuItem.isDefault = item.isDefault;
            return menuItem;
        });
    },

    hasMenuItem: function (menuItem) {
        return !!_items[menuItem.id];
    },

    open: function () {
        transport.call(_uri + "open", {async: true});
    },

    removeMenuItem: function (menuItem) {
        delete _items[menuItem.id];
        transport.call(_uri + "removeMenuItem", {
            get: {item: menuItem}
        });
    },

    setDefaultMenuItem: function (menuItem) {
        utils.forEach(_items, function (item) {
            item.isDefault = false;
        });

        _items[menuItem.id].isDefault = true;

        transport.call(_uri + "setDefaultMenuItem", {
            get: {id: menuItem.id}
        });
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/identity', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/identity/",
    _self;

_self = {
    getDefaultService: function () {
        return transport.call(_uri + "getDefaultService");
    },
    getServiceList: function () {
        return transport.call(_uri + "getServiceList");
    },
    getTransportList: function () {
        return transport.call(_uri + "getTransportList");
    }
};

_self.__defineGetter__("IMEI", function () {
    return transport.call(_uri + "IMEI");
});

_self.__defineGetter__("IMSI", function () {
    return transport.call(_uri + "IMSI");
});

_self.__defineGetter__("PIN", function () {
    return transport.call(_uri + "PIN");
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/messaging', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {};

});
define('ripple/platform/webworks.handset/2.0.0/client/CalendarArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.CalendarArguments ( )
//blackberry.invoke.CalendarArguments ( date : Date )
//blackberry.invoke.CalendarArguments ( appointment : blackberry.pim.Appointment )
var _self = function () {
    //readonly  property  Appointment   appointment
    //readonly  property  Date   date
    //readwrite  property  Number   view
    return {
        appointment: undefined,
        date: undefined,
        view: 0
    };
};

//const Number  VIEW_NEW  = 0
_self.__defineGetter__("VIEW_NEW", function () {
    return 0;
});
//const Number  VIEW_VIEW  = 1
_self.__defineGetter__("VIEW_VIEW", function () {
    return 1;
});
//const Number  VIEW_AGENDA  = 2
_self.__defineGetter__("VIEW_AGENDA", function () {
    return 2;
});
//const Number  VIEW_DAY  = 3
_self.__defineGetter__("VIEW_DAY", function () {
    return 3;
});
//const Number  VIEW_DEFAULT  = 4
_self.__defineGetter__("VIEW_DEFAULT", function () {
    return 4;
});
//const Number  VIEW_MONTH  = 5
_self.__defineGetter__("VIEW_MONTH", function () {
    return 5;
});
//const Number  VIEW_WEEK  = 6
_self.__defineGetter__("VIEW_WEEK", function () {
    return 6;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/CameraArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.CameraArguments ( )
var _self = function () {
    return {
        //readwrite  property  Number   view
        view: 0
    };
};

//const Number  VIEW_CAMERA  = 0
_self.__defineGetter__("VIEW_CAMERA", function () {
    return 0;
});
//const Number  VIEW_RECORDER  = 1
_self.__defineGetter__("VIEW_RECORDER", function () {
    return 1;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/PushData', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function PushData(data, port) {
    this.port = port;
    this.data = data;

    this.getHeaderField = function (field) {
        if (field === undefined || field === null) {
            throw "no field specified";
        }
        else if (!(typeof field === 'number' && field >= 0) && typeof field !== 'string') {
            throw "field is not valid";
        }

        return data.headerField[field];
    };

    this.getRequestURI =  function () {
        return data.requestURI;
    };

    this.getSource = function () {
        return data.source;
    };

    this.isChannelEncrypted = data.isChannelEncrypted;

    this.payload = data.payload;

    this.__defineGetter__("ACCEPT", function () {
        return 0;
    });
    this.__defineGetter__("DECLINE_USERDCR", function () {
        return 1;
    });
    this.__defineGetter__("DECLINE_USERDCU", function () {
        return 2;
    });
    this.__defineGetter__("DECLINE_USERPND", function () {
        return 3;
    });
    this.__defineGetter__("DECLINE_USERREQ", function () {
        return 4;
    });
    this.__defineGetter__("DECLINE_USERRFS", function () {
        return 5;
    });
}

module.exports = PushData;

});
define('ripple/platform/webworks.handset/2.0.0/client/identity/phone', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/identity/phone/",
    _self;

_self = {
    getLineIds: function () {
        return transport.call(_uri + "getLineIds");
    },
    getLineLabel: function (id) {
        return transport.call(_uri + "getLineLabel", {get: {id: id}});
    },
    getLineNumber: function (id) {
        return transport.call(_uri + "getLineNumber", {get: {id: id}});
    },
    getLineType: function (id) {
        return transport.call(_uri + "getLineType", {get: {id: id}});
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/identity/Service', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function Service() {
    return {
        emailAddress: null,
        isDefault: null,
        name: null,
        type: null
    };
}

Service.__defineGetter__("TYPE_EMAIL", function () {
    return 0;
});

Service.__defineGetter__("TYPE_CALENDAR", function () {
    return 1;
});

Service.__defineGetter__("TYPE_CONTACT", function () {
    return 2;
});

module.exports = Service;

});
define('ripple/platform/webworks.handset/2.0.0/client/identity/Transport', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function Transport(name, type) {
    this.__defineGetter__("name", function () {
        return name || "";
    });
    this.__defineGetter__("type", function () {
        return type || "";
    });
}

module.exports = Transport;

});
define('ripple/platform/webworks.handset/2.0.0/client/Reminder', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Reminder = function () {

    return {
        //readwrite  property  Date   date
        //readwrite  property  Number   relativeHours
        //readwrite  property  Number   type

        date: null,
        relativeHours: null,
        type: null

    };

};

Reminder.__defineGetter__("DATE", function () {
    return 0;
});

Reminder.__defineGetter__("RELATIVE", function () {
    return 1;
});

module.exports = Reminder;

});
define('ripple/platform/webworks.handset/2.0.0/client/systemEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    utils = require('ripple/utils'),
    _self,
	_callbacks = {};

function _poll(evt, args, callback) {
    _callbacks[evt + args.key] = callback;

    transport.poll("blackberry/system/event/" + evt, {get: args}, function () {
        var func = _callbacks[evt + args.key];

        if (func) {
            func();
        }

        return !!func;
    });
}

_self = {
    onCoverageChange: function (callback) {
        _poll("onCoverageChange", {}, callback);
    },

    onHardwareKey: function (key, callback) {
        _poll("onHardwareKey", {key: key}, callback);
    }
};

_self.__defineGetter__("KEY_BACK", function () {
    return 0;
});
_self.__defineGetter__("KEY_MENU", function () {
    return 1;
});
_self.__defineGetter__("KEY_CONVENIENCE_1", function () {
    return 2;
});
_self.__defineGetter__("KEY_CONVENIENCE_2", function () {
    return 3;
});
_self.__defineGetter__("KEY_STARTCALL", function () {
    return 4;
});
_self.__defineGetter__("KEY_ENDCALL", function () {
    return 5;
});
_self.__defineGetter__("KEY_VOLUMEDOWN", function () {
    return 6;
});
_self.__defineGetter__("KEY_VOLUMEUP", function () {
    return 7;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/Attendee', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function Attendee() {
    return {
        //readwrite  property  String   address
        //readwrite  property  Number   type

        address: null,
        type: null
    };
}

Attendee.__defineGetter__("ORGANIZER", function () {
    return 0;
});

Attendee.__defineGetter__("INVITED", function () {
    return 1;
});

Attendee.__defineGetter__("ACCEPTED", function () {
    return 2;
});

Attendee.__defineGetter__("DECLINED", function () {
    return 3;
});

Attendee.__defineGetter__("TENTATIVE", function () {
    return 4;
});

module.exports =  Attendee;

});
define('ripple/platform/webworks.handset/2.0.0/client/audio', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    supportedContentTypes: function (protocol) {
        return protocol === 'rtsp' ?
            ['audio/amr', 'audio/mp4', 'audio/aac'] :
            ['audio/midi', 'mpeg', 'x-wav', 'amr', 'basic', 'x-gsm', 'mp4', 'aac', 'x-ms-wma', 'flac', 'ogg'];
    },
    supportedProtocols: function (contentType) {
        return ['http', 'file', 'rtsp'];
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/client/category', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/pim/category/",
    _self;

_self = {
    addCategory: function (categoryName) {
        transport.call(_uri + "addCategory", {
            get: {categoryName: categoryName}
        });
    },
    deleteCategory: function (categoryName) {
        transport.call(_uri + "deleteCategory", {
            get: {categoryName: categoryName}
        });
    },
    getCategories: function () {
        return transport.call(_uri + "getCategories");
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/client/PhoneArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.PhoneArguments ( [dialString : String ] ,  [smartDialing : Boolean ] ,  [lineId : Number ] )
var _self = function (dialString, smartDialing, lineId) {
    return {
        dialString: dialString,
        smartDialing: smartDialing,
        lineId: (lineId ? lineId : -1),
        view: 0
    };
};

//const Number  VIEW_NEW  = 0
_self.__defineGetter__("VIEW_CALL", function () {
    return 0;
});
//const Number  VIEW_DEFAULT  = 1
_self.__defineGetter__("VIEW_VOICEMAIL", function () {
    return 1;
});

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/spec/events', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    events = require('ripple/platform/webworks.core/2.0.0/spec/events');

_self = {
    "system.event.onExit": {
        callback: function () {
            event.trigger("AppExit");
        }
    },
    "system.event.onCoverageChange": {
        callback: function () {
            event.trigger("CoverageChange");
        }
    },
    "system.event.onHardwareKey": {
        args: [
            "Back",
            "Menu",
            "Convenience 1",
            "Convenience 2",
            "Start Call",
            "End Call",
            "Volume Down",
            "Volume Up"
        ],
        callback: function (key) {
            event.trigger("HardwareKey", [key]);
        }
    }
};

utils.mixin(events, _self);

module.exports = _self;

});
define('ripple/platform/webworks.handset/2.0.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

module.exports = {
    "transports": {
        "TCP Cellular": {
            "name": "Cellular TCP",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "Wap": {
            "name": "WAP",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "Wap 2.0": {
            "name": "WAP 2.0",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "MDS": {
            "name": "MDS",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "Bis B": {
            "name": "BIS B",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "Unite!": {
            "name": "Unite",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "TCP Wifi": {
            "name": "Wifi TCP",
            "control": {
                "type": "checkbox",
                "value": true
            }
        }
    },
    "identity": {
        "IMEI": {
            "name": "IMEI",
            "control": {
                "type": "text",
                "value": "123456786543210"
            }
        },
        "IMSI": {
            "name": "IMSI",
            "control": {
                "type": "text",
                "value": "310150123456789"
            }
        },
        "PIN": {
            "name": "PIN",
            "control": {
                "type": "text",
                "value": "43A8C489"
            }
        }
    },
    "system": {
        "isMassStorageActive": {
            "name": "Mass Storage Is Connected",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "hasDataCoverage": {
            "name": "Has Data Coverage",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("CoverageChange");
                require('ripple/bus').send("network", setting);
            }
        },
        "lag": {
            "name": "Lag the network",
            "control": {
                type: "checkbox",
                value: false
            },
            "callback": function (setting) {
                require('ripple/bus').send("lag", setting);
            }
        },
        "network": {
            "name": "Data Network",
            "control": {
                "type": "select",
                "value": "3GPP"
            },
            "options": {
                "3GPP" : "3GPP",
                "CDMA": "CDMA",
                "iDEN": "iDEN",
                "Wi-Fi": "Wi-Fi"
            },
            "callback": function (setting) {
                event.trigger("CoverageChange");
            }
        }
    }
};

});
define('ripple/platform/webworks.handset/2.0.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        "deviceSettings",
        "geoView",
        "platformEvents",
        "widgetConfig",
        "messaging",
        "push",
        "phone",
        "build"
    ]
};

});
define('ripple/platform/webworks.handset/2.0.0/spec', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    id: "webworks.handset",
    version: "2.0.0",
    name: "WebWorks",

    persistencePrefix: "rim-handset-",

    ui: require('ripple/platform/webworks.handset/2.0.0/spec/ui'),
    device: require('ripple/platform/webworks.handset/2.0.0/spec/device'),
    config: require('ripple/platform/webworks.core/2.0.0/spec/config'),
    events: require('ripple/platform/webworks.handset/2.0.0/spec/events'),

    initialize: function () {},

    objects: {
        XMLHttpRequest: {
            path: "webworks.handset/2.0.0/XMLHttpRequest"
        },
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        navigator: {
            path: "w3c/1.0/navigator",
            children: {
                geolocation: {
                    path: "w3c/1.0/geolocation"
                }
            }
        },
        blackberry: {
            path: "webworks.handset/2.0.0/client/blackberry",
            children: {
                pim: {
                    path: "webworks.handset/2.0.0/client/pim",
                    feature: "blackberry.pim.category|blackberry.pim.Task|blackberry.pim.Recurrence|blackberry.pim.Reminder|blackberry.pim.Appointment|blackberry.pim.Address|blackberry.pim.Attendee|blackberry.pim.Memo|blackberry.pim.Contact",
                    children: {
                        category: {
                            path: "webworks.handset/2.0.0/client/category",
                            feature: "blackberry.pim.category"
                        },
                        Task: {
                            path: "webworks.handset/2.0.0/client/Task",
                            feature: "blackberry.pim.Task"
                        },
                        Recurrence: {
                            path: "webworks.handset/2.0.0/client/Recurrence",
                            feature: "blackberry.pim.Recurrence"
                        },
                        Reminder: {
                            path: "webworks.handset/2.0.0/client/Reminder",
                            feature: "blackberry.pim.Reminder"
                        },
                        Appointment: {
                            path: "webworks.handset/2.0.0/client/Appointment",
                            feature: "blackberry.pim.Appointment"
                        },
                        Address: {
                            path: "webworks.handset/2.0.0/client/Address",
                            feature: "blackberry.pim.Address"
                        },
                        Attendee: {
                            path: "webworks.handset/2.0.0/client/Attendee",
                            feature: "blackberry.pim.Attendee"
                        },
                        Memo: {
                            path: "webworks.handset/2.0.0/client/Memo",
                            feature: "blackberry.pim.Memo"
                        },
                        Contact: {
                            path: "webworks.handset/2.0.0/client/Contact",
                            feature: "blackberry.pim.Contact"
                        }
                    }
                },
                phone: {
                    children: {
                        Phone: {
                            path: "webworks.handset/2.0.0/client/Phone",
                            feature: "blackberry.phone.Phone"
                        },
                        PhoneLogs: {
                            path: "webworks.handset/2.0.0/client/PhoneLogs",
                            feature: "blackberry.phone.PhoneLogs|blackberry.phone.Find",
                            children: {
                                CallLog: {
                                    path: "webworks.handset/2.0.0/client/CallLog"
                                }
                            }
                        },
                        Find: {
                            children: {
                                FilterExpression: {
                                    path: "webworks.handset/2.0.0/client/FilterExpression",
                                    feature: "blackberry.phone.Find"
                                }
                            }
                        }
                    }
                },
                message: {
                    path: "webworks.handset/2.0.0/client/messaging",
                    feature: "blackberry.message.sms|blackberry.message",
                    children: {
                        sms: {
                            path: "webworks.handset/2.0.0/client/sms",
                            feature: "blackberry.message.sms"
                        },
                        Message: {
                            path: "webworks.handset/2.0.0/client/Message",
                            feature: "blackberry.message"
                        }
                    }
                },
                transport: {
                    path: "webworks.core/2.0.0/client/transport"
                },
                events: {
                    path: "webworks.core/2.0.0/client/events"
                },
                app: {
                    path: "webworks.handset/2.0.0/client/app",
                    feature: "blackberry.app",
                    children: {
                        event: {
                            path: "webworks.handset/2.0.0/client/appEvent",
                            feature: "blackberry.app.event"
                        }
                    }
                },
                invoke: {
                    path: "webworks.handset/2.0.0/client/invoke",
                    feature: "blackberry.invoke",
                    children: {
                        AddressBookArguments: {
                            path: "webworks.handset/2.0.0/client/AddressBookArguments",
                            feature: "blackberry.invoke.AddressBookArguments"
                        },
                        BrowserArguments: {
                            path: "webworks.handset/2.0.0/client/BrowserArguments",
                            feature: "blackberry.invoke.BrowserArguments"
                        },
                        CameraArguments: {
                            path: "webworks.handset/2.0.0/client/CameraArguments",
                            feature: "blackberry.invoke.CameraArguments"
                        },
                        CalendarArguments: {
                            path: "webworks.handset/2.0.0/client/CalendarArguments",
                            feature: "blackberry.invoke.CalendarArguments"
                        },
                        JavaArguments: {
                            path: "webworks.handset/2.0.0/client/JavaArguments",
                            feature: "blackberry.invoke.JavaArguments"
                        },
                        MapsArguments: {
                            path: "webworks.handset/2.0.0/client/MapsArguments",
                            feature: "blackberry.invoke.MapsArguments"
                        },
                        MemoArguments: {
                            path: "webworks.handset/2.0.0/client/MemoArguments",
                            feature: "blackberry.invoke.MemoArguments"
                        },
                        MessageArguments: {
                            path: "webworks.handset/2.0.0/client/MessageArguments",
                            feature: "blackberry.invoke.MessageArguments"
                        },
                        PhoneArguments: {
                            path: "webworks.handset/2.0.0/client/PhoneArguments",
                            feature: "blackberry.invoke.PhoneArguments"
                        },
                        SearchArguments: {
                            path: "webworks.handset/2.0.0/client/SearchArguments",
                            feature: "blackberry.invoke.SearchArguments"
                        },
                        TaskArguments: {
                            path: "webworks.handset/2.0.0/client/TaskArguments",
                            feature: "blackberry.invoke.TaskArguments"
                        }
                    }
                },
                identity: {
                    path: "webworks.handset/2.0.0/client/identity",
                    feature: "blackberry.identity",
                    children: {
                        Transport: {
                            path: "webworks.handset/2.0.0/client/identity/Transport",
                            feature: "blackberry.identity"
                        },
                        Service: {
                            path: "webworks.handset/2.0.0/client/identity/Service",
                            feature: "blackberry.identity"
                        },
                        phone: {
                            path: "webworks.handset/2.0.0/client/identity/phone",
                            feature: "blackberry.identity.phone"
                        }
                    }
                },
                system: {
                    path: "webworks.handset/2.0.0/client/system",
                    feature: "blackberry.system",
                    children: {
                        event: {
                            path: "webworks.handset/2.0.0/client/systemEvent",
                            feature: "blackberry.system.event"
                        }
                    }
                },
                ui: {
                    children: {
                        dialog: {
                            path: "webworks.core/2.0.0/client/dialog",
                            feature: "blackberry.ui.dialog"
                        },
                        menu: {
                            path: "webworks.handset/2.0.0/client/menu",
                            children: {
                                MenuItem: {
                                    path: "webworks.handset/2.0.0/client/MenuItem"
                                }
                            }
                        }
                    }
                },
                utils: {
                    path: "webworks.core/2.0.0/client/utils",
                    feature: "blackberry.utils"
                },
                find: {
                    feature: "blackberry.find",
                    children: {
                        FilterExpression: {
                            path: "webworks.handset/2.0.0/client/FilterExpression",
                            feature: "blackberry.find"
                        }
                    }
                },
                push: {
                    path: "webworks.handset/2.0.0/client/push",
                    feature: "blackberry.push"
                },
                audio: {
                    path: "webworks.handset/2.0.0/client/audio",
                    feature: "blackberry.audio",
                    children: {
                        Player: {
                            path: "webworks.handset/2.0.0/client/AudioPlayer",
                            feature: "blackberry.audio.Player"
                        }
                    }
                },
                io: {
                    children: {
                        dir: {
                            path: "webworks.handset/2.0.0/client/io/dir",
                            feature: "blackberry.io.dir"
                        },
                        file: {
                            path: "webworks.core/2.0.0/client/io/file",
                            feature: "blackberry.io.file"
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/phonegap/1.0.0/AudioCodecAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, compFormats, encode, decode) {
    return {
        info: info,
        id: id,
        compFormats: compFormats,
        encode: encode,
        decode: decode
    };
};

});
define('ripple/platform/phonegap/1.0.0/DisplayDeviceAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (orientation, brightness, contrast, blanked, dotsPerInchW, dotsPerInchH, physicalWidth, physicalHeight, info) {
    return {
        orientation: orientation,
        brightness: brightness,
        contrast: contrast,
        blanked: blanked,
        dotsPerInchW: dotsPerInchW,
        dotsPerInchH: dotsPerInchH,
        physicalWidth: physicalWidth,
        physicalHeight: physicalHeight,
        info: info
    };
};

});
define('ripple/platform/phonegap/1.0.0/StorageUnitAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, type, isWritable, capacity, availableCapacity, isRemoveable) {
    return {
        info: info,
        id: id,
        type: type,
        isWritable: isWritable,
        capacity: capacity,
        availableCapacity: availableCapacity,
        isRemoveable: isRemoveable
    };
};

});
define('ripple/platform/phonegap/1.0.0/orientation', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    currentOrientation: null,
    getCurrentOrientation: function (onSuccess, onFail) {
        throw "not implemented";
    },
    watchOrientation: function () {
        throw "not implemented";
    }
};

});
define('ripple/platform/phonegap/1.0.0/InputDevicesAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, pointingDevices, activePointingDevices, keyboards, activeKeyboards, cameras, activeCameras, microphones, activeMicrophones) {
    return {
        info: info,
        id: id,
        pointingDevices: pointingDevices,
        activePointingDevices: activePointingDevices,
        keyboards: keyboards,
        activeKeyboards: activeKeyboards,
        cameras: cameras,
        activeCameras: activeCameras,
        microphones: microphones,
        activeMicrophones: activeMicrophones
    };

};

});
define('ripple/platform/phonegap/1.0.0/ContactAddress', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (pref, type, formatted, streetAddress, locality, region, postalCode, country, id) {
    return {
        pref: pref || null,
        type: type || null,
        formatted: formatted || null,
        streetAddress: streetAddress || null,
        locality: locality || null,
        region: region || null,
        postalCode: postalCode || null,
        country: country || null,
        id: id || null
    };
};

});
define('ripple/platform/phonegap/1.0.0/telephony', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    send: function () {
        throw "not implemented";
    }
};

});
define('ripple/platform/phonegap/1.0.0/PowerAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, level, timeRemaining, isBattery, isCharging) {
    return {
        info: info,
        id: id,
        level: level,
        timeRemaining: timeRemaining,
        isBattery: isBattery,
        isCharging: isCharging
    };
};

});
define('ripple/platform/phonegap/1.0.0/ContactError', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function ContactError(code) {
    this.code = code || null;
}

ContactError.UNKNOWN_ERROR = 0;
ContactError.INVALID_ARGUMENT_ERROR = 1;
ContactError.NOT_FOUND_ERROR = 2;
ContactError.TIMEOUT_ERROR = 3;
ContactError.PENDING_OPERATION_ERROR = 4;
ContactError.IO_ERROR = 5;
ContactError.NOT_SUPPORTED_ERROR = 6;
ContactError.PERMISSION_DENIED_ERROR = 20;

module.exports = ContactError;

});
define('ripple/platform/phonegap/1.0.0/ThermalAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, state) {
    return {
        info: info,
        id: id,
        state: state
    };
};

});
define('ripple/platform/phonegap/1.0.0/MicrophoneAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (type, freqRangeLow, freqRangeHigh, info, name, types) {
    return {
        type: type,
        freqRangeLow: freqRangeLow,
        freqRangeHigh: freqRangeHigh,
        info: info,
        name: name,
        types: types
    };
};

});
define('ripple/platform/phonegap/1.0.0/map', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    show: function () {
        throw "not implemented";
    }
};

});
define('ripple/platform/phonegap/1.0.0/ContactAccount', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (domain, username, userid) {
    return {
        domain: domain,
        username: username,
        userid: userid
    };
};

});
define('ripple/platform/phonegap/1.0.0/accelerometer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Acceleration = require('ripple/platform/phonegap/1.0.0/Acceleration'),
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    _accelerometerInfo = new Acceleration(),
    _watches = {},
    self;

module.exports = self = {
    getCurrentAcceleration: function (onSuccess, onError) {
        // TODO: implement error call if accelerometer is not available, to be driven by behaviours?

        if (typeof onSuccess === "function") {
            setTimeout(function () {
                // TODO: build facility to trigger onError() from emulator
                // see pivotal item: https://www.pivotaltracker.com/story/show/7040343
                onSuccess(utils.copy(_accelerometerInfo));
            }, 1);
        }

    },

    watchAcceleration: function (accelerometerSuccess, accelerometerError, accelerometerOptions) {
        var watchId = (new Date()).getTime().toString(),
            watchObj = {};


        if (accelerometerOptions &&
                accelerometerOptions.frequency && typeof
                accelerometerOptions.frequency === "number" &&
                accelerometerOptions.frequency === Math.floor(accelerometerOptions.frequency)) {

            watchObj = {
                onSuccess: accelerometerSuccess,
                onError: accelerometerError,
                interval: accelerometerOptions.frequency
            };

            _watches[watchId] = watchObj;

            _watches[watchId].intervalId = setInterval(function () {
                self.getCurrentAcceleration(_watches[watchId].onSuccess, _watches[watchId].onError);
            }, accelerometerOptions.frequency);

        }
        else {
            if (typeof accelerometerError === "function") {
                setTimeout(function () {
                    accelerometerError();
                }, 1);
            }
        }

        return watchId;
    },

    clearWatch: function (watchId) {
        clearInterval(_watches[watchId].intervalId);
    }
};

event.on("AccelerometerInfoChangedEvent", function (accelerometerInfo) {
    _accelerometerInfo.x = accelerometerInfo.accelerationIncludingGravity.x / 9.8;
    _accelerometerInfo.y = accelerometerInfo.accelerationIncludingGravity.y / 9.8;
    _accelerometerInfo.z = accelerometerInfo.accelerationIncludingGravity.z / 9.8;
    _accelerometerInfo.timestamp = (new Date()).getTime();
});

});
define('ripple/platform/phonegap/1.0.0/PointerAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (type, supportsMultiTouch, info) {
    return {
        type: type,
        supportsMultiTouch: supportsMultiTouch,
        info: info
    };
};

});
define('ripple/platform/phonegap/1.0.0/PrintingDeviceAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (type, resolution, color, info) {
    return {
        type: type,
        resolution: resolution,
        color: color,
        info: info
    };
};

});
define('ripple/platform/phonegap/1.0.0/NetworkStatus', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    NOT_REACHABLE: 0,
    REACHABLE_VIA_CARRIER_DATA_NETWORK: 1,
    REACHABLE_VIA_WIFI_NETWORK: 2
};

});
define('ripple/platform/phonegap/1.0.0/SystemInfoOptions', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (highThreshold, lowThreshold, thresholdTarget, timeout, id) {
    return {
        highThreshold: highThreshold,
        lowThreshold: lowThreshold,
        thresholdTarget: thresholdTarget,
        timeout: timeout,
        id: id
    };
};

});
define('ripple/platform/phonegap/1.0.0/ConnectionAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, type, currentOrientation, currentUploadBandwidth, maxDownloadBandwidth, maxUploadBandwidth, currentSignalStrength, roaming) {
    return {
        info: info,
        id: id,
        type: type,
        currentDownloadBandwidth: currentOrientation,
        currentUploadBandwidth: currentUploadBandwidth,
        maxDownloadBandwidth: maxDownloadBandwidth,
        maxUploadBandwidth: maxUploadBandwidth,
        currentSignalStrength: currentSignalStrength,
        roaming: roaming
    };
};

});
define('ripple/platform/phonegap/1.0.0/ContactName', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (formatted, familyName, givenName, middleName, honorificPrefix, honorificSuffix) {
    return {
        formatted: formatted,
        familyName: familyName,
        givenName: givenName,
        middleName: middleName,
        honorificPrefix: honorificPrefix,
        honorificSuffix: honorificSuffix
    };
};

});
define('ripple/platform/phonegap/1.0.0/KeyboardAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (type, isHardware, info) {
    return {
        type: type,
        isHardware: isHardware,
        info: info
    };
};

});
define('ripple/platform/phonegap/1.0.0/CameraAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (supportsVideo, hasFlash, sensorPixels, maxZoomFactor) {
    return {
        supportsVideo: supportsVideo,
        hasFlash: hasFlash,
        sensorPixels: sensorPixels,
        maxZoomFactor: maxZoomFactor
    };

};

});
define('ripple/platform/phonegap/1.0.0/Connection', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    UNKNOWN: "unknown",
    ETHERNET: "ethernet",
    WIFI: "wifi",
    CELL_2G: "2g",
    CELL_3G: "3g",
    CELL_4G: "4g",
    NONE: "none"
};

});
define('ripple/platform/phonegap/1.0.0/Contact', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    event = require('ripple/event');

function _properties(obj) {
    var prop, newObj = {};
    for (prop in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, prop)) {
            if (typeof obj[prop] !== "function") {
                newObj[prop] = utils.copy(obj[prop]);
            }
        }
    }
    return newObj;
}

module.exports = function (
        id,
        displayName,
        name,
        nickname,
        phoneNumbers,
        emails,
        addresses,
        ims,
        organizations,
        birthday,
        note,
        photos,
        categories,
        urls
) {

    return {
        id: id || Math.uuid(undefined, 16),
        displayName: displayName || null,
        name: name || null,
        nickname: nickname || null,
        phoneNumbers: phoneNumbers || null,
        emails: emails || null,
        addresses: addresses || null,
        ims: ims || null,
        organizations: organizations || null,
        birthday: birthday || null,
        note: note || null,
        photos: photos || null,
        categories: categories || null,
        urls: urls || null,
        save: function (success, error) {
            var _self = this,
                lastUpdated = this.updated; // hackish

            this.updated = new Date();

            if (!this.id) {
                this.id = Math.uuid(undefined, 16);
            }

            event.trigger("phonegap-contact-save", [_properties(this), success, function (e) {
                _self.updated = lastUpdated;
                error(e);
            }]);
        },
        remove: function (success, error) {
            event.trigger("phonegap-contact-remove", [this.id, success, error]);
        },
        clone: function () {
            var copy = utils.copy(this);
            copy.id = null;
            return copy;
        }
    };
};

});
define('ripple/platform/phonegap/1.0.0/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self = {},
    event = require('ripple/event'),
    devices = require('ripple/devices');


event.on("HardwareKey", function (key) {
    event.trigger("HardwareKeyDefault", [key]);
});

_self.__defineGetter__("name", function () {
    return devices.getCurrentDevice().name;
});

_self.__defineGetter__("platform", function () {
    return devices.getCurrentDevice().osName;
});

_self.__defineGetter__("uuid", function () {
    return devices.getCurrentDevice().uuid;
});

_self.__defineGetter__("version", function () {
    return devices.getCurrentDevice().osVersion;
});

_self.phonegap = "placeholder string";

module.exports = _self;

});
define('ripple/platform/phonegap/1.0.0/sms', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    send: function () {
        throw "not implemented";
    }
};

});
define('ripple/platform/phonegap/1.0.0/navigator', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var nav = require('ripple/platform/w3c/1.0/navigator'),
    event = require('ripple/event'),
    _console = require('ripple/console'),
    utils = require('ripple/utils'),
    emulatorBridge = require('ripple/emulatorBridge'),
    _self = {};

event.on("TinyHipposLoaded", function () {
    var doc = emulatorBridge.document(),
        evt = doc.createEvent("Events");
    evt.initEvent("deviceready", true, true);
    doc.dispatchEvent(evt);
    _console.log("fired deviceready event!");
});

utils.mixin(nav, _self);

module.exports = _self;

});
define('ripple/platform/phonegap/1.0.0/NetworkAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, activeConnections) {
    return {
        info: info,
        id: id,
        activeConnections: activeConnections || []
    };
};

});
define('ripple/platform/phonegap/1.0.0/AVCodecsAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, audioCodecs, videoCodecs) {
    return {
        info: info,
        id: id,
        audioCodecs: audioCodecs,
        videoCodecs: videoCodecs
    };
};

});
define('ripple/platform/phonegap/1.0.0/Acceleration', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (x, y, z) {
    return {
        x: x || 0,
        y: y || 0,
        z: z || 0,
        timestamp: new Date().getTime()
    };
};

});
define('ripple/platform/phonegap/1.0.0/ContactField', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (type, value, pref) {
    return {
        type: type,
        value: value,
        pref: pref || false
    };
};

});
define('ripple/platform/phonegap/1.0.0/system', function (require, exports, module) {
module.exports = {
    get: function () {
        throw "not implemented";
    },
    has: function () {
        throw "not implemented";
    },
    monitor: function () {
        throw "not implemented";
    }
};

});
define('ripple/platform/phonegap/1.0.0/OutputDevicesAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, displayDevices, activeDisplayDevices, printingDevices, activePrintingDevice, brailleDevices, activeBrailleDevice, audioDevices, activeAudioDevices) {
    return {
        info: info,
        id: id,
        displayDevices: displayDevices,
        activeDisplayDevices: activeDisplayDevices,
        printingDevices: printingDevices,
        activePrintingDevice: activePrintingDevice,
        brailleDevices: brailleDevices,
        activeBrailleDevice: activeBrailleDevice,
        audioDevices: audioDevices,
        activeAudioDevices: activeAudioDevices
    };
};

});
define('ripple/platform/phonegap/1.0.0/PhoneGap', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    available: true
};

});
define('ripple/platform/phonegap/1.0.0/ContactFindOptions', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (filter, multiple, updatedSince) {
    return {
        filter: filter || "",
        multiple: multiple || false,
        updatedSince: updatedSince || ""
    };
};

});
define('ripple/platform/phonegap/1.0.0/camera', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    getPicture: function (cameraSuccess, cameraError, cameraOptions) {
        if (cameraError) {
            cameraError.apply(null, ["not implemented"]);
        }
        else {
            throw "not implemented";
        }
    }
};

});
define('ripple/platform/phonegap/1.0.0/BrailleDeviceAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (nbCells, info) {
    return {
        nbCells: nbCells,
        info: info
    };

};

});
define('ripple/platform/phonegap/1.0.0/service', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// for form, but could probably just delete
module.exports = {};

});
define('ripple/platform/phonegap/1.0.0/AudioDeviceAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (type, freqRangeLow, freqRangeHigh, volumeLevel, info) {
    return {
        type: type,
        freqRangeLow: freqRangeLow,
        freqRangeHigh: freqRangeHigh,
        volumeLevel: volumeLevel,
        info: info
    };

};

});
define('ripple/platform/phonegap/1.0.0/compass', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var geo = require('ripple/geo');

function _getHeading() {
    return geo.getPositionInfo().heading;
}

module.exports = {
    getCurrentHeading: function (compassSuccess, compassError, compassOptions) {
        setTimeout(function () {
            compassSuccess(_getHeading());
        }, 1);
    },
    watchHeading: function (compassSuccess, compassError, compassOptions) {
        compassOptions = compassOptions || {};
        return setInterval(function () {
            compassSuccess(_getHeading());
        }, compassOptions.frequency || 100);
    },
    clearWatch: function (watchId) {
        clearInterval(watchId);
    }
};

});
define('ripple/platform/phonegap/1.0.0/contacts', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Contact = require('./Contact'),
    ContactName = require('./ContactName'),
    ContactError = require('./ContactError'),
    ContactField = require('./ContactField'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    event = require('ripple/event'),
    _defaultContacts = 
    [{
        "id": Math.uuid(undefined, 16),
        "name": new ContactName("Brent Lintner"),
        "displayName": "Brent Lintner",
        "emails": [new ContactField("work", "brent@tinyhippos.com", false)]
    }, {
        "id": Math.uuid(undefined, 16),
        "name": new ContactName("PJ Lowe"),
        "displayName": "PJ Lowe",
        "emails": [new ContactField("work", "pj@tinyhippos.com", false)]
    }, {
        "id": Math.uuid(undefined, 16),
        "name": new ContactName("Dan Silivestru"),
        "displayName": "Dan Silivestru",
        "emails": [new ContactField("work", "dan@tinyhippos.com", false)]
    }, {
        "id": Math.uuid(undefined, 16),
        "name": new ContactName("Gord Tanner"),
        "displayName": "Gord Tanner",
        "emails": [new ContactField("work", "gord@tinyhippos.com", true)]
    }, {
        "id": Math.uuid(undefined, 16),
        "name": new ContactName("Mark McArdle"),
        "displayName": "Mark McArdle",
        "emails": [new ContactField("work", "mark@tinyhippos.com", false)]
    }],
    self;

function _error(callback, code, msg) {
    var e = new ContactError();
    e.code = code;
    e.message = msg;
    window.setTimeout(function () {
        callback(e);
    }, 1);
}


function _getContacts() {
    return db.retrieveObject("phonegap-contacts") || 
        _defaultContacts.map(function (person) {
            var contact = new Contact();
            contact.updated = new Date();
            utils.forEach(person, function (value, prop) {
                contact[prop] = value;
            });

            return contact;
        });
}

function _saveContacts(contacts) {
    db.saveObject("phonegap-contacts", contacts);
}

function _filtered(compare, options) {
    // this could be done a lot better..
    var found = false;
    if (!options.filter || options.filter === "") {
        found = true;
    } else if (typeof compare === "string" &&
              compare.match(new RegExp(".*" + options.filter + ".*", "i"))) {
        found = true;
    } else if (typeof compare === "object" || compare instanceof Array) {
        utils.forEach(compare, function (value) {
            if (!found) {
                found = _filtered(value, options);
            }
        });
    }
    return found;
}

event.on("phonegap-contact-save", function (contactProperties, success, error) {
    var contacts = _getContacts(),
        existsIndex = contacts.reduce(function (result, value, index) {
            return value.id === contactProperties.id ? index : result;
        }, -1),
        contact = existsIndex >= 0 ? contacts[existsIndex] : new Contact();

    utils.mixin(contactProperties, contact);
    if (existsIndex < 0) {
        contacts.push(contact);
    }
    _saveContacts(contacts);
    success(contact);
});

event.on("phonegap-contact-remove", function (id, success, error) {
    if (!id) {
        _error(error, ContactError.NOT_FOUND_ERROR, "id is falsy (" + id + ")");
    } else {
        var contacts = _getContacts(),
            toDelete = contacts.reduce(function (result, current, index) {
                return current.id === id ? index : result;
            }, -1);

        if (toDelete >= 0) {
            contacts.splice(toDelete, 1);
            _saveContacts(contacts);
            success();
        } else {
            _error(error, ContactError.NOT_FOUND_ERROR, "could not find contact with id (" + id + ")");
        }
    }
});

self = module.exports = {
    create: function (properties) {
        var contact = new Contact();
        utils.forEach(properties, function (value, key) {
            contact[key] = value;
        });
        return contact;
    },
    find: function (fields, success, error, options) {
        var foundContacts = [],
            tempContact = self.create(),
            contacts = _getContacts(),
            errorFlag = false;

        options = options || {};

        // not a fan of error handling at the moment
        if (!fields || !("forEach" in fields)) {
            errorFlag = true;
            _error(error, ContactError.INVALID_ARGUMENT_ERROR, "missing contact fields array");
            return;
        }

        // handle special case of ["*"] to return all fields
        if (fields.length === 1 && fields[0] === "*") {
            fields = utils.map(tempContact, function (v, k) {
                return k;
            });
        }

        fields.forEach(function (prop) {
            if (!(tempContact.hasOwnProperty(prop))) {
                errorFlag = true;
                _error(error, ContactError.INVALID_ARGUMENT_ERROR, "invalid contact field (" + prop + ")");
            }
        });

        if (typeof success !== "function" && !errorFlag) {
            errorFlag = true;
            _error(error, ContactError.INVALID_ARGUMENT_ERROR, "missing success callback");
        }

        if (errorFlag) {
            return;
        }

        if (fields.length > 0) {
            contacts.forEach(function (contact, index) {
                var newContact = utils.copy(contact);

                if (options && (!_filtered(contact, options) ||
                        options.updatedSince && contact.updated && contact.updated.getTime() < options.updatedSince.getTime())) {
                    return;
                }

                utils.forEach(newContact, function (value, prop) {
                    if (typeof newContact[prop] !== "function" && prop !== "id" &&
                        !fields.some(function (field) {
                            return field === prop;
                        })) {
                        delete newContact[prop];
                    }
                });

                foundContacts.push(newContact);
            });
        }

        window.setTimeout(function () {
            // TODO: don't loop over entire db just to slice the array
            if (options.multiple === false) {
                foundContacts = foundContacts.splice(0, 1);
            }
            success(foundContacts);
        }, 1);
    }
};

});
define('ripple/platform/phonegap/1.0.0/CPUAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, usage) {
    return {
        info: info,
        id: id,
        usage: usage
    };
};

});
define('ripple/platform/phonegap/1.0.0/VideoCodecAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (info, id, compFormats, containerFormats, hwAccel, profiles, frameTypes, rateTypes) {
    return {
        info: info,
        id: id,
        compFormats: compFormats,
        containerFormats: containerFormats,
        hwAccel: hwAccel,
        profiles: profiles,
        frameTypes: frameTypes,
        rateTypes: rateTypes
    };
};

});
define('ripple/platform/phonegap/1.0.0/spec/events', function (require, exports, module) {
function _fires(name, data) {
    return function () {
        var doc = require("ripple/emulatorBridge").document(),
            evt = doc.createEvent("Events");

        evt.initEvent(name, true, false);
        doc.dispatchEvent(evt);
    };
}

module.exports = {
    "deviceready": {
        callback: _fires("deviceready")
    },
    "backbutton": {
        callback: _fires("backbutton")
    },
    "menubutton": {
        callback: _fires("menubutton")
    },
    "pause": {
        callback: _fires("pause")
    },
    "resume": {
        callback: _fires("resume")
    },
    "searchbutton": {
        callback: _fires("searchbutton")
    },
    "online": {
        callback: _fires("online")
    },
    "offline": {
        callback: _fires("offline")
    }
};

});
define('ripple/platform/phonegap/1.0.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

module.exports = {
    "NetworkStatus": {
        "connectionType": {
            "name": "Connection Type",
            "control": {
                "type": "select",
                "value": "ethernet"
            },
            "options": {
                "unknown": "UNKNOWN",
                "ethernet": "ETHERNET",
                "wifi": "WIFI",
                "2g": "CELL_2G",
                "3g": "CELL_3G",
                "4g": "CELL_4G",
                "none": "none"
            },
            "callback": function (setting) {
                var connected = setting !== "none";
                require('ripple/bus').send("network", connected);
            }
        },
        "lag": {
            "name": "Lag the network",
            "control": {
                type: "checkbox",
                value: false
            },
            "callback": function (setting) {
                require('ripple/bus').send("lag", setting);
            }
        },
    }
};

});
define('ripple/platform/phonegap/1.0.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        "deviceSettings",
        "geoView",
        "widgetConfig",
        "platformEvents"
    ]
};

});
define('ripple/platform/phonegap/1.0.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (configValidationObject) {
        var valid = true;
        valid = !((!configValidationObject.widget.validationResult[0].attributes.xmlns.valid) ||
            (!configValidationObject.widget.validationResult[0].attributes["xmlns:gap"].valid));

        return valid;
    },
    extractInfo: function (configValidationObject) {
        if (!configValidationObject) {
            return null;
        }

        var widgetInfo = {};

        widgetInfo.id = configValidationObject.widget.validationResult[0].attributes.id.value || "";
        widgetInfo.name = configValidationObject.widget.children.name.validationResult[0].value;
        widgetInfo.icon = configValidationObject.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = configValidationObject.widget.validationResult[0].attributes.version.value;

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xmlns:gap": {
                    attributeName: "xmlns:gap",
                    required: true,
                    type: "list",
                    listValues: ["http://phonegap.com/ns/1.0"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                },
                dir: {
                    attributeName: "dir",
                    required: false,
                    type: "list",
                    listValues: ["ltr", "rtl", "lro", "rlo"]
                },
                id: {
                    attributeName: "id",
                    required: false,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    required: false,
                    type: "string"
                },
                height: {
                    attributeName: "height",
                    required: false,
                    type: "integer"
                },
                width: {
                    attributeName: "width",
                    required: false,
                    type: "integer"
                },
                viewmodes: {
                    attributeName: "viewmodes",
                    required: false,
                    type: "list",
                    listValues: ["floating", "fullscreen"]
                }
            },
            children: {
                name: {
                    nodeName: "name",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "short": {
                            attributeName: "short",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 1,
                    type: "string",
                    attributes: {
                        email: {
                            attributeName: "email",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.EMAIL
                        },
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 1,
                    type: "string",
                    attributes: {
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        height: {
                            attributeName: "height",
                            required: false,
                            type: "integer"
                        },
                        width: {
                            attributeName: "width",
                            required: false,
                            type: "integer"
                        }
                    }
                },
                content: {
                    nodeName: "content",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        encoding: {
                            attributeName: "encoding",
                            type: "string",
                            required: false
                        },
                        type: {
                            attributeName: "type",
                            type: "string",
                            required: false
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        name: {
                            attributeName: "name",
                            type: "list",
                            required: true,
                            listValues: ["http://api.phonegap.com/1.0/accelerometer", "http://api.phonegap.com/1.0/camera",
                                "http://api.phonegap.com/1.0/compass", "http://api.phonegap.com/1.0/contacts", "http://api.phonegap.com/1.0/device",
                                "http://api.phonegap.com/1.0/events", "http://api.phonegap.com/1.0/file", "http://api.phonegap.com/1.0/geolocation",
                                "http://api.phonegap.com/1.0/media", "http://api.phonegap.com/1.0/network", "http://api.phonegap.com/1.0/notification",
                                "http://api.phonegap.com/1.0/storage"]
                        },
                        required: {
                            attributeName: "required",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                preference: {
                    nodeName: "preference",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        name: {
                            attributeName: "name",
                            type: "string",
                            required: true
                        },
                        value: {
                            type: "string",
                            attributeName: "value",
                            required: false
                        },
                        readonly: {
                            attributeName: "readonly",
                            type: "boolean",
                            required: false
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/phonegap/1.0.0/ContactOrganization', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (pref, type, name, dept, title) {
    return {
        pref: pref || null,
        type: type || null,
        name: name || null,
        department: dept || null,
        title: title || null
    };
};

});
define('ripple/platform/phonegap/1.0.0/spec', function (require, exports, module) {
module.exports = {
    id: "phonegap",
    version: "1.0.0",
    name: "PhoneGap",
    type: "platform",

    persistencePrefix: "phonegap-",

    config: require('ripple/platform/phonegap/1.0.0/spec/config'),
    device: require('ripple/platform/phonegap/1.0.0/spec/device'),
    ui: require('ripple/platform/phonegap/1.0.0/spec/ui'),
    events: require('ripple/platform/phonegap/1.0.0/spec/events'),

    initialize: function () { },

    objects: {
        PhoneGap: {
            path: "phonegap/1.0.0/PhoneGap"
        },
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        Acceleration: {
            path: "phonegap/1.0.0/Acceleration"
        },
        navigator: {
            path: "phonegap/1.0.0/navigator",
            children: {
                accelerometer: {
                    path: "phonegap/1.0.0/accelerometer"
                },
                geolocation: {
                    path: "w3c/1.0/geolocation"
                },
                notification: {
                    path: "phonegap/1.0.0/notification"
                },
                contacts: {
                    path: "phonegap/1.0.0/contacts"
                },
                network: {
                    path: "phonegap/1.0.0/network"
                },
                camera: {
                    path: "phonegap/1.0.0/camera"
                },
                sms: {
                    path: "phonegap/1.0.0/sms"
                },
                telephony: {
                    path: "phonegap/1.0.0/telephony"
                },
                map: {
                    path: "phonegap/1.0.0/map"
                },
                orientation: {
                    path: "phonegap/1.0.0/orientation"
                },
                system: {
                    path: "phonegap/1.0.0/system"
                },
                compass: {
                    path: "phonegap/1.0.0/compass"
                }
            }
        },
        ContactError: {
            path: "phonegap/1.0.0/ContactError"
        },
        Contact: {
            path: "phonegap/1.0.0/Contact"
        },
        ContactName: {
            path: "phonegap/1.0.0/ContactName"
        },
        ContactAccount: {
            path: "phonegap/1.0.0/ContactAccount"
        },
        ContactAddress: {
            path: "phonegap/1.0.0/ContactAddress"
        },
        ContactOrganization: {
            path: "phonegap/1.0.0/ContactOrganization"
        },
        ContactFindOptions: {
            path: "phonegap/1.0.0/ContactFindOptions"
        },
        ContactField: {
            path: "phonegap/1.0.0/ContactField"
        },
        NetworkStatus: {
            path: "phonegap/1.0.0/NetworkStatus"
        },
        device: {
            path: "phonegap/1.0.0/device"
        },
        SystemInfoOptions: {
            path: "phonegap/1.0.0/SystemInfoOptions"
        },
        PowerAttributes: {
            path: "phonegap/1.0.0/PowerAttributes"
        },
        CPUAttributes: {
            path: "phonegap/1.0.0/CPUAttributes"
        },
        ThermalAttributes: {
            path: "phonegap/1.0.0/ThermalAttributes"
        },
        NetworkAttributes: {
            path: "phonegap/1.0.0/NetworkAttributes"
        },
        Connection: {
            path: "phonegap/1.0.0/Connection"
        },
        ConnectionAttributes: {
            path: "phonegap/1.0.0/ConnectionAttributes"
        },
        SensorAttributes: {
            path: "phonegap/1.0.0/SensorAttributes"
        },
        AVCodecsAttributes: {
            path: "phonegap/1.0.0/AVCodecsAttributes"
        },
        AudioCodecAttributes: {
            path: "phonegap/1.0.0/AudioCodecAttributes"
        },
        VideoCodecAttributes: {
            path: "phonegap/1.0.0/VideoCodecAttributes"
        },
        StorageUnitAttributes: {
            path: "phonegap/1.0.0/StorageUnitAttributes"
        },
        InputDevicesAttributes: {
            path: "phonegap/1.0.0/InputDevicesAttributes"
        },
        OutputDevicesAttributes: {
            path: "phonegap/1.0.0/OutputDevicesAttributes"
        },
        DisplayDeviceAttributes: {
            path: "phonegap/1.0.0/DisplayDeviceAttributes"
        },
        AudioDeviceAttributes: {
            path: "phonegap/1.0.0/AudioDeviceAttributes"
        },
        PrintingDeviceAttributes: {
            path: "phonegap/1.0.0/PrintingDeviceAttributes"
        },
        BrailleDeviceAttributes: {
            path: "phonegap/1.0.0/BrailleDeviceAttributes"
        },
        PointerAttributes: {
            path: "phonegap/1.0.0/PointerAttributes"
        },
        KeyboardAttributes: {
            path: "phonegap/1.0.0/KeyboardAttributes"
        },
        CameraAttributes: {
            path: "phonegap/1.0.0/CameraAttributes"
        },
        MicrophoneAttributes: {
            path: "phonegap/1.0.0/MicrophoneAttributes"
        }
    }

};

});
define('ripple/platform/phonegap/1.0.0/notification', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    _console = require('ripple/console'),
    ui = require('ripple/ui'),
    goodVibrations = require('ripple/ui/plugins/goodVibrations');

module.exports = {
    alert: function (message, title, buttonName) {
        notifications.openNotification("normal", message);
    },

    beep: function (times) {
        for (var i = times; i > 0; i--) {
            _console.log("beep!");
        }
        notifications.openNotification("normal", "BEEP x " + times);
    },

    vibrate: function (milliseconds) {
        milliseconds = milliseconds || 500;
        goodVibrations.vibrateDevice(milliseconds);
    }
};

});
define('ripple/platform/phonegap/1.0.0/SensorAttributes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (value, min, max, normalizedValue) {
    return {
        value: value,
        min: min,
        max: max,
        normalizedValue: normalizedValue
    };
};

});
define('ripple/platform/phonegap/1.0.0/network', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    _self = {
        connection: {
        }
    };

_self.connection.__defineGetter__("type", function () {
    return deviceSettings.retrieve("NetworkStatus.connectionType");
});

module.exports = _self;

});
define('ripple/platform/w3c/1.0/PositionError', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self = function () {
    return {
        code: undefined,
        message: undefined
    };
};

_self.PERMISSION_DENIED = "PERMISSION_DENIED";
_self.POSITION_UNAVAILABLE = "POSITION_UNAVAILABLE";
_self.TIMEOUT = "TIMEOUT";

module.exports = _self;

});
define('ripple/platform/w3c/1.0/SensorConnection', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    platform = require('ripple/platform'),
    event = require('ripple/event'),
    sensorSettings = require('ripple/sensorSettings'),
    accelerometer = require('ripple/accelerometer'),
    exception = require('ripple/exception'),

    _permission = true,
    _self;

function ErrorMsg() {
    this.__defineGetter__("UNKNOWN_ERROR", function () {
        return "An unknown error has occurred.";
    });

    this.__defineGetter__("TYPE_MISMATCH_ERROR", function () {
        return "The object type is incompatible with the expected type.";
    });

    this.__defineGetter__("INVALID_VALUES_ERROR", function () {
        return "The content of an object does not contain valid values.";
    });

    this.__defineGetter__("ILLEGAL_STATE", function () {
        return "The status of connection is illegal.";
    });
}

// TODO: Should be replaced by a global object in tizen 1.0
function ErrorCode() {
    this.__defineGetter__("UNKNOWN_ERR", function () {
        return 0;
    });

    this.__defineGetter__("INVALID_VALUES_ERROR", function () {
        return 1;
    });

    this.__defineGetter__("TYPE_MISMATCH_ERROR", function () {
        return 2;
    });

    this.__defineGetter__("ILLEGAL_STATE", function () {
        return 3;
    });
}

function SensorError(code, msg) {
    this.__defineGetter__("message", function () {
        return msg;
    });
    this.__defineGetter__("code", function () {
        return code;
    });

    this.PERMISSION_DENIED = -100;
}

function Event() {
    var _self = {
        CAPTURING_PHASE: 1,
        AT_TARGET:  2,
        BUBBLING_PHASE: 3,

        type: '',
        target: null, //new EventTarget(),
        currentTarget: null, //new EventTarget(),
        eventPhase: 0,
        bubbles: false,
        cancelable: false,
        timeStamp: 0
    };
        
    this.__defineGetter__("type", function () {
        return _self.type;
    });

    this.__defineGetter__("target", function () {
        return _self.target;
    });

    this.__defineGetter__("currentTarget", function () {
        return _self.currentTarget;
    });

    this.__defineGetter__("eventPhase", function () {
        return _self.eventPhase;
    });    

    this.__defineGetter__("bubbles", function () {
        return _self.bubbles;
    });

    this.__defineGetter__("cancelable", function () {
        return _self.cancelable;
    });
    
    this.__defineGetter__("timeStamp", function () {
        return _self.timeStamp;
    });

    this.stopPropagation = function () {};

    this.preventDefault = function () {};

    this.initEvent = function (eventTypeArg, canBubbleArg, cancelableArg) {
        _self.type = eventTypeArg;
        _self.bubbles = canBubbleArg;
        _self.cancelable = cancelableArg;
    };

    return _self;
}

function SensorDataEvent() {
    var _self = {
        data: 0,
        accuracy: 0,
        timestamp: 0,
        reason: ''
    };

    // This type of event inherit from Event
    Event.call(this);

    this.__defineGetter__("data", function () {
        return _self.data;
    });

    this.__defineGetter__("accuracy", function () {
        return _self.accuracy;
    });

    this.__defineGetter__("timestamp", function () {
        return _self.timestamp;
    });

    this.__defineGetter__("reason", function () {
        return _self.reason;
    });

    this.initSensorDataEvent = function (type, bubbles, cancelable, reason, timestamp, accuracy, data) {
        this.initEvent(type, bubbles, cancelable);

        _self.reason = reason;
        _self.timestamp = timestamp;
        _self.accuracy = accuracy;
        
        // If the data has only one part, just return the value, not the data object    
        if (utils.count(data) === 1) {
            utils.forEach(data, function (section, key) {
                _self.data = data[key];
            });
        }
        else {
            _self.data = utils.copy(data);
        }
    };
}

// As only one sensor will be used during the simulation with a SensorConnection object,
// we can get that sensor object first and then the following read or write operations will be simplified
function _getSensorObj(type, name) {
    var settings = platform.current().sensor, _sensor;

    utils.forEach(settings, function (settingSection, settingType) {
        if (settingSection.type === type) {

            if (settingSection.name && settingSection.name !== name) {
                return;
            }

            _sensor = utils.copy(settingSection);
        }
    });

    return _sensor;
}

function _getAccelerometerData(dataType) {
    var accelerometerData, data = {};

    switch (dataType) {
    case "Accelerometer":
        accelerometerData = accelerometer.getInfo();
        data = {
            x: accelerometerData.acceleration.x,
            y: accelerometerData.acceleration.y,
            z: accelerometerData.acceleration.z
        };
        break;
    case "Rotation":
        accelerometerData = accelerometer.getInfo();
        data = {
            x: accelerometerData.orientation.alpha,
            y: accelerometerData.orientation.beta,
            z: accelerometerData.orientation.gamma
        };
        break;
    case "Orientation":
        accelerometerData = accelerometer.getInfo();
        data = {
            alpha: accelerometerData.orientation.alpha,
            beta: accelerometerData.orientation.beta,
            gamma: accelerometerData.orientation.gamma
        };
        break;
    default:
        break;
    }

    return data;
}

// The parameter of event callback is an object that contains the latest value, not the value itself,
// so we need a function to create such object.
function _getSensorData(sensorType, sensor, onerror) {
    var data = {}, value;

    if (sensorType === "Accelerometer" || sensorType === "Rotation" || sensorType === "Orientation") {
        return _getAccelerometerData(sensorType);
    }

    utils.forEach(sensor, function (sensorSection, key) {
        try {
            value = sensorSettings.retrieve(sensorType + "." + key);
        }
        catch (e) {
            if (onerror) {
                onerror(e);
            }
        }
        
        if (value) {
            data[key] = value;
        }                    
    });
    
    return data;
}

// As the event type in sensor.js file are named in this way, so we can get it with this function.
function _getSensorEventTypes(type, sensor) {
    var types = [];

    if (type === "Accelerometer" || type === "Rotation" || type === "Orientation") {
        return ["AccelerometerInfoChangedEvent"];
    }

    utils.forEach(sensor, function (sensorSection, sensorType) {
        if (typeof sensorSection === "object") {
            types.push(type + "-" + sensorType + "Changed");
        }
    });

    return types;
}

function _onEventCallback(type, options, currentSensor, length, eventCallback, onerror) {
    return function (values) {
        var sensorEvent = new SensorDataEvent();

        // Only the sensor that has one attribute could be compared with the threshold
        if (options && options.threshold && length === 1 && values[0] < options.threshold) {
            return;
        }

        if (eventCallback) {
            sensorEvent.initSensorDataEvent(type, false, false, "read", (new Date()).getTime(), 
                                            currentSensor.resolution, _getSensorData(type, currentSensor, onerror));

            eventCallback(sensorEvent);
        }
    };
}

function _bind(name, obj) {
    var callback = null;

    obj.__defineGetter__(name, function () {
        return callback;
    });

    obj.__defineSetter__(name, function (cb) {
        callback = cb;
    });

    return {
        get: function () {
            return callback;
        },
        set: function (value) {
            callback = value;
        },
        exec: function (arg) {
            return callback && callback(arg);
        },
        unbind: function (cb) {
            callback = cb === callback ? null : callback;
        }
    };
}

function SensorConnection(type, name) {
    var _self,
        currentSensor = _getSensorObj(type, name),
        sensorEvent = new SensorDataEvent(),
        sensorEventTypes = _getSensorEventTypes(type, currentSensor),
        watches = [],
        _errorCode = new ErrorCode(),
        _errorMsg = new ErrorMsg(),
        sensorListener;

    if (currentSensor) {
        _self = {
            sensor: {
                resolution: currentSensor.resolution,
                minDelay: currentSensor.minDelay,
                range: currentSensor.range,
                name: currentSensor.name,
                type: currentSensor.type
            },
            status: "open",
            error: null,
            read: function () {

                if (_self.status !== "open" && _self.status !== "watching") {
                    exception.raise(exception.types.Argument, "illegal state", new SensorError(_errorCode.ILLEGAL_STATE, _errorMsg.ILLEGAL_STATE));
                    return;
                }                

                setTimeout(function () {
                    if (sensorListener.get()) {
                        sensorEvent.initSensorDataEvent(type, false, false, "read", (new Date()).getTime(), 
                                                        currentSensor.resolution, _getSensorData(type, currentSensor, _self.onerror));

                        sensorListener.exec(sensorEvent);
                    }
                }, 1);  

                return;
            },

            startWatch: function (options) {
                var index, watchId, watchObj = {};

                if (_self.status !== "open") {
                    exception.raise(exception.types.Argument, "illegal state", new SensorError(_errorCode.ILLEGAL_STATE, _errorMsg.ILLEGAL_STATE));
                    return;
                }
                    
                if (typeof options !== "object") {
                    if (_self.onerror) {
                        _self.onerror(new SensorError(_errorCode.TYPE_MISMATCH_ERROR, _errorMsg.TYPE_MISMATCH_ERROR));
                    }
                }

                setTimeout(function () {
                    watchId = (new Date()).getTime();   

                    // As there will be many attributes for some sensor, each of them is needed to be watched.
                    for (index = 0; index < sensorEventTypes.length; index++) {
                        watchObj = {
                            eventType: sensorEventTypes[index],
                            onEvent: _onEventCallback(type, options, currentSensor, sensorEventTypes.length, sensorListener.get(), _self.onerror),
                        };

                        watches.push(watchObj);
                        if (watchObj.eventType) {
                            event.on(watchObj.eventType, watchObj.onEvent);                                               
                        }
                    }

                    
                    if (options && options.interval) {
                        watchObj.intervalId = setInterval(_onEventCallback(type, options, currentSensor, sensorEventTypes.length, sensorListener.get(), _self.onerror), 
                                                          options.interval);
                    }

                    _self.status = "watching";
                    if (_self.onstatuschange) {
                        _self.onstatuschange();
                    }
                                                                                                        
                }, 1);  

                return;
            },

            endWatch: function () {
                var index, watchObj;

                if (_self.status !== "watching") {
                    exception.raise(exception.types.Argument, "illegal state", new SensorError(_errorCode.ILLEGAL_STATE, _errorMsg.ILLEGAL_STATE));
                    return;
                }

                for (index = 0; index < watches.length; index++) {
                    watchObj = watches[index];

                    try {
                        event.deleteEventHandler(watchObj.eventType, watchObj.onEvent);  
                    }
                    catch (e) {
                        if (_self.onerror) {
                            _self.onerror(e);
                        }
                    }

                    if (watchObj.intervalId) {
                        clearInterval(watchObj.intervalId);
                    }                
                }

                watches = [];

                _self.status = "open";
                if (_self.onstatuschange) {
                    _self.onstatuschange();
                }
            },

            // These functions are inherited from the EventTarget object
            addEventListener: function (eventType, callback, useCapture) {
                var sensorEvent;
                
                if (eventType === "sensordata") {
                    sensorListener.set(callback);  

                    event.on("sensordata", function (data) {
                        sensorEvent = new SensorDataEvent();        
                        sensorEvent.initSensorDataEvent("sensordata", false, false, "read", (new Date()).getTime(), 
                                                        currentSensor.resolution, _getSensorData(type, currentSensor, _self.onerror));           

                        sensorListener.exec(sensorEvent);
                    });             
                }               
            },

            removeEventListener: function (eventType, callback) {
                event.clear(eventType, callback);
                sensorListener.unbind(callback);                                
            },

            dispatchEvent: function (evt) {
                event.trigger("sensordata", evt);
            }
        };

        sensorListener = _bind("onsensordata", _self);
    }    

    return _self;
}

module.exports = function (option) {
 
    var connectionObj,
        _errorCode = new ErrorCode(),
        _errorMsg = new ErrorMsg();

    if (option === null || option === undefined) {
        return null;
    }

    // There are two ways to construct an object
    if (typeof option === "object") {
        if ((option.type === null || option.type === undefined) &&
            (option.name === null || option.name === undefined)) {
            // Spec: If none of the dictionary members are defined then raise an instantiation exception    
            exception.raise(exception.types.Argument, "type illegal", new SensorError(_errorCode.ILLEGAL_TYPE, _errorMsg.ILLEGAL_TYPE));             
        }

        connectionObj = new SensorConnection(option.type, option.name);
    }
    else if (typeof option === "string") {
        connectionObj = new SensorConnection(option, option);
    }

    return connectionObj;
};

});
define('ripple/platform/w3c/1.0/Rotation', function (require, exports, module) {
module.exports = function (alpha, beta, gamma) {
    return {
        alpha: alpha || 0,    //Rotation about the 'z' axis expressed in degrees [0, 360].    (Number)
        beta: beta || 0,      //Rotation about the 'x' axis expressed in degrees [-180, 180]. (Number)
        gamma: gamma || 0     //Rotation about the 'y' axis expressed in degrees [-90, 90].   (Number)
    };
};

});
define('ripple/platform/w3c/1.0/geolocation', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var geo = require('ripple/geo'),
    Position = require('ripple/platform/w3c/1.0/Position'),
    PositionError = require('ripple/platform/w3c/1.0/PositionError'),
    _watches = {},
    _self;

function createPosition() {
    var position = new Position(),
        positionInfo = geo.getPositionInfo();

    position.coords.latitude = positionInfo.latitude;
    position.coords.longitude = positionInfo.longitude;
    position.coords.altitude = positionInfo.altitude;
    position.coords.altitudeAccuracy = positionInfo.altitudeAccuracy;
    position.coords.accuracy = positionInfo.accuracy;
    position.coords.heading = positionInfo.heading;
    position.coords.speed = positionInfo.speed;
    position.timestamp = positionInfo.timeStamp.getTime();

    return position;
}

_self = {
    getCurrentPosition: function (onSuccess, onError) {
        var delay = ((geo.delay || 0) * 1000) || 1,
            timeout = geo.timeout;

        window.setTimeout(function () {
            if (timeout) {
                var error = new PositionError();
                error.code = PositionError.TIMEOUT;
                error.message = "postion timed out";

                onError(error);
            }
            else {
                // TODO: build facility to trigger onError() from emulator
                // see pivotal item: https://www.pivotaltracker.com/story/show/7040343
                _self.lastPosition = createPosition();
                onSuccess(_self.lastPosition);
            }
        }, delay);
    },

    watchPosition: function (geolocationSuccess, geolocationError, geolocationOptions) {
        var watchId = (new Date()).getTime().toString(),
            watchObj = {},
            timeout;

        if (geolocationOptions) {
            timeout = geolocationOptions.timeout || 10000;

            watchObj = {
                onSuccess: geolocationSuccess,
                onError: geolocationError,
                interval: timeout
            };

            _watches[watchId] = watchObj;

            _watches[watchId].intervalId = window.setInterval(function () {
                _self.getCurrentPosition(_watches[watchId].onSuccess, _watches[watchId].onError);
            }, timeout);

        }
        else {
            if (typeof geolocationError === "function") {
                window.setTimeout(function () {
                    geolocationError();
                }, 1);
            }
        }

        return watchId;
    },

    lastPosition: null,

    clearWatch: function (watchId) {
        window.clearInterval(_watches[watchId].intervalId);
        delete _watches[watchId];
    }
};

module.exports = _self;

});
define('ripple/platform/w3c/1.0/navigator', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _original = window.navigator,
    utils = require('ripple/utils'),
    devices = require('ripple/devices'),
    constants = require('ripple/constants'),
    _self = {};

(function () {
    var key,
        nav = window.navigator;

    function _handle(obj, key) {
        return typeof obj[key] !== "function" ? obj[key] : function () {
            return obj[key].apply(obj, Array.prototype.slice.call(arguments));
        };
    }

    for (key in nav) {
        _self[key] = _handle(nav, key);
    }
}());

_self.__defineGetter__('userAgent', function () {
    var currentUserAgent = devices.getCurrentDevice().userAgent;

    return currentUserAgent === constants.COMMON.USER_AGENT_DEFAULT ?
        _original.userAgent : currentUserAgent;
});

module.exports = _self;

});
define('ripple/platform/w3c/1.0/Acceleration', function (require, exports, module) {
module.exports = function (x, y, z) {
    return {
        x: x || 0,    //Acceleration in the 'x' expressed in m/s^2. (Number)
        y: y || 0,    //Acceleration in the 'y' expressed in m/s^2. (Number)
        z: z || 0     //Acceleration in the 'z' expressed in m/s^2. (Number)
    };
};

});
define('ripple/platform/w3c/1.0/Position', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Coordinates = require('ripple/platform/w3c/1.0/Coordinates');

module.exports = function () {
    return {
        coords: new Coordinates(),
        timestamp: new Date().getTime()
    };
};

});
define('ripple/platform/w3c/1.0/Coordinates', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function (latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed) {
    return {
        latitude: latitude || 0,                    //Latitude in decimal degrees. (Number)
        longitude: longitude || 0,                  //Longitude in decimal degrees. (Number)
        altitude: altitude || 0,                    //Height of the position in meters above the ellipsoid. (Number)
        accuracy: accuracy || 0,                    //Accuracy level of the latitude and longitude coordinates in meters. (Number)
        altitudeAccuracy: altitudeAccuracy || 0,    //Accuracy level of the altitude coordinate in meters. (Number)
        heading: heading || 0,                      //Direction of travel, specified in degrees counting clockwise relative to the true north. (Number)
        speed: speed || 0                           //Current ground speed of the device, specified in meters per second. (Number)
    };
};

});
define('ripple/platform/tizen/2.0/BluetoothClassDeviceMajor', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function () {
    var _self = {};

    _self.__defineGetter__("MISC", function () {
        return 0x00;
    });
    _self.__defineGetter__("COMPUTER", function () {
        return 0x01;
    });
    _self.__defineGetter__("PHONE", function () {
        return 0x02;
    });
    _self.__defineGetter__("NETWORK", function () {
        return 0x03;
    });
    _self.__defineGetter__("AUDIO_VIDEO", function () {
        return 0x04;
    });
    _self.__defineGetter__("PERIPHERAL", function () {
        return 0x05;
    });
    _self.__defineGetter__("IMAGING", function () {
        return 0x06;
    });
    _self.__defineGetter__("WEARABLE", function () {
        return 0x07;
    });
    _self.__defineGetter__("TOY", function () {
        return 0x08;
    });
    _self.__defineGetter__("HEALTH", function () {
        return 0x09;
    });
    _self.__defineGetter__("UNCATEGORIZED", function () {
        return 0x1F;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/TZDate', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tz = require('ripple/platform/tizen/2.0/timezone_info'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    _Month = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    _Day = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

module.exports = function (dt) {
    var d, UTCd, UTC_diff, tzid = "", target_diff, temp_date,
    time = require('ripple/platform/tizen/2.0/time'),
        hour = arguments[3] || 0, min = arguments[4] || 0,
        sec = arguments[5] || 0, msec = arguments[6] || 0,

    _d2UTCd_sync = function () {
        UTCd = new Date(d.valueOf() - (UTC_diff * 1000 * 60 * 60));
    },
    _UTCd2d_sync = function () {
        d = new Date(UTCd.valueOf() + (UTC_diff * 1000 * 60 * 60));
    },
    _getValue = function (o) {
        var other;
        other = new Date(o.getUTCFullYear(), o.getUTCMonth(), o.getUTCDate(),
                    o.getUTCHours(), o.getUTCMinutes(), o.getUTCSeconds(), o.getUTCMilliseconds());
        return other.valueOf();
    },
    _int_range_check = function (val, _min, _max) {
        var v = Number(val);

        if (v > _max || v < _min) {
            return false;
        }
        return true;
    };

    if (arguments[7] !== undefined) {
        tzid = arguments[7];
    }

    if (dt === null || dt === undefined) {
        temp_date = new Date();
        target_diff = tz.getTimezoneDiff(time.getLocalTimezone());
        d = new Date(temp_date.valueOf() + (target_diff + temp_date.getTimezoneOffset() / 60) * 1000 * 60 * 60);
    } else {
        if (tizen1_utils.isValidDate(dt)) {
            d = new Date(dt);
            if (arguments[1] !== undefined) {
                tzid = arguments[1];
            }
        } else {
            d = new Date(arguments[0], arguments[1], arguments[2], hour, min, sec, msec);
        }
    }

    if (tz.isValidTimezone(tzid) === false) {
        tzid = time.getLocalTimezone();
    }
    UTC_diff = tz.getTimezoneDiff(tzid);
    _d2UTCd_sync();

    return {
        getDate: function () {
            return d.getDate();
        },
        setDate: function (dt) {
            if (_int_range_check(dt, 1, 31)) {
                d.setDate(dt);
                _d2UTCd_sync();
            }
        },
        getDay: function () {
            return d.getDay();
        },
        getFullYear: function () {
            return d.getFullYear();
        },
        setFullYear: function (yr) {
            if (_int_range_check(yr, 1000, 9999)) {
                d.setFullYear(yr);
                _d2UTCd_sync();
            }
        },
        getHours: function () {
            return d.getHours();
        },
        setHours: function (hr) {
            if (_int_range_check(hr, 0, 23)) {
                d.setHours(hr);
                _d2UTCd_sync();
            }
        },
        getMilliseconds: function () {
            return d.getMilliseconds();
        },
        setMilliseconds: function (msec) {
            if (_int_range_check(msec, 0, 999)) {
                d.setMilliseconds(msec);
                _d2UTCd_sync();
            }
        },
        getMinutes: function () {
            return d.getMinutes();
        },
        setMinutes: function (min) {
            if (_int_range_check(min, 0, 59)) {
                d.setMinutes(min);
                _d2UTCd_sync();
            }
        },
        getMonth: function () {
            return d.getMonth();
        },
        setMonth: function (m) {
            if (_int_range_check(m, 0, 11)) {
                d.setMonth(m);
                _d2UTCd_sync();
            }
        },
        getSeconds: function () {
            return d.getSeconds();
        },
        setSeconds: function (s) {
            if (_int_range_check(s, 0, 59)) {
                d.setSeconds(s);
                _d2UTCd_sync();
            }
        },
        getUTCDate: function () {
            return UTCd.getDate();
        },
        setUTCDate: function (dt) {
            if (_int_range_check(dt, 1, 31)) {
                UTCd.setDate(dt);
                _UTCd2d_sync();
            }
        },
        getUTCDay: function () {
            return UTCd.getDay();
        },
        getUTCFullYear: function () {
            return UTCd.getFullYear();
        },
        setUTCFullYear: function (yr) {
            if (_int_range_check(yr, 1000, 9999)) {
                UTCd.setFullYear(yr);
                _UTCd2d_sync();
            }
        },
        getUTCHours: function () {
            return UTCd.getHours();
        },
        setUTCHours: function (hr) {
            if (_int_range_check(hr, 0, 23)) {
                UTCd.setHours(hr);
                _UTCd2d_sync();
            }
        },
        getUTCMilliseconds: function () {
            return UTCd.getMilliseconds();
        },
        setUTCMilliseconds: function (msec) {
            if (_int_range_check(msec, 0, 999)) {
                UTCd.setMilliseconds(msec);
                _UTCd2d_sync();
            }
        },
        getUTCMinutes: function () {
            return UTCd.getMinutes();
        },
        setUTCMinutes: function (min) {
            if (_int_range_check(min, 0, 59)) {
                UTCd.setMinutes(min);
                _UTCd2d_sync();
            }
        },
        getUTCMonth: function () {
            return UTCd.getMonth();
        },
        setUTCMonth: function (m) {
            if (_int_range_check(m, 0, 11)) {
                UTCd.setMonth(m);
                _UTCd2d_sync();
            }
        },
        getUTCSeconds: function () {
            return UTCd.getSeconds();
        },
        setUTCSeconds: function (s) {
            if (_int_range_check(s, 0, 59)) {
                UTCd.setSeconds(s);
                _UTCd2d_sync();
            }
        },
        getTimezone: function () {
            return tzid;
        },
        toTimezone: function (new_tzid) {
            var diff,
                Tzdate = require('ripple/platform/tizen/2.0/TZDate');
            if (typeof new_tzid !== 'string') {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            if (tz.isValidTimezone(new_tzid) === true) {
                diff = tz.getTimezoneDiff(new_tzid) - UTC_diff;
                return new Tzdate(new Date(d.valueOf() + (diff * 1000 * 60 * 60)), new_tzid);
            } else {
                throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
            }
        },
        toLocalTimezone: function () {
            var diff,
                Tzdate = require('ripple/platform/tizen/2.0/TZDate'),
                localTzid = time.getLocalTimezone();

            diff = tz.getTimezoneDiff(localTzid) - UTC_diff;
            return new Tzdate(new Date(d.valueOf() + (diff * 1000 * 60 * 60)), localTzid);
        },
        toUTC: function () {
            var Tzdate = require('ripple/platform/tizen/2.0/TZDate');
            return new Tzdate(UTCd, "UTC");
        },
        difference: function (other) {
            var diff,
                TDur = require('ripple/platform/tizen/2.0/TimeDuration');
            if (typeof other !== 'object') {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            diff = (UTCd.valueOf() - _getValue(other));
            return new TDur(diff).difference(new TDur(0));
        },
        equalsTo: function (other) {
            if (typeof other !== 'object') {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            return (UTCd.valueOf() === _getValue(other));
        },
        earlierThan: function (other) {
            if (typeof other !== 'object') {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            return (UTCd.valueOf() < _getValue(other));
        },
        laterThan: function (other) {
            if (typeof other !== 'object') {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            return (UTCd.valueOf() > _getValue(other));
        },
        addDuration: function (dur) {
            var Tzdate = require('ripple/platform/tizen/2.0/TZDate'),
                Tunit = {"MSECS": 1,
                         "SECS": 1000,
                         "MINS": 60 * 1000,
                         "HOURS": 60 * 60 * 1000,
                         "DAYS": 24 * 60 * 60 * 1000
                        };
            if (dur.length === undefined || dur.length === null ||
                dur.unit === undefined || dur.unit === null) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            if ((typeof dur.length) !== 'number') {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            if (Tunit[dur.unit] === undefined) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            return new Tzdate(new Date(d.valueOf() + (dur.length * Tunit[dur.unit])), tzid);
        },
        toLocaleDateString: function () {
            if (d.toString() === "Invalid Date") {
                return d.toString();
            } else {
                return this.toDateString() + " (" + tz.getTimezoneAbbr(tzid) + ")";
            }
        },
        toLocaleTimeString: function () {
            if (d.toString() === "Invalid Date") {
                return d.toString();
            } else {
                return this.toTimeString() + " (" + tz.getTimezoneAbbr(tzid) + ")";
            }
        },
        toLocaleString: function () {
            if (d.toString() === "Invalid Date") {
                return d.toString();
            } else {
                return this.toString() + " (" + tz.getTimezoneAbbr(tzid) + ")";
            }
        },
        toDateString: function () {
            var i, ret = "", fmt = time.getDateFormat();
            if (d.toString() === "Invalid Date") {
                return d.toString();
            }
            for (i = 0; i < fmt.length; i++) {
                switch (fmt.charAt(i)) {
                case 'd':
                    ret = ret + d.getDate();
                    break;
                case 'y':
                    ret = ret + d.getFullYear();
                    break;
                case 'm':
                    ret = ret + (d.getMonth() + 1);
                    break;
                case 'M':
                    ret = ret + _Month[d.getMonth()];
                    break;
                case 'D':
                    ret = ret + _Day[d.getDay()];
                    break;
                default:
                    ret = ret + fmt.charAt(i);
                }
            }
            return ret;
        },
        toTimeString: function () {
            var i, hh, mm, ss, AP,
                ret = "", fmt = time.getTimeFormat();

            if (d.toString() === "Invalid Date") {
                return d.toString();
            }

            if (fmt.search(/ap/) === -1) {
                AP = false;
            } else {
                AP = true;
                if (d.getHours() > 11) {
                    fmt = fmt.replace("ap", "PM");
                } else {
                    fmt = fmt.replace("ap", "AM");
                }
            }
            for (i = 0; i < fmt.length; i++) {
                switch (fmt.charAt(i)) {
                case 'h':
                    hh = d.getHours();
                    if (AP) {
                        hh = (hh > 12) ? hh - 12 : hh;
                    }
                    hh = (hh < 10 ? "0" : "") + hh;
                    ret = ret + hh;
                    break;
                case 'm':
                    mm = d.getMinutes();
                    mm = (mm < 10 ? "0" : "") + mm;
                    ret = ret + mm;
                    break;
                case 's':
                    ss = d.getSeconds();
                    ss = (ss < 10 ? "0" : "") + ss;
                    ret = ret + ss;
                    break;
                default:
                    ret = ret + fmt.charAt(i);
                }
            }
            return ret;
        },
        toString: function () {
            if (d.toString() === "Invalid Date") {
                return d.toString();
            } else {
                return (this.toDateString() + " " + this.toTimeString());
            }
        },
        getTimezoneAbbreviation: function () {
            return tz.getTimezoneAbbr(tzid);
        },
        secondsFromUTC: function () {
            return (-1 * UTC_diff * 60 * 60);
        },
        isDST: function () {
            throw (new WebAPIError(errorcode.NOT_SUPPORTED_ERR));
        },
        getPreviousDSTTransition: function () {
            throw (new WebAPIError(errorcode.NOT_SUPPORTED_ERR));
        },
        getNextDSTTransition: function () {
            throw (new WebAPIError(errorcode.NOT_SUPPORTED_ERR));
        }
    };
};

});
define('ripple/platform/tizen/2.0/SimpleCoordinates', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

module.exports = function (_latitude, _longitude) {
    return {
        latitude: _latitude || 0,
        longitude: _longitude || 0
    };
};


});
define('ripple/platform/tizen/2.0/battery', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    utils = require('ripple/utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    _data = {
        charging: true,
        chargingTime: 0,
        level: 1.0,
        dischargingTime: Infinity,
        chargingchange: {},
        chargingtimechange: {},
        levelchange: {},
        dischargingtimechange: {}
    },
    _self;

_self = {
    addEventListener: function (event, callback, capture) {
        if (typeof callback !== "function" || event === undefined) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        switch (event) {
        case "chargingchange":
        case "chargingtimechange":
        case "levelchange":
        case "dischargingtimechange":
            var isExist = false, item;
            for (item in _data[event]) {
                if (callback === item) {
                    isExist = true;
                    break;
                }
            }
            if (!isExist) {
                _data[event].add(callback);
            }
            break;

        default:
            break;
        }
    },

    removeEventListener: function (event, callback, capture) {
        if (typeof callback !== "function" || event === undefined) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        _data[event].unbind(callback);
    },

    dispatchEvent: function (event) {
        if (event === undefined) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        return _data[event].exec(event);
    }
};

_self.__defineGetter__("charging", function () {
    return _data.charging;
});

_self.__defineGetter__("chargingTime", function () {
    return _data.chargingTime;
});

_self.__defineGetter__("level", function () {
    return _data.level;
});

_self.__defineGetter__("dischargingTime", function () {
    return _data.dischargingTime;
});

function _initialize() {
    var callback = [];

    function bind(name) {
        _self.__defineGetter__(name, function () {
            return callback;
        });

        _self.__defineSetter__(name, function (cb) {
            callback = cb;
        });

        return {
            get: function () {
                return callback;
            },

            set: function (value) {
                callback = value;
            },

            add: function (value) {
                callback.push(value);
            },

            exec: function (arg) {
                callback.forEach(function (callback) {
                    return !callback || callback(arg);
                });
            },

            unbind: function (value) {
                if (value === undefined) {
                    callback = [];
                } else {
                    utils.forEach(callback, function (callback, index) {
                        if (callback === value) {
                            callback.splice(index, 1);
                        }
                    });
                }
            }
        };
    }

    _data.chargingchange        = bind("onchargingchange");
    _data.chargingtimechange    = bind("onchargingtimechange");
    _data.levelchange           = bind("onlevelchange");
    _data.dischargingtimechange = bind("ondischargingtimechange");

    event.on("BatteryEvent", function (status) {
        for (var ev in status) {
            if ((status[ev] !== undefined) && (status[ev] !== _data[ev])) {
                _data[ev] = status[ev];
            }
        }
        _data[status.type].exec();
    });
}

_initialize();

module.exports = _self;

});
define('ripple/platform/tizen/2.0/MessagingService', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    Message = require('ripple/platform/tizen/2.0/Message'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    PrivMessage = require('ripple/platform/tizen/2.0/PrivMessage'),
    MessageStorage = require('ripple/platform/tizen/2.0/MessageStorage'),
    utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    msg_utils = require('ripple/platform/tizen/2.0/msg_utils'),
    _self,
    TIZEN_DEFAULT_MSG_FROM = {"messaging.sms": "13572468",
                              "messaging.mms": "13572468",
                              "messaging.email": "tizen.simulator@tizen.org"},
    INCOMING_TYPE = {"messaging.sms": "sms",
                     "messaging.mms": "mms",
                     "messaging.email": "email"};

_self = function (id, name, type, security_check) {
    var msg_service = {},
        pendingOperations = {},
        _msgSending = {},
        _receivedEmails = [],
        _id = id,
        _name = name,
        _type = type,
        _security_check = security_check,
        _from = TIZEN_DEFAULT_MSG_FROM[_type],
        _incomingType = INCOMING_TYPE[_type],
        _messages = msg_utils.loadMsg(_type, _id),
        _messageStorage = new MessageStorage(_messages, _security_check);

    event.on("MessageSent", function (rst) {
        var i, rsp_ok = [], rsp_fail = [];
        // rst.msg is the real msg in module
        if (rst.msg.priv.type !== _type ||
            rst.msg.priv.serviceId !== _id) {
            // not my msg
            return;
        }
        if (_msgSending[rst.id] !== undefined) {
            for (i in rst) {
                if ((i !== "id") && (i !== "msg")) {
                    if (rst[i] === true) {
                        rsp_ok.push(i);
                    } else {
                        rsp_fail.push(i);
                    }
                }
            }
            rst.msg.priv.folderId = "SENTBOX";
            if (rsp_fail.length === 0) {
                rst.msg.priv.messageStatus = "SENT";
                _msgSending[rst.id].onsuccess(rsp_ok);
            } else {
                rst.msg.priv.messageStatus = "FAILED";
                _msgSending[rst.id].onerror(rsp_fail);
            }
            msg_utils.saveMsg(rst.msg);  // sync to remote
            event.trigger("MsgSentRst", [rst.msg]);
            delete _msgSending[rst.id];
        }
    });

    event.on("MessageReceived", function (rst) {
        var m, opt = {}, msgInit = {}, msg = {};

        if (rst.type !== _incomingType) {
            // not my msg
            return;
        }
        msgInit.plainBody = rst.body;
        msgInit.to = [_from];
        // TODO: handle attachment
        if (msg_utils.setMsg(msgInit, msg) === false) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR, "received message error"));
        }
        opt.id = Math.uuid(8, 16);
        opt.serviceId = _id;
        opt.conversationId = opt.id;
        opt.folderId = "INBOX";
        opt.type = _type;
        opt.timestamp = new Date();
        opt.from = rst.from;
        if (msg.attachments.length === 0) {
            opt.hasAttachment = false;
        } else {
            opt.hasAttachment = true;
        }
        opt.messageStatus = "RECEIVED";
        m = new PrivMessage(msg, opt);
        msg_utils.saveMsg(m);   // save in server
        if (_type !== "messaging.email") {
            _messages.msg[m.priv.id] = m;  // sync to local
            event.trigger("MsgRecv", [m]);
        } else {
            _receivedEmails.push(m);  // don't sync to local yet
        }
    });

    msg_service = {
        sendMessage: function (_msg, onSuccess, onError) {
            var m, msg = {}, opt = {}, shortMsg = {}, rst = {}, _sendMsg;
            if (_security_check.send === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (_msg === null || _msg === undefined || _msg.id === undefined) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }

            if (msg_utils.setMsg(_msg, msg) === false) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            _sendMsg = function () {
                if (typeof _msg.id === 'string') {
                    if (_messages.msg[_msg.id] === undefined) {
                        if (onError) {
                            setTimeout(function () {
                                onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                            }, 1);
                        }
                        return;
                    }
                    if (_messages.msg[_msg.id].priv.messageStatus === "DRAFT") {
                        msg_utils.delMsg(_messages.msg[_msg.id]);
                        delete _messages.msg[_msg.id];
                    } else {
                        // if msg found in storage, it can only be a draft.
                        if (onError) {
                            setTimeout(function () {
                                onError(new WebAPIError(errorcode.SECURITY_ERR));
                            }, 1);
                        }
                        return;
                    }
                }
                opt.id = Math.uuid(8, 16);
                opt.serviceId = _id;
                if ((msg.inResponseTo !== null) &&
                    (_messages.msg[msg.inResponseTo] !== undefined) &&
                    (_messages.msg[msg.inResponseTo].priv.messageStatus !== "DRAFT")) {
                    opt.conversationId = _messages.msg[msg.inResponseTo].priv.conversationId;
                } else {
                    opt.conversationId = opt.id;
                }
                opt.folderId = "OUTBOX";
                opt.type = _type;
                opt.timestamp = new Date();
                opt.from = _from;
                if (msg.attachments.length === 0) {
                    opt.hasAttachment = false;
                } else {
                    opt.hasAttachment = true;
                }
                opt.messageStatus = "SENDING";

                m = new PrivMessage(msg, opt);
                _messages.msg[m.priv.id] = m;
                msg_utils.saveMsg(m);  // sync to remote
                shortMsg.msg = m;   // pass by ref
                shortMsg.id = m.priv.id;
                shortMsg.body = m.body.plainBody;
                shortMsg.to = m.to.slice(0);
                shortMsg.cc = m.cc.slice(0);
                shortMsg.bcc = m.bcc.slice(0);
                event.trigger("OutsideMessageReceived", [shortMsg]);
                rst.onsuccess = onSuccess;
                rst.onerror = onError;
                _msgSending[m.priv.id] = rst;
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messagingService:sendMsg", _sendMsg);
        },

        loadMessageBody: function (msg, onSuccess, onError) {
            var pendingID, _loadMsgBody;
            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            _loadMsgBody = function () {
                pendingID = setTimeout(function () {
                    if (pendingOperations[pendingID] === undefined) {
                        // has been cancelled/expired
                        return;
                    }
                    delete pendingOperations[pendingID];
                    onSuccess();
                }, 1);
                pendingOperations[pendingID] = onError;
                return pendingID;
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messagingService:loadMessageBody", _loadMsgBody);
        },
        loadMessageAttachment: function (msg, onSuccess, onError) {
            var pendingID, _loadMsgAttachment;

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (_messages.msg[msg.id] === undefined) {
                throw (new WebAPIError(errorcode.NOT_FOUND_ERR));
            }
            _loadMsgAttachment = function () {
                pendingID = setTimeout(function () {
                    if (pendingOperations[pendingID] === undefined) {
                        // has been cancelled/expired
                        return;
                    }
                    delete pendingOperations[pendingID];
                    onSuccess();
                }, 1);
                pendingOperations[pendingID] = onError;
                return pendingID;
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messagingService:loadMessageAttachment", _loadMsgAttachment);
        },
        sync: function (onSuccess, onError, limit) {
            var i, m, pendingID, _sync, _onError;

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            _onError = onError || null;
            _sync = function () {
                pendingID = setTimeout(function () {
                    if (pendingOperations[pendingID] === undefined) {
                        // has been cancelled/expired
                        return;
                    }
                    delete pendingOperations[pendingID];
                    for (i = 0; i < _receivedEmails.length; i++) {
                        m = _receivedEmails[i];
                        _messages.msg[m.priv.id] = m;  // sync to local
                        event.trigger("MsgRecv", [m]);
                    }
                    _receivedEmails = [];
                    onSuccess();
                }, 1);
                pendingOperations[pendingID] = _onError;
                return pendingID;
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messagingService:sync", _sync);
        },

        syncFolder: function (folder, onSuccess, onError, limit) {
            var i, m, pendingID, _syncFolder;

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            _syncFolder = function () {
                pendingID = setTimeout(function () {
                    if (pendingOperations[pendingID] === undefined) {
                        // has been cancelled/expired
                        return;
                    }
                    delete pendingOperations[pendingID];
                    if (folder.id === "INBOX") {
                        for (i = 0; i < _receivedEmails.length; i++) {
                            m = _receivedEmails[i];
                            _messages.msg[m.priv.id] = m;  // sync to local
                            event.trigger("MsgRecv", [m]);
                        }
                        _receivedEmails = [];
                    }
                    onSuccess();
                }, 1);
                pendingOperations[pendingID] = onError;
                return pendingID;
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messagingService:syncFolder", _syncFolder);
        },

        stopSync: function (pendingID) {
            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (typeof pendingID !== number) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            if (pendingOperations[pendingID] === undefined) {
                return;
            } else {
                clearTimeout(pendingID);
                pendingOperations[pendingID](new WebAPIError(errorcode.ABORT_ERR));
                delete pendingOperations[pendingID];
            }
        }
    };
    msg_service.__defineGetter__("id", function () {
        return _id;
    });
    msg_service.__defineGetter__("type", function () {
        return _type;
    });
    msg_service.__defineGetter__("name", function () {
        return _name;
    });
    msg_service.__defineGetter__("messageStorage", function () {
        return _messageStorage;
    });
    return msg_service;
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/BluetoothSocket', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (prop) {
    var _self,
        _uuid = prop.uuid,
        _protocol = prop.protocol,
        state = prop.state,
        _peer = prop.peer,
        _security = prop.metaData,
        _buf = [];

    _self = {
        onmessage : null,
        onclose : null,
        onerror : null,
        writeData : function (data) {
            if (!_security.all && !_security.writeData) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }
            if (!tizen1_utils.isValidArray(data)) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            if (this.state === "CLOSED") {
                return;
            }

            event.trigger("bt-service-write-msg", [_peer.address, _uuid, data]);
            return data.length;
        },
        readData : function () {
            var data;
            if (!_security.all && !_security.readData) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }
            if (this.state === "CLOSED") {
                return;
            }

            data = utils.copy(_buf);
            _buf = [];
            return data;
        },
        close : function () {
            if (!_security.all && !_security.close) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            Object.defineProperty(this, "state", {value: "CLOSED", writable: false});
            event.trigger("bt-service-state-changed", [_peer.address, _uuid, false]);
            event.trigger("bt-device-connected-update", [_peer.address, false]);

            if (this.onclose) {
                this.onclose();
            }
        }
    };

    event.on("bt-service-state-update", function (addr, state) {
        var stateStr = "CLOSED";
        if (addr === _peer.address) {
            if (state) {
                stateStr = "OPEN";
            }
            Object.defineProperty(this, "state", {value: stateStr, writable: false});
            event.trigger("bt-service-state-changed", [_peer.address, _uuid, state]);
            event.trigger("bt-device-connected-update", [_peer.address, state]);
        }
    });

    event.on("bt-service-rawdata-received", function (addr, uuid, msg) {
        var i;
        if (addr === _peer.address && uuid === _uuid) {
            _buf = [];
            for (i = 0; i < msg.length; i++) {
                _buf.push(msg.charCodeAt(i));
            }
            if (_self.onmessage) {
                _self.onmessage();
            }
        }
    });

    _self.__defineGetter__("uuid", function () {
        return _uuid;
    });
    _self.__defineGetter__("protocol", function () {
        return _protocol;
    });
    _self.__defineGetter__("state", function () {
        return state;
    });
    _self.__defineGetter__("peer", function () {
        return _peer;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/TimeDuration', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (l, u) {
    var _length, _unit,
        TimeDurationUnit = {"MSECS": 1,
                            "SECS": 1000,
                            "MINS": 60 * 1000,
                            "HOURS": 60 * 60 * 1000,
                            "DAYS": 24 * 60 * 60 * 1000
                           },
        _simplifyDuration = function (ms) {
            var TDur = require('ripple/platform/tizen/2.0/TimeDuration'),
                uni = "MSECS";
            if ((ms % 1000) === 0) {
                ms = ms / 1000;
                uni = "SECS";
                if ((ms % 60) === 0) {
                    ms = ms / 60;
                    uni = "MINS";
                    if ((ms % 60) === 0) {
                        ms = ms / 60;
                        uni = "HOURS";
                        if ((ms % 24) === 0) {
                            ms = ms / 24;
                            uni = "DAYS";
                        }
                    }
                }
            }
            return (new TDur(ms, uni));
        },
        _toMSECS = function (unit) {
            if (TimeDurationUnit[unit] === undefined) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            } else {
                return TimeDurationUnit[unit];
            }
        };

    _length = l || 0;
    if ((u !== undefined) && (u !== null)) {
        if (TimeDurationUnit[u] === undefined) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        } else {
            _unit = u;
        }
    } else {
        _unit = "MSECS";
    }
    return {
        length: _length,
        unit: _unit,
        difference: function (o) {
            var thisMS = _length * _toMSECS(_unit),
                otherMS = o.length * _toMSECS(o.unit);
            return _simplifyDuration(thisMS - otherMS);
        },
        equalsTo: function (o) {
            var thisMS = _length * _toMSECS(_unit),
                otherMS = o.length * _toMSECS(o.unit);
            return (thisMS === otherMS);
        },
        lessThan: function (o) {
            var thisMS = _length * _toMSECS(_unit),
                otherMS = o.length * _toMSECS(o.unit);
            return (thisMS < otherMS);
        },
        greaterThan: function (o) {
            var thisMS = _length * _toMSECS(_unit),
                otherMS = o.length * _toMSECS(o.unit);
            return (thisMS > otherMS);
        }
    };
};

});
define('ripple/platform/tizen/2.0/ContactAddress', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils');

module.exports = function (prop) {
    var _self, type, i;
    _self = {};
    if (prop) {
        if (prop.country !== null && prop.country !== undefined) {
            _self.country = String(prop.country);
        }
        if (prop.region !== null && prop.region !== undefined) {
            _self.region = String(prop.region);
        }
        if (prop.city !== null && prop.city !== undefined) {
            _self.city = String(prop.city);
        }
        if (prop.streetAddress !== null && prop.streetAddress !== undefined) {
            _self.streetAddress = String(prop.streetAddress);
        }
        if (prop.additionalInformation !== null && prop.additionalInformation !== undefined) {
            _self.additionalInformation = String(prop.additionalInformation);
        }
        if (prop.postalCode !== null && prop.postalCode !== undefined) {
            _self.postalCode = String(prop.postalCode);
        }
        _self.types = [];
        if (tizen1_utils.isValidArray(prop.types)) {
            for (i = 0; i < prop.types.length; i++) {
                type = String(prop.types[i]).toUpperCase();
                _self.types.push(type);
            }
        }
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/alarm', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    exception = require('ripple/exception'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    Alarm = require('ripple/platform/tizen/2.0/AlarmBase'),
    AlarmRelative = require('ripple/platform/tizen/2.0/AlarmRelative'),
    AlarmAbsolute = require('ripple/platform/tizen/2.0/AlarmAbsolute'),
    AlarmStore,
    _DB_ALARMS_KEY = "tizen1.0-db-alarms",
    PERIOD_MINUTE = 60,
    PERIOD_HOUR   = 60 * PERIOD_MINUTE,
    PERIOD_DAY    = 24 * PERIOD_HOUR,
    PERIOD_WEEK   = 7 * PERIOD_DAY,
    _alarms = {}, _alarmStack = [],
    _security = {
        "http://tizen.org/api/alarm": [],
        "http://tizen.org/api/alarm.read": ["get", "getAll"],
        "http://tizen.org/api/alarm.write": ["add", "remove", "removeAll", "getRemainingSeconds", "getNextScheduledDate"],
        all: true
    },
    _isInitialized = false, _self;

function _initialize() {
    _alarms = db.retrieveObject(_DB_ALARMS_KEY);
    utils.forEach(_alarms, function (alarmStore) {
        _alarmStack.push(alarmStore);
    });
    _isInitialized = true;
}

function _get() {
    if (!_isInitialized) {
        _initialize();
    }
}

function _save() {
    db.saveObject(_DB_ALARMS_KEY, _alarmStack);
}

function _updateDB(alarmStore) {
    _alarmStack.push(alarmStore);
    _save();
}

function _getCurrentAppId() {
    return db.retrieve("current-url");
}

function _checkTriggerAlarm(alarm) {
    var remainingTime, nextTriggerDate;

    if (alarm.delay !== undefined) { // Alarm is relative
        if (alarm.period !== null)
            return false;

        remainingTime = alarm.getRemainingSeconds();
        if (remainingTime === null)
            return true; // This alarm is triggered, remove it
    } else if (alarm.period !== undefined) { // Alarm is absolute,no repeat
        nextTriggerDate = alarm.getNextScheduledDate();
        if (nextTriggerDate === null)
            return true; // Already triggered
    }

    return false; // Alarm is repeat, not expired
}

function _convertToAlarm(alarmStore) {
    var alarm, frequency;

    if (alarmStore.delay !== null) { // AlarmRelative
        alarm = new AlarmRelative(alarmStore.delay, alarmStore.period);
        alarm.date = alarmStore.date;
    } else { // AlarmAbsolute
        if (alarmStore.period !== null && alarmStore.period !== PERIOD_WEEK) {
            frequency = alarmStore.period;
        } else if (alarmStore.period === PERIOD_WEEK) {
            frequency = alarmStore.daysOfTheWeek;
        }
        alarm = new AlarmAbsolute(alarmStore.date, frequency);
    }
    alarm.id = alarmStore.id;

    return alarm;
}

function _eventCheckAlarm(id) {
    var alarm, diff;

    _get();
    utils.forEach(_alarmStack, function (alarmStore) {
        if (alarmStore.id !== id)
            return;

        alarm = _convertToAlarm(alarmStore);
        if (alarm.delay !== undefined) {
            diff = alarm.getRemainingSeconds();
            if (0 < diff && diff < 2) {
                event.trigger("SendTriggerAppId", [alarmStore.applicationId]);
            }
        } else {
            diff = (new Date()) - alarm.getNextScheduledDate();
            if (-2000 < diff && diff < 2000) {
                event.trigger("SendTriggerAppId", [alarmStore.applicationId]);
            }
        }
    });
}

_self = function () {
    var currentAppId, alarm;

    alarm = {
        add: function (alarm, applicationId, argument) {
            var alarmStore;

            if (!_security.all && !_security.add)
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            if ((alarm === undefined || !(alarm instanceof Alarm) ||
                (typeof applicationId !== "string") ||
                (argument !== undefined && typeof argument !== "string")))
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            currentAppId = _getCurrentAppId(); // Update The Current URL.
            alarmStore = new AlarmStore(alarm, applicationId, currentAppId, argument);
            _updateDB(alarmStore);
        },

        remove: function (alarmId) {
            var isFound = false, i;

            if (!_security.all && !_security.remove)
                throw (new WebAPIError(errorcode.SECURITY_ERR));

            if (typeof alarmId !== "string")
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

            for (i in _alarmStack) {
                if (_alarmStack[i].id !== alarmId)
                    continue;

                _alarmStack.splice(i, 1);
                _save();
                isFound = true;
            }
            if (!isFound)
                throw (new WebAPIError(errorcode.NOT_FOUND_ERR));
        },

        removeAll: function () {
            var availableStack = [], i;

            if (!_security.all && !_security.remove)
                throw (new WebAPIError(errorcode.SECURITY_ERR));

            for (i in _alarmStack) {
                if (_alarmStack[i].currentAppId === currentAppId)
                    continue;

                availableStack.push(_alarmStack[i]);
            }
            _alarmStack = availableStack;
            _save();
        },

        getAll: function () {
            var availableStack = [], backAlarms = [], isExpired, alarm, i;

            if (!_security.all && !_security.getAll)
                throw (new WebAPIError(errorcode.SECURITY_ERR));

            for (i in _alarmStack) {
                alarm = _convertToAlarm(_alarmStack[i]); // alarmStore --> alarm
                isExpired = _checkTriggerAlarm(alarm); // Check if the alarm is expired
                if (isExpired)
                    continue;

                availableStack.push(_alarmStack[i]);
                if (_alarmStack[i].currentAppId === currentAppId)
                    backAlarms.push(alarm);
            }
            _alarmStack = availableStack;
            _save();
            return backAlarms;
        },

        get: function (alarmId) {
            var isFound = false, item, isExpired, alarm;

            if (!_security.all && !_security.get)
                throw (new WebAPIError(errorcode.SECURITY_ERR));

            if (typeof alarmId !== "string")
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

            for (item in _alarmStack) {
                if (_alarmStack[item].id === alarmId) {
                    alarm = _convertToAlarm(_alarmStack[item]);
                    isExpired = _checkTriggerAlarm(alarm);
                    if (isExpired) {
                        _alarmStack.splice(item, 1);
                        _save();
                    } else {
                        isFound = true;
                    }
                    break;
                }
            }
            if (!isFound)
                throw (new WebAPIError(errorcode.NOT_FOUND_ERR));

            return alarm;
        },

        handleSubFeatures: function (subFeatures) {
            for (var subFeature in subFeatures) {
                if (_security[subFeature].length === 0) {
                    _security.all = true;
                    return;
                }
                _security.all = false;
                utils.forEach(_security[subFeature], function (method) {
                    _security[method] = true;
                });
            }
        }
    };

    currentAppId = _getCurrentAppId();
    _get();

    alarm.__defineGetter__("PERIOD_MINUTE", function () {
        return PERIOD_MINUTE;
    });

    alarm.__defineGetter__("PERIOD_HOUR", function () {
        return PERIOD_HOUR;
    });

    alarm.__defineGetter__("PERIOD_DAY", function () {
        return PERIOD_DAY;
    });

    alarm.__defineGetter__("PERIOD_WEEK", function () {
        return PERIOD_WEEK;
    });

    return alarm;
};

AlarmStore = function (alarmObject, applicationId, currentAppId, argument) {
    var _self;
    _self = {
        id: alarmObject.id,
        delay: alarmObject.delay || null,
        date: alarmObject.date || null,
        period: alarmObject.period || null,
        daysOfTheWeek: alarmObject.daysOfTheWeek || null,
        applicationId: applicationId,
        currentAppId: currentAppId,
        argument: argument || null
    };
    return _self;
};

event.on("CheckAlarm", function (id) {
    _eventCheckAlarm(id);
});

module.exports = _self;

});
define('ripple/platform/tizen/2.0/MessageBody', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils');

module.exports = function (id, isloaded, _plainbody, _htmlbody, inlineattachments) {
    var msgbody, _id = id, _loaded = isloaded;
    msgbody = {
        plainBody: _plainbody,
        htmlBody: _htmlbody,
        inlineAttachments: [] // TODO: not support attachment yet
    };
    msgbody.__defineGetter__("messageId", function () {
        return _id;
    });
    msgbody.__defineGetter__("loaded", function () {
        return _loaded;
    });
    return msgbody;
};

});
define('ripple/platform/tizen/2.0/BluetoothDevice', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    event = require('ripple/event'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    BluetoothClass = require('ripple/platform/tizen/2.0/BluetoothClass'),
    BluetoothSocket = require('ripple/platform/tizen/2.0/BluetoothSocket');

module.exports = function (prop) {
    var _self,
        _name = prop.name || "",
        _address = prop.address || "",
        _deviceClass = new BluetoothClass(prop.deviceClass) || {},
        _isBonded = prop.isBonded || false,
        _isTrusted = prop.isTrusted || false,
        _isConnected = prop.isConnected || false,
        _services = prop.services,
        _security = prop.metaData,
        _uuids = [],
        _sockets = {};

    _self = {
        connectToServiceByUUID: function (uuid, successCallback, errorCallback, protocol) {
            if (!_security.all && !_security.connectToServiceByUUID) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (typeof uuid !== "string") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            tizen1_utils.validateArgumentType(successCallback, "function",
                    new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

            if (errorCallback) {
                tizen1_utils.validateArgumentType(errorCallback, "function",
                        new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }

            if (protocol) {
                if (protocol !== "RFCOMM" && protocol !== "L2CAP") {
                    new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                }
            }

            if (_uuids.join(",").indexOf(uuid) === -1) {
                if (errorCallback) {
                    errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                }
                return;
            }
            _isConnected = true;
            event.trigger("bt-device-connected-changed", [_address, true]);
            Object.defineProperty(_sockets[uuid], "state", {value: "OPEN", writable: false});
            event.trigger("bt-service-state-changed", [_address, uuid, true]);
            successCallback(_sockets[uuid]);
        }
    };
    
	event.on("bt-device-connected-update", function (addr, isConnected) {
		if (addr === _address) {
			_isConnected = isConnected;
			event.trigger("bt-device-connected-changed", [_address, _isConnected]);
		}
	});

    utils.forEach(_services, function (service) {
		_uuids.push(service.uuid);
        _sockets[service.uuid] = new BluetoothSocket({
            uuid: service.uuid,
            protocol: service.protocol,
            state: "CLOSED",
            peer: _self,
            metaData: _security
        });
    });

    _self.__defineGetter__("name", function () {
        return _name;
    });
    _self.__defineGetter__("address", function () {
        return _address;
    });
    _self.__defineGetter__("deviceClass", function () {
        return _deviceClass;
    });
    _self.__defineGetter__("isBonded", function () {
        return _isBonded;
    });
    _self.__defineGetter__("isTrusted", function () {
        return _isTrusted;
    });
    _self.__defineGetter__("isConnected", function () {
        return _isConnected;
    });
    _self.__defineGetter__("uuids", function () {
        return _uuids;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/power', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    deviceSettings = require('ripple/deviceSettings'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    PowerStateRequest = require('ripple/platform/tizen/2.0/PowerStateRequest'),
    _RULES = constants.POWER_RULES,// Rule Allow: true; Deny false
    _POWER_RESOURCE = constants.POWER_RESOURCE,
    _CPU_STATE = constants.POWER_RESOURCE.CPU.STATE,
    _DISPLAY_STATE = constants.POWER_RESOURCE.DISPLAY.STATE,
    cpuState = {"previous" : null, "current" : null},
    displayState = {"previous" : null, "current" : null},
    _PORWER_RULES_KEY = "tizen1-db-power-role",
    _cpuListener = {
        "LOW" : [],
        "HIGH" : []
    },
    _displayListener = {
        "OFF" : [],
        "DIM" : [],
        "NORMAL" : [],
        "BRIGHT" : []
    },
    _self;

/**initialize**/
function initState() {
    var dbRules;
    //Init power rules.
    dbRules = db.retrieveObject(_PORWER_RULES_KEY);
    _RULES =  dbRules && _RULES ? dbRules : _RULES;
    event.trigger("initPowerDB", [_RULES]);
    //Init power state.
    updateResourceState();
}

function updatePowerRules(state, value) {
    _RULES[state] = value;
    db.saveObject(_PORWER_RULES_KEY, _RULES);
}

function getResourceState(resource, value) {
    var state;
    value = Number(value);
    switch (resource) {
    case "CPU" :
        if (value <= _CPU_STATE.LOW.MAX) {
            state = _CPU_STATE.LOW.NAME;//LOW
        } else {
            state = _CPU_STATE.HIGH.NAME;
        }
        break;
    case "DISPLAY" :
        if (value ===  _DISPLAY_STATE.OFF.MAX) {
            state = _DISPLAY_STATE.OFF.NAME;
        } else if (value <= _DISPLAY_STATE.DIM.MAX) {
            state = _DISPLAY_STATE.DIM.NAME;
        } else if (value <= _DISPLAY_STATE.NORMAL.MAX) {
            state = _DISPLAY_STATE.NORMAL.NAME;
        } else {
            state = _DISPLAY_STATE.BRIGHT.NAME;
        }
        break;
    default:
        break;
    }
    return state;
}

function updateResourceState() {
    var load, brightness, actualState;
    // Init CPU state
    load = deviceSettings.retrieve("Cpu.load");
    actualState = getResourceState("CPU", load);
    cpuState.previous = cpuState.current;
    cpuState.current = actualState;
    // Init DISPLAY state
    brightness = deviceSettings.retrieve("Display.brightness");
    actualState = getResourceState("DISPLAY", brightness);
    displayState.previous = displayState.current;
    displayState.current = actualState;
}

function callListeners(listeners, resource, actualState, requestState) {
    if (listeners.length === 0) {
        return;
    }
    listeners.forEach(function (listener) {
        setTimeout(function () {
            listener(resource, actualState, requestState);
        }, 1);
    });
}

function findListenerCB(resource, value, stateObj) {
    var i, listeners, actualState = getResourceState(resource, value);
    listeners = (resource === "CPU" ? _cpuListener : _displayListener);
    if (!stateObj.previous) {
        return;
    }
    if (stateObj.previous !== stateObj.current) {
        callListeners(listeners[stateObj.previous], resource, actualState, stateObj.previous);
        callListeners(listeners[stateObj.current], resource, actualState, stateObj.current);
    }
}

function saveListenerCB(resource, state, listener) {
    if (listener) {
        switch (resource) {
        case "CPU" :
            _cpuListener[state].push(listener);
            break;
        case "DISPLAY" :
            _displayListener[state].push(listener);
            break;
        default:
            break;
        }
    }
}

_self = {
    request: function (request, successCB, errorCB, listener) {
        var resource, state, value, actualState;
        //Check all parameters.
        tizen1_utils.validateCallbackType(listener);
        tizen1_utils.validateCallbackType(successCB, errorCB);
        if (!request || !request.resource || !request.minimalState) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }
        resource = request.resource;
        state = request.minimalState;
        //Check resource
        if (!_POWER_RESOURCE.hasOwnProperty(resource)) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }
        //Check state
        if (!_POWER_RESOURCE[resource].STATE.hasOwnProperty(state)) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }
        saveListenerCB(resource, state, listener);
        //Check the state rule
        if (!_RULES[state]) {//Deny
            actualState = resource === "CPU" ? cpuState : displayState;
            if (errorCB) {
                setTimeout(function () {
                    errorCB(new WebAPIError(errorcode.NOT_SUPPORTED_ERR));
                }, 1);
            }
            if (listener) {
                setTimeout(function () {
                    listener(resource, actualState.current, state);
                }, 1);
            }
            return;
        }
        switch (resource) {
        case "CPU" :
            value = _CPU_STATE[state].VALUE;// Update Cpu.load.
            deviceSettings.persist("Cpu.load", value);
            updateResourceState();
            findListenerCB('CPU', value, cpuState);
            event.trigger("CpuLoadChangedByPower", [value]);
            break;
        case "DISPLAY" :
            value = _DISPLAY_STATE[state].VALUE;// Update Display.brightness.
            deviceSettings.persist("Display.brightness", value);
            updateResourceState();
            findListenerCB("DISPLAY", value, displayState);
            event.trigger("DisplayBrightnessChangedByPower", [value]);
            break;
        default:
            break;
        }
        if (successCB) {//SuccessCallback
            setTimeout(function () {
                successCB();
            }, 1);
        }
        
    },

    release: function (resource) {
        switch (resource) {
        case "CPU" :
            _cpuListener.LOW = [];
            _cpuListener.HIGH = [];
            break;
        case "DISPLAY" :
            _displayListener.OFF = [];
            _displayListener.DIM = [];
            _displayListener.NORMAL = [];
            _displayListener.BRIGHT = [];
            break;
        default:
            throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
        }
    }
};

initState();
event.on("CpuLoadChanged", function (value) {
    updateResourceState();
    findListenerCB('CPU', value, cpuState);
});
event.on("DisplayBrightnessChanged", function (value) {
    updateResourceState();
    findListenerCB("DISPLAY", value, displayState);
});
event.on("updatePowerRules", function (object) {
    updatePowerRules(object.state, object.value);
});
module.exports = _self;


});
define('ripple/platform/tizen/2.0/CalendarRecurrenceRule', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    TZDate = require('ripple/platform/tizen/2.0/TZDate');

module.exports = function (frequency, ruleInitDict) {
    var _self = {};

    _self.frequency = (frequency) ? frequency : 0;

    if ((ruleInitDict !== undefined) && (ruleInitDict !== null)) {
        _self.interval        = ((ruleInitDict.interval > 0) && (ruleInitDict.interval === parseInt(ruleInitDict.interval))) ? Number(ruleInitDict.interval) : 1;
        _self.untilDate       = tizen1_utils.isValidTZDate(ruleInitDict.untilDate) ? (new TZDate(new Date(ruleInitDict.untilDate))) : null;
        _self.occurrenceCount = (ruleInitDict.occurrenceCount === parseInt(ruleInitDict.occurrenceCount)) ? Number(ruleInitDict.occurrenceCount) : -1;
        _self.daysOfTheWeek   = tizen1_utils.isValidArray(ruleInitDict.daysOfTheWeek) ? utils.copy(ruleInitDict.daysOfTheWeek) : [];
        _self.setPositions    = tizen1_utils.isValidArray(ruleInitDict.setPositions) ? utils.copy(ruleInitDict.setPositions) : [];
        _self.exceptions      = tizen1_utils.isValidArray(ruleInitDict.exceptions) ? utils.copy(ruleInitDict.exceptions) : [];
    } else {
        _self.interval        = 1;
        _self.untilDate       = null;
        _self.occurrenceCount = -1;
        _self.daysOfTheWeek   = [];
        _self.setPositions    = [];
        _self.exceptions      = [];
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/CalendarItem', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    TZDate = require('ripple/platform/tizen/2.0/TZDate'),
    CalendarRecurrenceRule = require('ripple/platform/tizen/2.0/CalendarRecurrenceRule'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    CalendarItemInit,
    CalendarEventInit,
    CalendarTaskInit,
    CalendarItem;

CalendarItem = function (type, id, lastModificationDate) {
    var _self;

    function _2digital(number) {
        return ((number >= 10) ? '' : '0') + number;
    }

    if ((type !== "EVENT") && (type !== "TASK"))
        throw new WebAPIError(errorcode.NOT_FOUND_ERR);

    _self = (type === "EVENT") ? new CalendarEventInit() : new CalendarTaskInit();

    id = id || Math.uuid(null, 16);
    lastModificationDate = (lastModificationDate) ? utils.copy(lastModificationDate) : (new TZDate());
    _self.status = (type === "EVENT") ? "CONFIRMED" : "NEEDS_ACTION";

    _self.__defineGetter__("id", function () {
        return id;
    });

    _self.__defineGetter__("lastModificationDate", function () {
        return lastModificationDate;
    });

    _self.clone = function () {
        var item = new CalendarItem(type);

        item.id                   = Math.uuid(null, 16);
        item.lastModificationDate = new TZDate();
        item.description          = _self.description;
        item.summary              = _self.summary;
        item.isAllDay             = _self.isAllDay;
        item.startDate            = _self.startDate;
        item.duration             = _self.duration;
        item.location             = _self.location;
        item.geolocation          = _self.geolocation;
        item.organizer            = _self.organizer;
        item.visibility           = _self.visibility;
        item.status               = _self.status;
        item.priority             = _self.priority;
        item.alarms               = _self.alarms;
        item.categories           = _self.categories;
        item.attendees            = _self.attendees;

        if (type === "EVENT") {
            item.endDate          = _self.endDate;
            item.availability     = _self.availability;
            item.recurrenceRule   = _self.recurrenceRule;
        } else {
            item.dueDate          = _self.dueDate;
            item.completedDate    = _self.completedDate;
            item.progress         = _self.progress;
        }

        return item;
    };

    _self.convertToString = function (format) {
        var str = "", pri, i, date, before, y, m, d, hh, mm, ss, dateStart = "", dateEnd = "",
            header = "BEGIN:VCALENDAR\r\nPRODID:-//Tizen.org//Tizen Calendar//EN\r\nVERSION:2.0\r\n",
            end = "END:VCALENDAR\r\n";

        if (format !== "ICALENDAR_20" && format !== "VCALENDAR_10") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERROR);
        }

        //TODO: vcalendar 1.0 doesn't support yet
        if (format === "VCALENDAR_10") {
            return;
        }

        str = header;
        if (type === "EVENT") {
            str += "BEGIN:VEVENT\r\n";
        } else if (type === "TASK") {
            str += "BEGIN:VTODO\r\n";
        }

        if (this.isAllDay) {
            if (this.startDate) {
                date = this.startDate;
                y = date.getFullYear();
                m = _2digital(date.getMonth() + 1);
                d = _2digital(date.getDate());
                str += "DTSTART;VALUE=DATE:" + y + m + d + "\r\n";
                dateStart = "" + y + m + d + "T000000Z";
                if (this.duration) {
                    date = date.addDuration(this.duration);
                    y = date.getFullYear();
                    m = _2digital(date.getMonth() + 1);
                    d = _2digital(date.getDate());
                    str += "DTEND;VALUE=DATE:" + y + m + d + "\r\n";
                    dateEnd = "" + y + m + d + "T000000Z";
                }
            }
        } else {
            if (this.startDate) {
                date = this.startDate;
                y = date.getFullYear();
                m = _2digital(date.getMonth() + 1);
                d = _2digital(date.getDate());
                hh = _2digital(date.getHours());
                mm = _2digital(date.getMinutes());
                ss = _2digital(date.getSeconds());
                str += "DTSTART:" + y + m + d + "T" + hh + mm + ss + "Z" + "\r\n";
                dateStart = "" + y + m + d + "T" + hh + mm + ss + "Z";
                if (this.duration && this.duration.length && this.duration.unit) {
                    date = date.addDuration(this.duration);
                    y = date.getFullYear();
                    m = _2digital(date.getMonth() + 1);
                    d = _2digital(date.getDate());
                    hh = _2digital(date.getHours());
                    mm = _2digital(date.getMinutes());
                    ss = _2digital(date.getSeconds());
                    str += "DTEND:" + y + m + d + "T" + hh + mm + ss + "Z" + "\r\n";
                    dateEnd = "" + y + m + d + "T" + hh + mm + ss + "Z";
                }
            }
        }

        if (this.description) {
            str += "DESCRIPTION:" + this.description + "\r\n";
        }
        if (this.summary) {
            str += "SUMMARY:" + this.summary + "\r\n";
        }
        if (this.location) {
            str += "LOCATION:" + this.location + "\r\n";
        }
        if (this.geolocation) {
            // Don't need to check latitude and longitude due to they are mandatory attributes
            str += "GEO:" + this.geolocation.latitude + "," + this.geolocation.longitude + "\r\n";
        }
        if (this.organizer) {
            str += "ORGANIZER:" + this.organizer + "\r\n";
        }
        if (this.visibility) {
            str += "CLASS:" + this.visibility + "\r\n";
        }
        if (this.status) {
            str += "STATUS:" + this.status + "\r\n";
        }
        if (this.priority) {
            switch (this.priority) {
            case "HIGH":
                pri = 2;
                break;
            case "MEDIUM":
                pri = 5;
                break;
            case "LOW":
                pri = 7;
                break;
            }
            str += "PRIORITY:" + pri + "\r\n";
        }
        if (tizen1_utils.isValidArray(this.alarms)) {
            for (i = 0; i < this.alarms.length; i++) {
                str += "BEGIN:VALARM\r\n";
                // Don't need to check this.alarms[i].method due to it is a mandatory attribute
                str += "ACTION:" + this.alarms[i].method + "\r\n";
                if (this.alarms[i].description) {
                    str += "DESCRIPTION:" + this.alarms[i].description + "\r\n";
                } else {
                    // description property MUST included if action is DISPLAY (RFC5545 3.6.6)
                    str += "DESCRIPTION:This is a reminder\r\n";
                }
                if (this.alarms[i].absoluteDate) {
                    date = this.alarms[i].absoluteDate;
                    y = date.getFullYear();
                    m = _2digital(date.getMonth() + 1);
                    d = _2digital(date.getDate());
                    hh = _2digital(date.getHours());
                    mm = _2digital(date.getMinutes());
                    ss = _2digital(date.getSeconds());
                    str += "TRIGGER;VALUE=DATE-TIME:" + y + m + d + "T" + hh + mm + ss + "Z" + "\r\n";
                } else {
                    //it must be included before attribute
                    before = this.alarms[i].before;
                    switch (before.unit) {
                    case "DAYS":
                        str += "TRIGGER:-P" + before.length + "D" + "\r\n";
                        break;
                    case "HOURS":
                        str += "TRIGGER:-P0DT" + before.length + "H0M0S" + "\r\n";
                        break;
                    case "MINS":
                        str += "TRIGGER:-P0DT0H" + before.length + "M0S" + "\r\n";
                        break;
                    case "SECS":
                        str += "TRIGGER:-P0DT0H0M" + before.length + "S" + "\r\n";
                        break;
                    }
                }
                str += "END:VALARM\r\n";
            }
        }
        if (tizen1_utils.isValidArray(this.categories)) {
            str += "CATEGORIES:";
            for (i = 0; i < this.categories.length; i++) {
                str += this.categories[i] + ",";
            }
            str = str.slice(0, -1);
            str += "\r\n";
        }
        if (tizen1_utils.isValidArray(this.attendees)) {
            for (i = 0; i < this.attendees.length; i++) {
                //TODO: basic implementation
                str += "ATTENDEE:mailto:" + this.attendees[i].uri + "\r\n";
            }
        }

        if (type === "EVENT" && this.availability && dateStart !== "" && dateEnd !== "") {
            switch (this.availability) {
            case "BUSY":
                str += "FREEBUSY;FBTYPE=BUSY:";
                break;
            case "FREE":
                str += "FREEBUSY;FBTYPE=FREE:";
                break;
            }
            str += dateStart + "/" + dateEnd + "\r\n";
        }
        //TODO: endDate doesn't support (CalendarEvent specific property)
        //TODO: recurrenceRule doesn't support (CalendarEvent specific property)
        //TODO: dueDate doesn't support (CalendarTask specific property)
        //TODO: completeDate doesn't support (CalendarTask specific property)
        if (type === "TASK" && this.progress) {
            str += "PERCENT-COMPLETE:" + this.progress + "\r\n";
        }

        if (type === "EVENT") {
            str += "END:VEVENT\r\n";
        } else if (type === "TASK") {
            str += "END:VTODO\r\n";
        }
        str += end;
    };

    return _self;
};

CalendarItemInit = function () {
    return {
        description: "",
        summary:     "",
        isAllDay:    false,
        startDate:   null,
        duration:    null,
        location:    "",
        geolocation: new SimpleCoordinates(),
        organizer:   "",
        visibility:  "PUBLIC",
        status:      "",
        priority:    "LOW",
        alarms:      [],
        categories:  [],
        attendees:   []
    };
};

CalendarEventInit = function () {
    var _self = new CalendarItemInit();

    _self.endDate        = undefined;
    _self.availability   = undefined;
    _self.recurrenceRule = undefined;

    return _self;
};

CalendarTaskInit = function () {
    var _self = new CalendarItemInit();

    _self.dueDate       = undefined;
    _self.completedDate = undefined;
    _self.progress      = undefined;

    return _self;
};

module.exports = CalendarItem;

});
define('ripple/platform/tizen/2.0/PrivMessage', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"),
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils');

module.exports = function (m, opt) {
    return {
// readonly begin
        priv: {id: opt.id,
               serviceId: opt.serviceId,
               conversationId: opt.conversationId,
               folderId: opt.folderId,
               type: opt.type,
               timestamp: new Date(opt.timestamp),
               from: opt.from,
               hasAttachment: opt.hasAttachment,
               messageStatus: opt.messageStatus
        },
// readonly end
        to: m.to.slice(0),
        cc: m.cc.slice(0),
        bcc: m.bcc.slice(0),
        body: utils.copy(m.body),
        isRead: m.isRead,
        isHighPriority: m.isHighPriority,
        subject: m.subject,
        inResponseTo: m.inResponseTo,
        attachments: utils.copy(m.attachments)
    };
};

});
define('ripple/platform/tizen/2.0/ContactPhoneNumber', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils');

module.exports = function (number, types) {
    var _self, _number = "", i,
        _types = [], type;
    
    if (number) {
        _number = String(number);
    }
    if (tizen1_utils.isValidArray(types)) {
        for (i = 0; i < types.length; i++) {
            type = String(types[i]).toUpperCase();
            _types.push(type);
        }
    }

    _self = {
        number : _number,
        types : _types
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/POIGeometry', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    GeoRectBounds = require('ripple/platform/tizen/2.0/GeoRectBounds');

module.exports = function (position, viewport, wkt) {
    var _self, _position = null, _viewport = null, _wkt = "";

    if (position) {
        _position = new SimpleCoordinates(position.latitude, position.longitude);
    }

    if (viewport) {
        _viewport = new GeoRectBounds(viewport.southWest, viewport.northEast);
    }

    if (wkt) {
        _wkt = String(wkt);
    }

    _self = {
        position : _position,
        viewport: _viewport,
        wkt: _wkt
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/CalendarEvent', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var TZDate = require('ripple/platform/tizen/2.0/TZDate'),
    CalendarItem = require('ripple/platform/tizen/2.0/CalendarItem'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    CalendarRecurrenceRule = require('ripple/platform/tizen/2.0/CalendarRecurrenceRule');

module.exports = function (eventInitDict) {
    var _self, isDetached = false; //isDetached

    _self = new CalendarItem("EVENT");

    if ((eventInitDict !== undefined) && (eventInitDict !== null)) {
        _self.endDate        = tizen1_utils.isValidTZDate(eventInitDict.endDate) ? (new TZDate(new Date(eventInitDict.endDate))) : null;
        _self.availability   = (eventInitDict.availability) ? String(eventInitDict.availability) : "BUSY";
        _self.recurrenceRule = utils.copy(eventInitDict.recurrenceRule);
        if (eventInitDict.description) {
            _self.description = String(eventInitDict.description);
        }
        if (eventInitDict.summary) {
            _self.summary = String(eventInitDict.summary);
        }
        if (eventInitDict.isAllDay && (typeof eventInitDict.isAllDay === "boolean")) {
            _self.isAllDay = eventInitDict.isAllDay;
        }
        if (eventInitDict.startDate && tizen1_utils.isValidTZDate(eventInitDict.startDate)) {
            _self.startDate = eventInitDict.startDate;
        }
        if (eventInitDict.duration && (typeof eventInitDict.duration === "object")) {
            _self.duration = new TZDate(eventInitDict.duration);
        }
        if (eventInitDict.location) {
            _self.location = String(eventInitDict.location);
        }
        if (eventInitDict.geolocation && eventInitDict.geolocation.latitude && eventInitDict.geolocation.longitude) {
            _self.geolocation = new SimpleCoordinates(eventInitDict.geolocation.latitude, eventInitDict.geolocation.longitude);
        }
        if (eventInitDict.organizer) {
            _self.organizer = String(eventInitDict.organizer);
        }
        if (eventInitDict.visibility) {
            _self.visibility = String(eventInitDict.visibility);
        }
        if (eventInitDict.status) {
            _self.status = String(eventInitDict.status);
        }
        if (eventInitDict.priority) {
            _self.priority = String(eventInitDict.priority);
        }
        if (eventInitDict.alarms && tizen1_utils.isValidArray(eventInitDict.alarms)) {
            var isInValid = false;
            eventInitDict.alarms.some(function (alarm) {
                if (!alarm || alarm.method === undefined) {// 'method' is CalendarAlarm's property.
                    isInValid = true;
                    return;
                }
            });
            if (!isInValid) {
                _self.alarms = eventInitDict.alarms;
            }
        }
        if (eventInitDict.categories && tizen1_utils.isValidArray(eventInitDict.categories)) {
            var isInValid = false;
            eventInitDict.categories.some(function (categorie) {
                if (!categorie || typeof categorie !== "string") {
                    isInValid = true;
                    return;
                }
            });
            if (!isInValid) {
                _self.categories = eventInitDict.categories;
            }
        }
        if (eventInitDict.attendees && tizen1_utils.isValidArray(eventInitDict.attendees)) {
            var isInValid = false;
            eventInitDict.attendees.some(function (attendee) {
                if (!attendee || attendee.uri === undefined) {// 'uri' is CalendarAttendee's property.
                    isInValid = true;
                    return;
                }
            });
            if (!isInValid) {
                _self.attendees = eventInitDict.attendees;
            }
        }
    } else {
        _self.endDate        = null;
        _self.availability   = "BUSY";
        _self.recurrenceRule = new CalendarRecurrenceRule();
    }

    _self.expandRecurrence = function (startDate, endDate, successCallback, errorCallback) {
        _self.startDate = startDate;
        _self.endDate   = endDate;
    };
    _self.__defineGetter__("isDetached", function () {
        return isDetached;
    });
    return _self;
};

});
define('ripple/platform/tizen/2.0/map', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var lbs = require('ripple/platform/tizen/2.0/lbs_utils'),
    mapProviders = [],
    MapStyle,
    MapProvider,
    _self;

function _initialize() {
    // EPSG:3857 is a Spherical Mercator projection coordinate system popularized by web services such as Google and later OpenStreetMap
    // mapStyles are from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
    var projection = "EPSG:3857",
        mapStyle1 = new MapStyle("Mapnik", "http://b.tile.openstreetmap.org/${z}/${x}/${y}.png"),
        mapStyle2 = new MapStyle("Cycle", "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png");

    mapProviders = [new MapProvider({name: "OpenStreetMap", connectivity: "ONLINE"}, projection, [mapStyle1, mapStyle2])];
}

_self = {
    getDefaultProvider: function () {
        return mapProviders[0];
    },
    getProviders: function () {
        return mapProviders;
    }
};

MapStyle = function (name, url) {
    return {
        name: name,
        url: url
    };
};

MapProvider = function (prop, projection, mapStyles) {
    var mapProvider = new lbs.LocationServiceProvider(prop);

    mapProvider.__defineGetter__("projection", function () {
        return projection;
    });

    mapProvider.__defineGetter__("mapStyles", function () {
        return mapStyles;
    });

    return mapProvider;
};

_initialize();

module.exports = _self;

});
define('ripple/platform/tizen/2.0/ContactAccount', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

module.exports = function (id, accountURI) {
    var _self, _id, _uri;

    if (id) {
        _id = String(id);
    }

    if (accountURI) {
        _uri = String(accountURI);
    }

    _self = {
        accountServiceId : _id,
        contactURI : _uri
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/ApplicationServiceData', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils');

module.exports = function (key, value) {
    this.key = String(key);
    this.value = [];

    if (tizen1_utils.isValidArray(value)) {
        for (var i in value) {
            this.value.push(String(value[i]));
        }
    }
};

});
define('ripple/platform/tizen/2.0/CompositeFilter', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

module.exports = function (_type, _filters) {
    return {
        type: _type,
        filters: _filters
    };
};


});
define('ripple/platform/tizen/2.0/ReverseGeocodeOptions', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    SortMode = require('ripple/platform/tizen/2.0/SortMode');

module.exports = function (_sortMode, _resultType, _maxResults) {
    var _self;
    if (_sortMode !== null && _sortMode !== undefined) {
        if (typeof _sortMode !== "object") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        try {
            new SortMode(_sortMode.attributeName, _sortMode.order);
        } catch (e) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }
    if (_resultType !== null && _resultType !== undefined) {
        if (_resultType !== "FORMATTED" && _resultType !== "STRUCTURED") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }
    if (_maxResults !== null && _maxResults !== undefined) {
        if (typeof _maxResults !== "number") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }
    _self = {
        sortMode : _sortMode,
        resultType : _resultType || "FORMATTED",
        maxResults : _maxResults || 0
    };

    return _self;
};


});
define('ripple/platform/tizen/2.0/tizen1_utils', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var self,
    utils = require('ripple/utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

self = module.exports = {
    _wac2_regexSanitize: function (regexString) {
        var escapePattern = /([^\\]|^)(%)/g, percentPattern = /\\%/g;
        return regexString.replace("^", "\\^")
                .replace("$", "\\$")
                .replace("(", "\\(")
                .replace(")", "\\)")
                .replace("<", "\\<")
                .replace("[", "\\[")
                .replace("{", "\\{")
                .replace(/\\([^%])/, "\\\\$1")    /* don't replace \\% */
                .replace("|", "\\|")
                .replace(">", "\\>")
                .replace(".", "\\.")
                .replace("*", "\\*")
                .replace("+", "\\+")
                .replace("?", "\\?")
                .replace(escapePattern, "$1.*")  /* replace % with .* */
                .replace(percentPattern, "%");   /* strip excape of % */
    },

    isValidDate: function (d) {
        if (Object.prototype.toString.call(d) !== "[object Date]")
            return false;
        return !isNaN(d.getTime());
    },
    isValidTZDate: function (d) {
        if (Object.prototype.toString.call(d) !== "[object Object]")
            return false;
        return d.getTimezone && !isNaN(d.getDate());//getTimezone() belongs to TZDate
    },
    isValidArray: function (a) {
        return (Object.prototype.toString.call(a) === "[object Array]");
    },

    matchOptionArrayString: function (src, attr, pattern) {
        /* src.obj[attr] is a StringArray */
        var _pattern, re, _stringMatch;
        _pattern = this._wac2_regexSanitize(pattern);
        re = new RegExp("^" + _pattern + "$", "i");

        _stringMatch = function (obj, index) {
            if (pattern.search(/^%*$/i) === 0)
                return true;
            if (obj[attr] === undefined || obj[attr] === null)
                return false;
            return obj[attr].some(function (f) {
                return f.search(re) !== -1;
            });
        };
        return utils.filter(src, _stringMatch);
    },

    matchAttributeBooleanFilter: function (src, attr, value) {
        // only support EXACTLY matchFlag
        var _booleanMatch, atr = attr.split(".");

        if (atr.length === 2) {
            _booleanMatch = function (obj, index) {
                return (obj[atr[0]][atr[1]] === value);
            };
        } else {
            _booleanMatch = function (obj, index) {
                return (obj[attr] === value);
            };
        }

        return utils.filter(src, _booleanMatch);
    },

    matchAttributeArrayFilter: function (src, attr, matchFlag, value) {
        var _re, _arrayMatch, atr = attr.split("."), _existMatch;

        if (atr.length === 2) {
            _existMatch = function (obj, index) {
                return (obj[atr[0]][atr[1]] !== undefined);
            };
        } else {
            _existMatch = function (obj, index) {
                return (obj[attr] !== undefined);
            };
        }

        if (value === undefined) {
            return utils.filter(src, _existMatch);
        }

        switch (matchFlag)
        {
        case "EXACTLY":
            _re = new RegExp("^" + value + "$");
            break;
        case "FULLSTRING":
            _re = new RegExp("^" + value + "$", "i");
            break;
        case "CONTAINS":
            _re = new RegExp(value, "i");
            break;
        case "STARTSWITH":
            _re = new RegExp("^" + value, "i");
            break;
        case "ENDSWITH":
            _re = new RegExp(value + "$", "i");
            break;
        case "EXISTS":
            return utils.filter(src, _existMatch);
        default:
            return [];
        }

        if (atr.length === 2) {
            _arrayMatch = function (obj, index) {
                return (obj[atr[0]][atr[1]].some(function (o) {
                    return (o.search(_re) !== -1);
                }));
            };
        } else {
            _arrayMatch = function (obj, index) {
                return (obj[attr].some(function (o) {
                    return (o.search(_re) !== -1);
                }));
            };
        }

        return utils.filter(src, _arrayMatch);
    },

    matchAttributeRangeFilter: function (src, attr, low, high) {
        var _rangeMatch, atr = attr.split(".");

        if (atr.length === 2) {
            _rangeMatch = function (obj, index) {
                var matched = true;
                if (low !== null && low !== undefined) {
                    matched = (obj[atr[0]][atr[1]] >= low);
                }
                if (matched && (high !== null && high !== undefined)) {
                    matched = (obj[atr[0]][atr[1]] <= high);
                }
                return matched;
            };
        } else {
            _rangeMatch = function (obj, index) {
                var matched = true;
                if (low !== null && low !== undefined) {
                    matched = (obj[attr] >= low);
                }
                if (matched && (high !== null && high !== undefined)) {
                    matched = (obj[attr] <= high);
                }
                return matched;
            };
        }
        return utils.filter(src, _rangeMatch);
    },

    matchAttributeFilter: function (src, attr, matchFlag, value) {
        var _re, _stringMatch, atr = attr.split("."),
            _existMatch;

        if (atr.length === 2) {
            _existMatch = function (obj, index) {
                return (obj[atr[0]][atr[1]] !== undefined);
            };
        } else {
            _existMatch = function (obj, index) {
                return (obj[attr] !== undefined);
            };
        }

        if (value === undefined) {
            return utils.filter(src, _existMatch);
        }

        switch (matchFlag)
        {
        case "EXACTLY":
            _re = new RegExp("^" + value + "$");
            break;
        case "FULLSTRING":
            _re = new RegExp("^" + value + "$", "i");
            break;
        case "CONTAINS":
            _re = new RegExp(value, "i");
            break;
        case "STARTSWITH":
            _re = new RegExp("^" + value, "i");
            break;
        case "ENDSWITH":
            _re = new RegExp(value + "$", "i");
            break;
        case "EXISTS":
            return utils.filter(src, _existMatch);
        default:
            return [];
        }
        if (atr.length === 2) {
            _stringMatch = function (obj, index) {
                if (typeof obj[atr[0]][atr[1]] !== 'string') {
                    return false;
                } else {
                    return (obj[atr[0]][atr[1]].search(_re) !== -1);
                }
            };
        } else {
            _stringMatch = function (obj, index) {
                if (typeof obj[attr] !== 'string') {
                    return false;
                } else {
                    return (obj[attr].search(_re) !== -1);
                }
            };
        }
        return utils.filter(src, _stringMatch);
    },

    matchOptionString: function (src, attr, pattern) {
        /* src.obj[attr] is a string */
        var _stringMatch, _pattern, _re;
        _pattern = this._wac2_regexSanitize(pattern);
        _re = new RegExp("^" + _pattern + "$", "mi");

        _stringMatch = function (obj, index) {
            return (obj[attr].search(_re) !== -1);
        };
        return utils.filter(src, _stringMatch);
    },

    matchOptionDate: function (src, attr, filterStart, filterEnd) {
        var _dateMatch;
        _dateMatch = function (obj, index) {
            var matched = true, valueDate = obj[attr];

            if (filterStart !== undefined && filterStart !== null) {
                matched = (valueDate.getTime() >= filterStart.getTime());
            }
            if (matched && (filterEnd !== undefined && filterEnd !== null)) {
                matched = (valueDate.getTime() <= filterEnd.getTime());
            }
            return matched;
        };
        return utils.filter(src, _dateMatch);
    },

    matchOptionShortArray: function (src, attr, filterArray) {
        /* src.obj[attr] is a short, filterArray is an array
           i.e. find status is [CONFRIMED or TENTATIVE] */
        var arraySome = function (obj, index) {
            return filterArray.some(function (f) {
                return f === obj[attr];
            });
        };
        return utils.filter(src, arraySome);
    },

    validateArgumentType: function (arg, argType, errorObj) {
        var invalidArg = false;

        switch (argType) {
        case "array":
            if (!arg instanceof Array) {
                invalidArg = true;
            }
            break;
        case "date":
            if (!arg instanceof Date) {
                invalidArg = true;
            }
            break;
        case "integer":
            if (typeof Number(arg) !== "number" || Number(arg) !== Math.floor(arg)) {
                invalidArg = true;
            }
            break;
        default:
            if (typeof arg !== argType) {
                invalidArg = true;
            }
            break;
        }

        if (invalidArg) {
            throw errorObj;
        }
    },

    validateCallbackType: function (successCallback, errorCallback) {
        if (successCallback) {
            this.validateArgumentType(successCallback, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (errorCallback) {
            this.validateArgumentType(errorCallback, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    },

    validateEqualArrays: function (arrayOne, arrayTwo) {
        var isEqual = false, i;

        if (Object.prototype.toString.call(arrayTwo) === "[object Array]" &&
            Object.prototype.toString.call(arrayTwo) === "[object Array]" &&
            arrayOne.length === arrayTwo.length) {
            isEqual = true;
            for (i in arrayOne) {
                if (arrayOne[i] !== arrayTwo[i]) {
                    isEqual = false;
                    break;
                }
            }
        }
        return isEqual;
    },

    validateTypeMismatch: function (onSuccess, onError, name, callback) {

        if (onSuccess === undefined || onSuccess === null) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }
        if (onSuccess) {
            this.validateArgumentType(onSuccess, "function",
                                      new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (onError) {
            this.validateArgumentType(onError, "function",
                                      new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        return callback && callback();
    },

    isEmptyObject: function (obj) {
        var prop;

        for (prop in obj) {
            return false;
        }
        return true;
    },

    arrayComposite: function (mode, arrayA, arrayB) {
        var combinedArray = arrayA.concat(arrayB),
            intersectionArray = arrayA.filter(function (value) {
                if (utils.arrayContains(arrayB, value)) {
                    return true;
                }

                return false;
            });

        switch (mode) {
        case "AND":
        case "INTERSECTION":
            return intersectionArray;
        case "OR":
        case "UNION":
            return intersectionArray.concat(combinedArray.filter(function (value) {
                if (utils.arrayContains(intersectionArray, value)) {
                    return false;
                }

                return true;
            }));
        default:
            return undefined;
        }
    },

    isEqual: function (srcObj, aimObj) {
        var i;

        if (typeof srcObj !== typeof aimObj) {
            return false;
        }

        if (srcObj === null || srcObj === undefined || typeof srcObj === 'number' ||
            typeof srcObj === 'string' || typeof srcObj === 'boolean') {
            return srcObj === aimObj;
        }

        for (i in srcObj) {
            if (!aimObj.hasOwnProperty(i) || !self.isEqual(srcObj[i], aimObj[i])) {
                return false;
            }
        }

        return true;
    },

    query: function (objects, filter, sortMode, limit, offset) {
        function isCompositeFilter(filter) {
            return (filter.type) ? true : false;
        }

        function isAttributeFilter(filter) {
            return (filter.matchFlag) ? true : false;
        }

        function getValue(obj, key) {
            var keys = key.split("."),
                value = obj[keys[0]],
                i;

            for (i = 1; i < keys.length; i++) {
                if (value[keys[i]]) {
                    value = value[keys[i]];
                }
            }

            return value;
        }

        function _filter(objects, filter) {
            var i, results, eachResult;

            if (isCompositeFilter(filter)) {
                for (i in filter.filters) {
                    eachResult = _filter(objects, filter.filters[i]);
                    results = (results === undefined) ? eachResult : self.arrayComposite(filter.type, results, eachResult);
                }
                return results;
            }

            if (isAttributeFilter(filter)) {
                results = self.matchAttributeFilter(objects, filter.attributeName, filter.matchFlag, filter.matchValue);
            } else {
                results = self.matchAttributeRangeFilter(objects, filter.attributeName, filter.initialValue, filter.endValue);
            }

            return results;
        }

        function _sort(objects, sortMode) {
            objects.sort(function (a, b) {
                return (sortMode.order === "ASC") ?
                    (getValue(a, sortMode.attributeName) < getValue(b, sortMode.attributeName) ? -1 : 1):
                    (getValue(a, sortMode.attributeName) > getValue(b, sortMode.attributeName) ? -1 : 1);
            });

            return objects;
        }

        var res;

        if (filter === null || filter === undefined)
            return objects;

        res = _filter(objects, filter);

        if (sortMode) {
            _sort(res, sortMode);

            // If the LIMIT expression evaluates to a negative value,
            // then there is no upper bound on the number of rows returned.
            // @spec: If 0, there is no limit set.
            // If the OFFSET clause evaluates to a negative value,
            // the results are the same as if it had evaluated to zero
            if (limit > 0) {
                limit = limit | 0;
                offset = offset | 0;

                offset = (offset >= 0) ? offset : 0;
                res = res.slice(offset, limit);
            }
        }

        return res;
    },

    copyString: function (str) {
        var newStr, charConvert = [], i;

        if (typeof str !== 'string') {
            return str;
        }
        for (i = 0; i < str.length; i++) {
            charConvert[i] = str.charAt(i);
        }
        newStr = charConvert.join("");

        return newStr;
    },

    copy: function (obj) {
        var i,
            newObj = jQuery.isArray(obj) ? [] : {};

        if (typeof obj === 'number' ||
            typeof obj === 'string' ||
            typeof obj === 'boolean' ||
            obj === null ||
            obj === undefined) {
            return obj;
        }

        if (obj instanceof Date) {
            return new Date(obj);
        }

        if (obj instanceof RegExp) {
            return new RegExp(obj);
        }

        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                if (obj.__lookupGetter__(i)) {
                    newObj.__defineGetter__(i, (function (key) {
                        return function () {
                            return self.copy(obj[key]);
                        };
                    }(i)));
                }
                else {
                    newObj[i] = self.copy(obj[i]);
                }
            }
        }

        return newObj;
    }
};

});
define('ripple/platform/tizen/2.0/GeoCircleBounds', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (_center, _radius) {
    var center, radius;
    center = _center || null;
    radius = _radius || 0;

    this.__defineGetter__("center", function () {
        return center;
    });

    this.__defineGetter__("radius", function () {
        return radius;
    });
};

});
define('ripple/platform/tizen/2.0/ContactName', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils');

module.exports = function (prop) {
    var _self, i;
    _self = {
        prefix : "",
        firstName : "",
        middleName : "",
        lastName : "",
        nicknames : [],
        phoneticName : "",
        displayName : null
    };

    if (prop) {
        if (prop.prefix !== null && prop.prefix !== undefined) {
            _self.prefix = String(prop.prefix);
        }
        if (prop.firstName !== null && prop.firstName !== undefined) {
            _self.firstName = String(prop.firstName);
        }
        if (prop.middleName !== null && prop.middleName !== undefined) {
            _self.middleName = String(prop.middleName);
        }
        if (prop.lastName !== null && prop.lastName !== undefined) {
            _self.lastName = String(prop.lastName);
        }
        if (tizen1_utils.isValidArray(prop.nicknames)) {
            for (i = 0; i < prop.nicknames.length; i++) {
                _self.nicknames.push(String(prop.nicknames[i]));
            }
        }
        if (prop.phoneticName !== null && prop.phoneticName !== undefined) {
            _self.phoneticName = String(prop.phoneticName);
        }
        if (prop.displayName !== null && prop.displayName !== undefined) {
            _self.displayName = String(prop.displayName);
        }
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/GeometryFilter', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (criteria, geometry) {
    var _self;

    _self = {
        criteria: criteria,
        geometry: geometry
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/Message', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    msg_utils = require('ripple/platform/tizen/2.0/msg_utils'),
    MessageBody = require('ripple/platform/tizen/2.0/MessageBody'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (type, messageInit) {
    var _id = null, _serviceId = null, _conversationId = null,
        _folderId = null, _type = type, _timestamp = null,
        _from = null, _hasAttachment = false, _messageStatus = null,
        msg = {};

    if (messageInit !== undefined && messageInit !== null) {
        if (msg_utils.setMsg(messageInit, msg) === false) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (messageInit.priv !== undefined) {
            /* secret constructor for PrivateMessage */
            _id = messageInit.priv.id;
            _serviceId = messageInit.priv.serviceId;
            _conversationId = messageInit.priv.conversationId;
            _folderId = messageInit.priv.folderId;
            _type = messageInit.priv.type;
            _timestamp = new Date(messageInit.priv.timestamp);
            _from = messageInit.priv.from;
            _hasAttachment = messageInit.priv.hasAttachment;
            _messageStatus = messageInit.priv.messageStatus;
        }
        msg.body = new MessageBody(_id, msg.body.loaded, msg.body.plainBody, msg.body.htmlBody, []);
    }

    msg.__defineGetter__("id", function () {
        return _id;
    });
    msg.__defineGetter__("serviceId", function () {
        return _serviceId;
    });
    msg.__defineGetter__("conversationId", function () {
        return _conversationId;
    });
    msg.__defineGetter__("folderId", function () {
        return _folderId;
    });
    msg.__defineGetter__("type", function () {
        return _type;
    });
    msg.__defineGetter__("timestamp", function () {
        return _timestamp;
    });
    msg.__defineGetter__("from", function () {
        return _from;
    });
    msg.__defineGetter__("hasAttachment", function () {
        return _hasAttachment;
    });
    msg.__defineGetter__("messageStatus", function () {
        return _messageStatus;
    });
    return msg;
};

});
define('ripple/platform/tizen/2.0/poi', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var OpenMapQuestProvider = require('ripple/platform/tizen/2.0/poiBackend_openmapquest'), // opne.MapQuest.xapi service
    _providers,
    _security = {
        "http://tizen.org/api/poi": [],
        "http://tizen.org/api/poi.read": ["find"],
        "http://tizen.org/api/poi.write": ["add", "remove", "update"],
        all: true
    },
    _self;

function _initialize() {
    _providers = [new OpenMapQuestProvider({name : "MapQuest", connectivity : "ONLINE", metaData : _security})];
}

_self = function () {
    var poi;

    poi = {
        getDefaultProvider : function () {
            return _providers[0];
        },
        getProviders : function () {
            return _providers;
        },
        handleSubFeatures: function (subFeatures) {
            var i, subFeature;
            for (subFeature in subFeatures) {
                if (_security[subFeature].length === 0) {
                    _security.all = true;
                    break;
                }
                _security.all = false;
                for (i = 0; i < _security[subFeature].length; i++) {
                    _security[_security[subFeature][i]] = true;
                }
            }
            _initialize();
        }
    };

    return poi;
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/errorcode', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"),
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _self = {};

_self.__defineGetter__("UNKNOWN_ERR", function () {
    return 0;
});

_self.__defineGetter__("INDEX_SIZE_ERR", function () {
    return 1;
});

_self.__defineGetter__("DOMSTRING_SIZE_ERR", function () {
    return 2;
});

_self.__defineGetter__("HIERARCHY_REQUEST_ERR", function () {
    return 3;
});

_self.__defineGetter__("WRONG_DOCUMENT_ERR", function () {
    return 4;
});

_self.__defineGetter__("INVALID_CHARACTER_ERR", function () {
    return 5;
});

_self.__defineGetter__("NO_DATA_ALLOWED_ERR", function () {
    return 6;
});

_self.__defineGetter__("NO_MODIFICATION_ALLOWED_ERR", function () {
    return 7;
});

_self.__defineGetter__("NOT_FOUND_ERR", function () {
    return 8;
});

_self.__defineGetter__("NOT_SUPPORTED_ERR", function () {
    return 9;
});

_self.__defineGetter__("INUSE_ATTRIBUTE_ERR", function () {
    return 10;
});

_self.__defineGetter__("INVALID_STATE_ERR", function () {
    return 11;
});

_self.__defineGetter__("SYNTAX_ERR", function () {
    return 12;
});

_self.__defineGetter__("INVALID_MODIFICATION_ERR", function () {
    return 13;
});

_self.__defineGetter__("NAMESPACE_ERR", function () {
    return 14;
});

_self.__defineGetter__("INVALID_ACCESS_ERR", function () {
    return 15;
});

_self.__defineGetter__("VALIDATION_ERR", function () {
    return 16;
});

_self.__defineGetter__("TYPE_MISMATCH_ERR", function () {
    return 17;
});

_self.__defineGetter__("SECURITY_ERR", function () {
    return 18;
});

_self.__defineGetter__("NETWORK_ERR", function () {
    return 19;
});

_self.__defineGetter__("ABORT_ERR", function () {
    return 20;
});

_self.__defineGetter__("URL_MISMATCH_ERR", function () {
    return 21;
});

_self.__defineGetter__("QUOTA_EXCEEDED_ERR", function () {
    return 22;
});

_self.__defineGetter__("TIMEOUT_ERR", function () {
    return 23;
});

_self.__defineGetter__("INVALID_NODE_TYPE_ERR", function () {
    return 24;
});

_self.__defineGetter__("DATA_CLONE_ERR", function () {
    return 25;
});

_self.__defineGetter__("INVALID_VALUES_ERR", function () {
    return 99;
});

_self.__defineGetter__("IO_ERR", function () {
    return 100;
});

_self.__defineGetter__("SERVICE_NOT_AVAILABLE_ERR", function () {
    return 111;
});

module.exports = _self;


});
define('ripple/platform/tizen/2.0/nfc', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    _NFC_TAG = "tizen1.0-nfc-tag",
    _NFC_PEER = "tizen1.0-nfc-peer",
    _NFC_OUTPUT_MESSAGE = "tizen1.0-nfc-output-message",
    NFCAdapter, NFCTag, NFCPeer,
    tag,
    peer,
    isPeerConnected = false,
    _data = {
        INTERVAL : 1000,
        listener : {
            onTagDetected : null,
            onPeerDetected : null,
            onNDEFReceived : null
        },
        pairedNFC : null,
        nfcAdapter : {},
        nfcTags : [],
        nfcTag: {},
        nfcPeer : {},
        isNear : false,     // Identify the device is whether near
        isDetectTag : false, // Identify NFC tag is detected
        connectedState : false
    },
    _security = {
        "http://tizen.org/api/nfc": [],
        "http://tizen.org/api/nfc.tag": ["setTagListener", "unsetTagListener", "getCachedMessage", "readNDEF", "writeNDEF", "transceive", "formatNDEF"],
        "http://tizen.org/api/nfc.p2p": ["setPeerListener", "unsetPeerListener", "setReceiveNDEFListener", "unsetReceiveNDEFListener", "sendNDEF"],
        all: true
    },
    _self;


//validate the type match
function _validateCallbackType(onSuccess, onError) {
    if (onSuccess &&
        typeof onSuccess !== "function" &&
        typeof onSuccess !== "object") {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }
    if (onError) {
        tizen1_utils.validateArgumentType(onError, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }
    tizen1_utils.validateArgumentType(onSuccess.onattach, "function",
        new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    tizen1_utils.validateArgumentType(onSuccess.ondetach, "function",
        new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
}

_self = function () {
    function getDefaultAdapter() {
        if (arguments.length > 0)
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (!_data.nfcAdapter)
            throw new WebAPIError(errorcode.UNKNOWN_ERR);

        return _data.nfcAdapter;
    }

    function handleSubFeatures(subFeatures) {
        for (var subFeature in subFeatures) {
            if (_security[subFeature].length === 0) {
                _security.all = true;
                return;
            }
            _security.all = false;
            utils.forEach(_security[subFeature], function (method) {
                _security[method] = true;
            });
        }
    }

    var nfc = {
        getDefaultAdapter: getDefaultAdapter,
        handleSubFeatures: handleSubFeatures
    };

    nfc.__defineGetter__("NFC_RECORD_TNF_EMPTY", function () {
        return 0;
    });

    nfc.__defineGetter__("NFC_RECORD_TNF_WELL_KNOWN", function () {
        return 1;
    });

    nfc.__defineGetter__("NFC_RECORD_TNF_MIME_MEDIA", function () {
        return 2;
    });

    nfc.__defineGetter__("NFC_RECORD_TNF_URI", function () {
        return 3;
    });

    nfc.__defineGetter__("NFC_RECORD_TNF_EXTERNAL_RTD", function () {
        return 4;
    });

    nfc.__defineGetter__("NFC_RECORD_TNF_UNKNOWN", function () {
        return 5;
    });

    nfc.__defineGetter__("NFC_RECORD_TNF_UNCHANGED", function () {
        return 6;
    });

    return nfc;
};


NFCAdapter = function () {
    var nfcAdapter,
        interval,
        powered = false, // Identify the device on or off
        polling = false; // Identify the device is polled
        
    event.trigger("nfc-power-changed", [powered]);
    event.trigger("nfc-polling-changed", [polling]);
    event.on("nfc-power-setting", function (status) {
        _updatePowerStatus(status);   
    });
    event.on("nfc-polling-setting", function (status) {
        _updatePollingStatus(status);   
    });
    event.on("nfc-attach-setting", function (type, isAttached) {
        var isDetectTag;
        isDetectTag = type === "Tag" ? true : false;
        _updateIsNear(isDetectTag, isAttached);
    });
    event.on("nfc-tag-send", function (status) {
        if (status) {
            tag = db.retrieveObject(_NFC_TAG);
            if (tag.isSupportedNDEF) {
                _data.nfcTag = new NFCTag(tag.type, tag.isSupportedNDEF, tag.ndefSize, null, true, tag.ndefs);
            } else {
                _data.nfcTag = new NFCTag(tag.type, tag.isSupportedNDEF, tag.ndefSize, null, true, tag.rawData);
            }
            if (_data.listener.onTagDetected) {
                _data.listener.onTagDetected.onattach(_data.nfcTag);
            }
        } else {
            tag = {};
            if (_data.listener.onTagDetected) {
                _data.listener.onTagDetected.ondetach();
            }
        }
    });
    event.on("nfc-peer-send", function (status) {
        if (status) {
            _data.nfcPeer = new NFCPeer(true);
            if (_data.listener.onPeerDetected) {
                _data.listener.onPeerDetected.onattach(_data.nfcPeer);
            }
            isPeerConnected = true;
        } else {
            if (_data.listener.onPeerDetected) {
                _data.listener.onPeerDetected.ondetach();
            }
            isPeerConnected = false;
        }
    });
    event.on("nfc-peer-sending-ndef", function () {
        if (isPeerConnected) {
            peer = db.retrieveObject(_NFC_PEER);
            if (_data.listener.onNDEFReceived) {
                _data.listener.onNDEFReceived(peer.ndef);
            }
        }
    });

    // private
    function _updatePowerStatus(status) {
        if (powered === status) {
            return;
        }
        if (!status) {
            _updatePollingStatus(false);
            _updateIsNear(_data.isDetectTag, false);
            _data.listener.onTagDetected = null;
            _data.listener.onPeerDetected = null;
            _data.listener.onNDEFReceived = null;
        }
        powered = status;
        event.trigger("nfc-power-changed", [powered]);
    }
    function _updatePollingStatus(status) {
        if (!powered)
            return;
        if (polling === status) {
            return;
        }
        polling = status;
        event.trigger("nfc-polling-changed", [polling]);
        if (polling) {
            interval = setInterval(poll, _data.INTERVAL);
        } else {
            clearInterval(interval);
        }
    }
    function _updateIsNear(isDetectTag, isAttached) {
        _data.isDetectTag = isDetectTag;
        _data.isNear = isAttached;
        if (!_data.isNear) {
            _data.connectedState = false;
            event.trigger("nfc-connectedState-changed", [false]);
        }
    }
    function poll() {
        if (!_data.isNear) {
            return;
        }
        if (!_data.connectedState) {
            _data.connectedState = true;
            event.trigger("nfc-connectedState-changed", [true]);

        }
    }

    // public
    // Turns NFC adapter on or off.
    function setPowered(state, successCallback, errorCallback) {
        tizen1_utils.validateArgumentType(state, "boolean",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        _updatePowerStatus(state);
        successCallback(powered);
    }

    // Starts/stops polling for targets.
    function setPolling(state, successCallback, errorCallback) {
        tizen1_utils.validateArgumentType(state, "boolean",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        _updatePollingStatus(state);
        successCallback(polling);
    }

    // Registers a callback function to invoke when NFC tag is detected.
    function setTagListener(detectCallback, errorCallback, tagFilter) {

        if (!_security.all && !_security.setTagListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        _validateCallbackType(detectCallback, errorCallback);

        if (tagFilter) {
            tizen1_utils.validateArgumentType(tagFilter, "array",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (!powered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
            return;
        }
        _data.listener.onTagDetected = detectCallback;
    }

    // Registers a callback function to be invoked when NFC peer-to-peer target is detected.
    function setPeerListener(detectCallback, errorCallback) {
        if (!_security.all && !_security.setPeerListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        _validateCallbackType(detectCallback, errorCallback);

        if (!polling) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
            return;
        }
        _data.listener.onPeerDetected = detectCallback;
    }

    // Unregisters the listener for detecting an NFC tag.
    function unsetTagListener() {
        if (!_security.all && !_security.unsetTagListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if (!polling || !_data.listener.onTagDetected)
            return;

        _data.listener.onTagDetected = null;
    }

    // Unregisters the listener for detecting an NFC peer-to-peer target.
    function unsetPeerListener() {
        if (!_security.all && !_security.unsetPeerListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if (!polling || !_data.listener.onPeerDetected)
            return;

        _data.listener.onPeerDetected = null;
    }

    // Gets NDEF message cached when the tag is detected.
    function getCachedMessage() {
        if (!_security.all && !_security.getCachedMessage)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        return _data.pairedNFC || {
            recordCount : 0,
            records : [],
            toByte : function () {
                var result = [], i;
                for (i in this.records) {
                    result = result.concat(this.records[i].payload);
                }
                return result;
            }
        };
    }

    nfcAdapter = {
        setPowered : setPowered,
        setPolling : setPolling,
        setTagListener : setTagListener,
        setPeerListener : setPeerListener,
        unsetTagListener : unsetTagListener,
        unsetPeerListener : unsetPeerListener,
        getCachedMessage : getCachedMessage
    };

    nfcAdapter.__defineGetter__("powered", function () {
        return powered;
    });

    nfcAdapter.__defineGetter__("polling", function () {
        return polling;
    });

    return nfcAdapter;
};

NFCTag = function (type, isSupportedNDEF, ndefSize, properties, isConnected, ndefs) {
    var nfcTag,
        _ndefs,
        _ndefs_index = 0;
        
    type = type || null;
    isSupportedNDEF = isSupportedNDEF || false;
    ndefSize = ndefSize || 1;
    properties = null;
    isConnected = isConnected || false;
    _ndefs = ndefs || [];

    // Reads NDEF data.
    function readNDEF(readCallback, errorCallback) {
        function _readNDEF() {
            if (!isConnected || !isSupportedNDEF) {
                if (errorCallback) {
                    errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
                }
                return;
            }
            if (_ndefs_index >= ndefSize) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            } else {
                readCallback(_ndefs[_ndefs_index]);
                _ndefs_index++;
            }
        }

        if (!_security.all && !_security.readNDEF)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        tizen1_utils.validateTypeMismatch(readCallback, errorCallback, "nfc:readNDEF", _readNDEF);
    }

    // Writes NDEF data.
    function writeNDEF(ndefMessage, successCallback, errorCallback) {
        if (!_security.all && !_security.writeNDEF)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        tizen1_utils.validateArgumentType(ndefMessage, "object",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        if (!isConnected || !isSupportedNDEF) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
            return;
        }
        db.saveObject(_NFC_OUTPUT_MESSAGE, ndefMessage);
        event.trigger("nfc-output-msg", []);
        if (successCallback) {
            successCallback();
        }
    }

    // Access the raw format card.
    function transceive(data, dataCallback, errorCallback) {
        function _transceive() {
            if (!tizen1_utils.isValidArray(data))
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

            if (!isConnected || isSupportedNDEF) {
                if (errorCallback) {
                    errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
                }
                return;
            }
            db.saveObject(_NFC_OUTPUT_MESSAGE, data);
            event.trigger("nfc-output-msg", []);
            dataCallback(_ndefs);
        }

        if (!_security.all && !_security.transceive)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        tizen1_utils.validateTypeMismatch(dataCallback, errorCallback, "nfc:transceive", _transceive);
    }

    // Formats the detected tag that can store NDEF messages.
    function formatNDEF(successCallback, errorCallback, key) {
        if (!_security.all && !_security.formatNDEF)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (key) {
            tizen1_utils.validateArgumentType(key, "array",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (!isConnected || !isSupportedNDEF) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
            return;
        }

        successCallback();
    }

    nfcTag = {
        readNDEF : readNDEF,
        writeNDEF : writeNDEF,
        transceive : transceive,
        formatNDEF : formatNDEF
    };

    nfcTag.__defineGetter__("type", function () {
        return type;
    });

    nfcTag.__defineGetter__("isSupportedNDEF", function () {
        return isSupportedNDEF;
    });

    nfcTag.__defineGetter__("ndefSize", function () {
        return ndefSize;
    });

    nfcTag.__defineGetter__("properties", function () {
        return properties;
    });

    nfcTag.__defineGetter__("isConnected", function () {
        return isConnected;
    });

    return nfcTag;
};

NFCPeer = function (isConnected) {
    var nfcPeer;

    isConnected = isConnected || false;

    // Registers a callback function to be invoked when NDEF message is received from NFC peer-to-peer target connected.
    function setReceiveNDEFListener(successCallback, errorCallback) {
        function _setReceiveNDEFListener() {
            if (!isConnected) {
                if (errorCallback) {
                    errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
                }
                return;
            }
            _data.listener.onNDEFReceived = successCallback;
        }

        if (!_security.all && !_security.setReceiveNDEFListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "nfc:setReceiveNDEFListener", _setReceiveNDEFListener);
    }

    // Unregisters the listener for receiving NDEFMessage from NFC peer-to-peer target connected.
    function unsetReceiveNDEFListener() {
        if (!_security.all && !_security.unsetReceiveNDEFListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        _data.listener.onNDEFReceived = null;
    }

    // Sends data to NFC peer-to-peer target.
    function sendNDEF(ndefMessage, successCallback, errorCallback) {
        if (!_security.all && !_security.sendNDEF)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        tizen1_utils.validateArgumentType(ndefMessage, "object",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        if (!isConnected) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
            return;
        }

        db.saveObject(_NFC_OUTPUT_MESSAGE, ndefMessage);
        event.trigger("nfc-output-msg", []);
        if (successCallback) {
            successCallback();
        }
    }

    nfcPeer = {
        setReceiveNDEFListener : setReceiveNDEFListener,
        unsetReceiveNDEFListener : unsetReceiveNDEFListener,
        sendNDEF : sendNDEF
    };

    nfcPeer.__defineGetter__("isConnected", function () {
        return isConnected;
    });

    return nfcPeer;
};

function _initialize() {
    _data.nfcAdapter = new NFCAdapter();
}
_initialize();

module.exports = _self;


});
define('ripple/platform/tizen/2.0/NotificationBase', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (_title) {
    var id = Math.uuid(null, 16),
        type = "STATUS",
        postedTime,
        title = _title,
        content,
        _self = {};

    _self.__defineGetter__("id", function () {
        return id;
    });
    _self.__defineGetter__("type", function () {
        return type;
    });
    _self.__defineGetter__("postedTime", function () {
        return postedTime;
    });
    _self.__defineGetter__("title", function () {
        return title;
    });
    _self.__defineSetter__("title", function (_title) {
        title = _title;
    });
    _self.__defineGetter__("content", function () {
        return content;
    });
    _self.__defineSetter__("content", function (_content) {
        content = _content;
    });

    return _self;
};
});
define('ripple/platform/tizen/2.0/AccountBase', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (appId, userName, displayName, service) {
    var _self,
        _id = Math.uuid(null, 16);

    _self = {
        appId : appId || "",
        userName : userName || "",
        displayName : displayName || "",
        service : service || {}
    };

    _self.__defineGetter__("id", function () {
        return _id;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/navigator', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _original = window.navigator,
    utils = require('ripple/utils'),
    devices = require('ripple/devices'),
    constants = require('ripple/constants'),
    vibration = require('ripple/platform/tizen/2.0/vibration'),
    _self = {};

(function () {
    var key,
        nav = window.navigator;

    function _handle(obj, key) {
        return typeof obj[key] !== "function" ? obj[key] : function () {
            return obj[key].apply(obj, Array.prototype.slice.call(arguments));
        };
    }

    for (key in nav) {
        _self[key] = _handle(nav, key);
    }
}());

_self.__defineGetter__('userAgent', function () {
    var currentUserAgent = devices.getCurrentDevice().userAgent;

    return currentUserAgent === constants.COMMON.USER_AGENT_DEFAULT ?
        _original.userAgent : currentUserAgent;
});

_self.__defineGetter__('vibrate', function () {
    return vibration.vibrate;
});

module.exports = _self;

});
define('ripple/platform/tizen/2.0/call', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    db = require('ripple/db'),
    event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    _history,
    _currentServiceIndex = 0,
    _data = {
        DB_CALL_KEY: "tizen1-db-call",
        isCallInProgress: false,
        observers: {},
        callServices: [],
        callHistory: []
    },
    _security = {
        "http://tizen.org/api/call": [],
        "http://tizen.org/api/call.simple": ["getCallServices", "isCallInProgress"],
        "http://tizen.org/api/call.history": ["history"],
        "http://tizen.org/api/call.history.read": ["find", "addListener", "removeListener"],
        "http://tizen.org/api/call.history.write": ["CallHistoryEntry", "remove", "removeBatch", "removeAll"],
        all: true
    },
    CALL_SERVICE_TYPE = ["tizen.tel", "tizen.xmpp", "tizen.sip"],
    CALL_SERVICE_TAG = ["call", "call.voice", "call.video", "call.emergency"],
    _RECORDING_KEY = "tizen1-call-recording",
    _RECORDING_PATH = "music/",
    _self;

function _getValue(inputValue, key) {
    var keys = key.split("."),
        value = inputValue[keys[0]],
        index;

    for (index = 1; index < keys.length; index++) {
        if (value[keys[index]]) {
            value = value[keys[index]];
        }
    }

    return value;
}

function _filter(inputArray, filter) {
    var index, filterResults = [], compositeResultArray;

    if (filter === null || filter === undefined) {
        return inputArray;
    }

    if (filter.attributeName === null || filter.attributeName === undefined) {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }

    if (filter.matchFlag) {
        filterResults = tizen1_utils.matchAttributeFilter(inputArray, filter.attributeName, filter.matchFlag, filter.matchValue);
    }
    else if (filter.initialValue || filter.endValue) {
        filterResults = tizen1_utils.matchAttributeRangeFilter(inputArray, filter.attributeName, filter.initialValue, filter.endValue);
    }
    else if (filter.type && filter.filters) {
        for (index = 0; index < filter.filters.length; index++) {
            compositeResultArray = _filter(inputArray, filter.filters[index]);

            filterResults = tizen1_utils.arrayComposite(filter.type, filterResults, compositeResultArray);
        }
    }

    return filterResults;
}

function _sort(inputArray, sortMode) {
    if (sortMode.attributeName === null || sortMode.attributeName === undefined) {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }

    inputArray.sort(function (a, b) {
        return sortMode.order === "DESC" ? _getValue(a, sortMode.attributeName) - _getValue(b, sortMode.attributeName) :
               _getValue(b, sortMode.attributeName) - _getValue(a, sortMode.attributeName);
    });

    return inputArray;
}

function _save() {
    db.saveObject(_data.DB_CALL_KEY, _data.callHistory);
}

function _retrive() {
    var callHistoryList, callHistory, index;
    
    if (_data.callHistory.length === 0) {
        callHistoryList = db.retrieveObject(_data.DB_CALL_KEY) || [];

        for (index = 0; index < callHistoryList.length; index++) {
            callHistory = callHistoryList[index];
            _data.callHistory.push(_getCallHistoryEntry(callHistory.serviceId, callHistory.callType, callHistory.tags,
                                       callHistory.callParticipants, callHistory.forwardedFrom, 
                                       callHistory.startTime, callHistory.duration, callHistory.endReason,
                                       callHistory.direction, callHistory.recording, callHistory.cost, callHistory.currency));
        }
    }

    return tizen1_utils.copy(_data.callHistory);
}

function _deleteRecording(id) {
    var path = _RECORDING_PATH + id + ".mp3",
        recording = [];

    recording = db.retriveObject(_RECORDING_KEY);
    recording = recording.filter(function (element) {
        return element !== path;
    });
    
    db.saveObject(_RECORDING_KEY, recording);
}

function _isCallHistoryEntryType(arg) {
    return arg && arg.hasOwnProperty("serviceId") && arg.hasOwnProperty("callType") &&
           arg.hasOwnProperty("tags") && arg.hasOwnProperty("callParticipants") && 
           arg.hasOwnProperty("forwardedFrom") && arg.hasOwnProperty("startTime") &&
           arg.hasOwnProperty("duration") && arg.hasOwnProperty("endReason") &&
           arg.hasOwnProperty("direction") && arg.hasOwnProperty("recording") && 
           arg.hasOwnProperty("cost") && arg.hasOwnProperty("currency");
}

function _isCallServiceFilterType(arg) {
    if (arg && arg.hasOwnProperty("serviceTypeId") && !utils.arrayContains(CALL_SERVICE_TYPE, arg["serviceTypeId"])) {
        return false;
    }

    if (arg && arg.hasOwnProperty("tags")) {
        if (!tizen1_utils.isValidArray(arg["tags"])) {
            return false;
        }
        else if (arg["tags"].some(function (element) {
            return !utils.arrayContains(CALL_SERVICE_TAG, element);
        })) {
            return false;
        }
    }

    return true;
}

function _getRemoteParty(remoteParty, displayName, contactRef) {
    var _contactRef = tizen1_utils.copy(contactRef),
        _self = {};

    _self.__defineGetter__("remoteParty", function () {
        return remoteParty;
    });

    _self.__defineGetter__("displayName", function () {
        return displayName;
    });

    _self.__defineGetter__("contactRef", function () {
        return _contactRef;
    });

    return _self;
}

function _getCallHistoryEntry(serviceId, callType, tags, callParticipants,
                              forwardedFrom, startTime, duration, endReason,
                              direction, recording, cost, currency) {
    var _tags = tizen1_utils.copy(tags),
        _callParticipants = [],
        _forwardedFrom = forwardedFrom ? _getRemoteParty(forwardedFrom.remoteParty, forwardedFrom.displayName, forwardedFrom.contactRef) : {},
        _startTime = new Date(startTime),
        _recording = tizen1_utils.copy(recording),
        _self = {},
        participantItem,
        index;

    for (index = 0; index < callParticipants.length; index++) {
        participantItem = callParticipants[index];
        _callParticipants.push(_getRemoteParty(participantItem.id, participantItem.displayName, participantItem.contactRef));
    }

    _self.__defineGetter__("serviceId", function () {
        return serviceId;
    });

    _self.__defineGetter__("callType", function () {
        return callType;
    });

    _self.__defineGetter__("tags", function () {
        return _tags;
    });

    _self.__defineGetter__("callParticipants", function () {
        return _callParticipants;
    });

    _self.__defineGetter__("forwardedFrom", function () {
        return _forwardedFrom;
    });

    _self.__defineGetter__("startTime", function () {
        return _startTime;
    });

    _self.__defineGetter__("duration", function () {
        return duration;
    });

    _self.__defineGetter__("endReason", function () {
        return endReason;
    });

    _self.direction = direction;

    _self.__defineGetter__("recording", function () {
        return _recording;
    });

    _self.__defineGetter__("cost", function () {
        return cost;
    });

    _self.currency = currency;

    return _self;
}

function AccountServiceClass(serviceName, serviceTypeId, providerId, tags) {
    var _self = {
        serviceName: serviceName,
        serviceTypeId: serviceTypeId,
        providerId: providerId,
        tags: tags
    };

    this.__defineGetter__("serviceName", function () {
        return _self.serviceName;
    });
    this.__defineGetter__("serviceTypeId", function () {
        return _self.serviceTypeId;
    });
    this.__defineGetter__("providerId", function () {
        return _self.providerId;
    });
    this.__defineGetter__("tags", function () {
        return _self.tags;
    });

    this.applicationId = "";
    this.displayName = "";
    this.icon = "";
    this.enabled = false;
    this.settings = "";
}

function AccountService() {
    var _self = {
        id: "",
        accountId: ""
    };

    if (arguments.length >= 4) {
        AccountServiceClass.call(this, arguments[0], arguments[1], arguments[2], arguments[3]);
    }
    else {
        AccountServiceClass.call(this);
    }

    this.__defineGetter__("id", function () {
        return _self.id;
    });
    this.__defineGetter__("accountId", function () {
        return _self.accountId;
    });
}

function CallService() {
    if (arguments.length >= 4) {
        AccountService.call(this, arguments[0], arguments[1], arguments[2], arguments[3]);
    }
    else {
        AccountService.call(this);
    }

    this.launchDialer = function (remoteParty, successCallback, errorCallback, extension) {
        if (remoteParty === null || remoteParty === undefined) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }

        if ((successCallback && typeof successCallback !== "function") || 
            (errorCallback && typeof errorCallback !== "function")) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        // The ui pannel will respnd this event and launch the dailer panel
        event.trigger("DialerLaunched", [remoteParty]);
    };

    this.__defineGetter__("voicemailNumbers", function () {
        return "13800100200";
    });
}

function CellularCallService() {
    var subscriberNumbers = ["10086"],
        emergencyNumbers = ["110", "911", "120"];

    if (arguments.length >= 4) {
        CallService.call(this, arguments[0], arguments[1], arguments[2], arguments[3]);
    }
    else {
        CallService.call(this);
    }

    this.sendUSSD = function (command, successCallback, errorCallback) {
        var response = "";
    
        if (command === null || command === undefined) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }

        if ((successCallback && typeof successCallback !== "function") ||
            (errorCallback && typeof errorCallback !== "function")) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        if (command === "*#06#") {
            response = "352099001761482";
        }
        else {
            response = "simulated USSD response";
        }

        setTimeout(successCallback(response), 1);
    };    

    this.__defineGetter__("subscriberNumbers", function () {
        return subscriberNumbers;
    });

    this.__defineGetter__("emergencyNumbers", function () {
        return emergencyNumbers;
    });
}

function CallHistory() {
    this.find = function (successCallback, errorCallback, filter, sortMode, limit, offset) {
        var callHistory = _retrive(),
            filterResults = callHistory,
            limitValue = limit | 0,
            offsetValue = offset | 0;

            if (!_security.all && !_security.history && !_security.find) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (successCallback === null || successCallback === undefined) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            if (typeof successCallback !== "function" || (errorCallback && typeof errorCallback !== "function")) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

        setTimeout(function () {
            if (filter) {
                filterResults = _filter(callHistory, filter);
            }
            
            if (sortMode) {
                _sort(filterResults, sortMode);
            }

            if (limitValue > 0) {
                offsetValue = offsetValue > 0 ? offsetValue : 0;
                filterResults = filterResults.slice(offsetValue, limitValue);
            }

            successCallback(filterResults);
        }, 1);
    };
    this.remove = function (entry) {
        var isFound = false;

        if (!_security.all && !_security.history && !_security.remove) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (!_isCallHistoryEntryType(entry)) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _data.callHistory = _data.callHistory.filter(function (element) {
            return utils.some(element, function (value, key) {
                if (tizen1_utils.isEqual(entry[key], value)) {
                    isFound = true;
                    return false;
                }
                return true;
            });
        });

        if (!isFound) {
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);
        }

        _save();
    };
    this.removeBatch = function (entries, successCallback, errorCallback) {
        var isFound = false, index;

        if (!_security.all && !_security.history && !_security.removeBatch) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if ((successCallback && typeof successCallback !== "function") ||
            (errorCallback && typeof errorCallback !== "function")) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        for (index = 0; index < entries.length; index++) {
            if (!_isCallHistoryEntryType(entries[index])) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
        }

        setTimeout(function () {
            isFound = entries.every(function (element) {
                return _data.callHistory.some(function (callHistory) {
                    return tizen1_utils.isEqual(element, callHistory);
                });
            });

            if (!isFound) {
                if (errorCallback) {
                    errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                    return;
                }
                else {
                    throw new WebAPIError(errorcode.NOT_FOUND_ERR);
                }
            }

            _data.callHistory = _data.callHistory.filter(function (element) {
                return !entries.some(function (entryValue, entryIndex) {
                    return tizen1_utils.isEqual(element, entryValue);
                });
            });
        
            _save();

            if (successCallback) {
                successCallback(_retrive());
            }
        }, 1);
    };
    this.removeAll = function (successCallback, errorCallback) {
        var removedEntries = [];

        if (!_security.all && !_security.history && !_security.removeAll) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if ((successCallback && typeof successCallback !== "function") ||
            (errorCallback && typeof errorCallback !== "function")) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        removedEntries = _retrive();
        _data.callHistory = [];
        _save();

        if (successCallback) {
            successCallback(removedEntries);
        }
    };
    this.deleteRecording = function (historyEntry, successCallback, errorCallback) {
        var isFound = false;

        if (!_security.all && !_security.history && !_security.deleteRecording) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if ((successCallback && typeof successCallback !== "function") ||
            (errorCallback && typeof errorCallback !== "function")) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        if (!_isCallHistoryEntryType(historyEntry) || historyEntry["recording"] === null) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        isFound = _data.callHistory.some(function (callHistory, index) {
            if (tizen1_utils.isEqual(historyEntry, callHistory)) {
                _data.callHistory[index]["recording"] = null;
                return true;
            }
            return false;
        });

        if (!isFound) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                return;
            }
            else {
                throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }
        }

        _deleteRecording(historyEntry.serviceId);
        _save();

        if (successCallback) {
            successCallback(_retrive());
        }

        utils.forEach(_data.observers, function (observer) {
            observer.onchanged(historyEntry);
        });
    };
    this.addListener = function (observerObj) {
        var handle = Math.uuid(null, 16);

        if (!_security.all && !_security.history && !_security.addListener) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if ((observerObj === null || observerObj === undefined) || !observerObj.hasOwnProperty("onadded") ||
            !observerObj.hasOwnProperty("onchanged")) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        if (typeof observerObj.onadded !== "function" || typeof observerObj.onchanged !== "function") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _data.observers[handle] = observerObj;

        return handle;
    };
    this.removeListener = function (handle) {
        if (!_security.all && !_security.history && !_security.removeListener) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (_data.observers[handle]) {
            delete _data.observers[handle];
        }
        else {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }
    };
}

function _initialize() {
    _data.callServices.push(new CallService("TelVoice1", "tizen.tel", "VTMobile", ["call.voice", "call.video"]));
    _data.callServices.push(new CallService("TelEmergency1", "tizen.xmpp", "VTUnicom", ["call.voice", "call.emergency"]));
    _data.callServices.push(new CallService("Telephone1", "tizen.sip", "VTComm", ["call"]));

    _history = new CallHistory();
    _retrive();

    event.on("CallInProgress", function (isInProgress) {
        _data.isCallInProgress = isInProgress;
    });

    event.on("CallRecorded", function (record) {
        var callService = _data.callServices[_currentServiceIndex],
            historyEntry = _getCallHistoryEntry(record.serviceId, callService.serviceTypeId, callService.tags,
                               record.callParticipants, record.forwardedFrom, record.startTime, record.duration, 
                               record.endReason, record.direction, record.recording, 0, null);

        _data.callHistory.push(historyEntry);
        _save();

        utils.forEach(_data.observers, function (observer) {
            observer.onadded([historyEntry]);
        });
    });
}

_self = {
    history: undefined,
    isCallInProgress: function () {
        if (!_security.all && !_security.isCallInProgress) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        return _data.isCallInProgress;
    },
    getCallServices: function (filter) {
        if (!_security.all && !_security.getCallServices) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (!_isCallServiceFilterType(filter)) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _data.callServices = _data.callServices.filter(function (element) {
            var flag = true;
            utils.forEach(filter, function (value, key) {
                if (!tizen1_utils.isEqual(element[key], value)) {
                    flag = false;
                }
            });

            return flag;
        });

        return _data.callServices;
    },
    handleSubFeatures: function (subFeatures) {
        function setSecurity(_security) {
            return function (method) {
                _security[method] = true;
            };
        }

        for (var subFeature in subFeatures) {
            if (_security[subFeature].length === 0) {
                _security.all = true;
                return;
            }
            _security.all = false;
            utils.forEach(_security[subFeature], setSecurity);
        }
    }
};

_self.__defineGetter__("history", function () {
    return _history;
});

_initialize();

module.exports = _self;

});
define('ripple/platform/tizen/2.0/AttributeFilter', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (_attributeName, _matchFlag, _matchValue) {
    return {
        attributeName: _attributeName,
        matchFlag: _matchFlag,
        matchValue: _matchValue
    };
};

});
define('ripple/platform/tizen/2.0/BluetoothClassDeviceMinor', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function () {
    var _self = {};

    _self.__defineGetter__("COMPUTER_UNCATEGORIZED", function () {
        return 0x00;
    });
    _self.__defineGetter__("COMPUTER_DESKTOP", function () {
        return 0x01;
    });
    _self.__defineGetter__("COMPUTER_SERVER", function () {
        return 0x02;
    });
    _self.__defineGetter__("COMPUTER_LAPTOP", function () {
        return 0x03;
    });
    _self.__defineGetter__("COMPUTER_HANDHELD_PC_OR_PDA", function () {
        return 0x04;
    });
    _self.__defineGetter__("COMPUTER_PALM_PC_OR_PDA", function () {
        return 0x05;
    });
    _self.__defineGetter__("COMPUTER_WEARABLE", function () {
        return 0x06;
    });

    _self.__defineGetter__("PHONE_UNCATEGORIZED", function () {
        return 0x00;
    });
    _self.__defineGetter__("PHONE_CELLULAR", function () {
        return 0x01;
    });
    _self.__defineGetter__("PHONE_CORDLESS", function () {
        return 0x02;
    });
    _self.__defineGetter__("PHONE_SMARTPHONE", function () {
        return 0x03;
    });
    _self.__defineGetter__("PHONE_MODEM_OR_GATEWAY", function () {
        return 0x04;
    });
    _self.__defineGetter__("PHONE_ISDN", function () {
        return 0x05;
    });

    _self.__defineGetter__("AV_UNRECOGNIZED", function () {
        return 0x00;
    });
    _self.__defineGetter__("AV_WEARABLE_HEADSET", function () {
        return 0x01;
    });
    _self.__defineGetter__("AV_HANDSFREE", function () {
        return 0x02;
    });
    _self.__defineGetter__("AV_MICROPHONE", function () {
        return 0x04;
    });
    _self.__defineGetter__("AV_LOUDSPEAKER", function () {
        return 0x05;
    });
    _self.__defineGetter__("AV_HEADPHONES", function () {
        return 0x06;
    });
    _self.__defineGetter__("AV_PORTABLE_AUDIO", function () {
        return 0x07;
    });
    _self.__defineGetter__("AV_CAR_AUDIO", function () {
        return 0x08;
    });
    _self.__defineGetter__("AV_SETTOP_BOX", function () {
        return 0x09;
    });
    _self.__defineGetter__("AV_HIFI", function () {
        return 0x0a;
    });
    _self.__defineGetter__("AV_VCR", function () {
        return 0x0b;
    });
    _self.__defineGetter__("AV_VIDEO_CAMERA", function () {
        return 0x0c;
    });
    _self.__defineGetter__("AV_CAMCORDER", function () {
        return 0x0d;
    });
    _self.__defineGetter__("AV_MONITOR", function () {
        return 0x0e;
    });
    _self.__defineGetter__("AV_DISPLAY_AND_LOUDSPEAKER", function () {
        return 0x0f;
    });
    _self.__defineGetter__("AV_VIDEO_CONFERENCING", function () {
        return 0x10;
    });
    _self.__defineGetter__("AV_GAMING_TOY", function () {
        return 0x12;
    });

    _self.__defineGetter__("PERIPHERAL_UNCATEGORIZED", function () {
        return 0;
    });
    _self.__defineGetter__("PERIPHERAL_KEYBOARD", function () {
        return 0x10;
    });
    _self.__defineGetter__("PERIPHERAL_POINTING_DEVICE", function () {
        return 0x20;
    });
    _self.__defineGetter__("PERIPHERAL_KEYBOARD_AND_POINTING_DEVICE", function () {
        return 0x30;
    });
    _self.__defineGetter__("PERIPHERAL_JOYSTICK", function () {
        return 0x01;
    });
    _self.__defineGetter__("PERIPHERAL_GAMEPAD", function () {
        return 0x02;
    });
    _self.__defineGetter__("PERIPHERAL_REMOTE_CONTROL", function () {
        return 0x03;
    });
    _self.__defineGetter__("PERIPHERAL_SENSING_DEVICE", function () {
        return 0x04;
    });
    _self.__defineGetter__("PERIPHERAL_DEGITIZER_TABLET", function () {
        return 0x05;
    });
    _self.__defineGetter__("PERIPHERAL_CARD_READER", function () {
        return 0x06;
    });
    _self.__defineGetter__("PERIPHERAL_DIGITAL_PEN", function () {
        return 0x07;
    });
    _self.__defineGetter__("PERIPHERAL_HANDHELD_SCANNER", function () {
        return 0x08;
    });
    _self.__defineGetter__("PERIPHERAL_HANDHELD_INPUT_DEVICE", function () {
        return 0x09;
    });

    _self.__defineGetter__("IMAGING_UNCATEGORIZED", function () {
        return 0x00;
    });
    _self.__defineGetter__("IMAGING_DISPLAY", function () {
        return 0x04;
    });
    _self.__defineGetter__("IMAGING_CAMERA", function () {
        return 0x08;
    });
    _self.__defineGetter__("IMAGING_SCANNER", function () {
        return 0x10;
    });
    _self.__defineGetter__("IMAGING_PRINTER", function () {
        return 0x20;
    });

    _self.__defineGetter__("WEARABLE_WRITST_WATCH", function () {
        return 0x01;
    });
    _self.__defineGetter__("WEARABLE_PAGER", function () {
        return 0x02;
    });
    _self.__defineGetter__("WEARABLE_JACKET", function () {
        return 0x03;
    });
    _self.__defineGetter__("WEARABLE_HELMET", function () {
        return 0x04;
    });
    _self.__defineGetter__("WEARABLE_GLASSES", function () {
        return 0x05;
    });

    _self.__defineGetter__("TOY_ROBOT", function () {
        return 0x01;
    });
    _self.__defineGetter__("TOY_VEHICLE", function () {
        return 0x02;
    });
    _self.__defineGetter__("TOY_DOLL", function () {
        return 0x03;
    });
    _self.__defineGetter__("TOY_CONTROLLER", function () {
        return 0x04;
    });
    _self.__defineGetter__("TOY_GAME", function () {
        return 0x05;
    });

    _self.__defineGetter__("HEALTH_UNDEFINED", function () {
        return 0x00;
    });
    _self.__defineGetter__("HEALTH_BLOOD_PRESSURE_MONITOR", function () {
        return 0x01;
    });
    _self.__defineGetter__("HEALTH_THERMOMETER", function () {
        return 0x02;
    });
    _self.__defineGetter__("HEALTH_WEIGHING_SCALE", function () {
        return 0x03;
    });
    _self.__defineGetter__("HEALTH_GLUCOSE_METER", function () {
        return 0x04;
    });
    _self.__defineGetter__("HEALTH_PULSE_OXIMETER", function () {
        return 0x05;
    });
    _self.__defineGetter__("HEALTH_PULSE_RATE_MONITOR", function () {
        return 0x06;
    });
    _self.__defineGetter__("HEALTH_DATA_DISPLAY", function () {
        return 0x07;
    });
    _self.__defineGetter__("HEALTH_STEP_COUNTER", function () {
        return 0x08;
    });
    _self.__defineGetter__("HEALTH_BODY_COMPOSITION_ANALYZER", function () {
        return 0x09;
    });
    _self.__defineGetter__("HEALTH_PEAK_FLOW_MONITOR", function () {
        return 0x0a;
    });
    _self.__defineGetter__("HEALTH_MEDICATION_MONITOR", function () {
        return 0x0b;
    });
    _self.__defineGetter__("HEALTH_KNEE_PROSTHESIS", function () {
        return 0x0c;
    });
    _self.__defineGetter__("HEALTH_ANKLE_PROSTHESIS", function () {
        return 0x0d;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/ContactEmailAddress', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils');

module.exports = function (email, types) {
    var _self, _email = "", i,
        _types = [], type;
    
    if (email) {
        _email = String(email);
    }
    if (tizen1_utils.isValidArray(types)) {
        for (i = 0; i < types.length; i++) {
            type = String(types[i]).toUpperCase();
            _types.push(type);
        }
    }

    _self = {
        email : _email,
        types : _types
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/account', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    _data = {
        DB_ACCOUNT_KEY : "tizen1-db-accounts",
        accounts : {}
    },
    _self;

function _checkAccount(account) {
    if (typeof account !== "object" ||
        typeof account.id !== "string" ||
        typeof account.appid !== "string" ||
        typeof account.userName !== "string" ||
        typeof account.displayName !== "string" ||
        typeof account.service !== "object") {
        return false;
    }

    return true;
}

function _checkCallback(successCallback, errorCallback) {
    tizen1_utils.validateArgumentType(successCallback, "function",
                                        new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    if (errorCallback) {
        tizen1_utils.validateArgumentType(errorCallback, "function",
                                            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }
}

_self = {
    getAccounts : function () {
        var results = [];
        utils.forEach(_data.accounts, function (account) {
            results.push(utils.copy(account)); 
        });

        return results;
    },

    getAccountById : function (id) {
        var acccount = null;

        if (typeof id !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        if (_data.accounts[id]) {
            account = utils.copy(_data.accounts[id]);
        }

        return account;
    },

    getAccountByUserName : function (userName) {
        var result = null;

        if (typeof userName !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        utils.forEach(_data.accounts, function (account) {
            if (userName === account.userName) {
                result = utils.copy(account);
            }
        });

        return result;
    },

    getAccountByappId : function (appId) {
        var result = null;

        if (typeof appId !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        utils.forEach(_data.accounts, function (account) {
            if (appId === account.appId) {
                result = utils.copy(account);
            }
        });

        return result;
    },

    getAccountByServiceId : function (serviceId) {
        var result = null;

        if (typeof serviceId !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        utils.forEach(_data.accounts, function (account) {
            if (serviceId === account.service.id) {
                result = utils.copy(account);
            }
        });

        return result;
    },

    getAccountByTag : function (tag) {
        var results = [], i;

        if (typeof tag !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        utils.forEach(_data.accounts, function (account) {
            for (i in account.service.tag) {
                if (tag === account.service.tag[i]) {
                    results.push(utils.copy(account));
                    break;
                }
            }
        });

        return results;
    },

    add : function (account, successCallback, errorCallback) {
        if (!_checkAccount(account)) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _checkCallback(successCallback, errorCallback);

        if (!_data.accounts[account.id]) {
            _data.accounts[account.id] = utils.copy(account);
        }

        successCallback();
    },

    update : function (account, successCallback, errorCallback) {
        if (!_checkAccount(account)) {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _checkCallback(successCallback, errorCallback);

        if (!_data.accounts[account.id]) {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
            return;
        }

        _data.accounts[account.id] = utils.copy(account);
        successCallback();
    },

    remove : function (id, successCallback, errorCallback) {
        if (typeof id !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _checkCallback(successCallback, errorCallback);

        if (!_data.accounts[id]) {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
            return;
        }

        delete _data.accounts[id];
        successCallback();
    },

    getAccountApplications : function () {
        var results = [];
        /* FIXME: wait for API update */
        return results;
    }
};

function _initialize() {
    _data.accounts = db.retrieveObject(_data.DB_ACCOUNT_KEY) || {};
}

_initialize();

module.exports = _self;

});
define('ripple/platform/tizen/2.0/poiBackend_openmapquest', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var lbs = require('ripple/platform/tizen/2.0/lbs_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    POIGeometry = require('ripple/platform/tizen/2.0/POIGeometry'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    _security;

function POIPublic(prop) {
    /* This is created for public use */
    var _self, i, copy, attr,  _id = null, _providerName = null;
    if (prop.id) {
        _id = prop.id;
    }
    if (prop.providerName) {
        _providerName = prop.providerName;
    }
    _self = {
        name : null,
        categories : [],
        address : null,
        phoneNumbers : [],
        geometry : null,
        urls : [],
        rating : null,
        tags : null,
        toGeoJSON : function () {
            throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
        }
    };

    _self.__defineGetter__("id", function () {
        return _id;
    });

    _self.__defineGetter__("providerName", function () {
        return _providerName;
    });

    if (prop) {
        if (prop.name) {
            _self.name = String(prop.name);
        }
        if (tizen1_utils.isValidArray(prop.categories)) {
            _self.categories = [];
            for (i in prop.categories) {
                _self.categories.push(String(prop.categories[i]));
            }
        }
        if (prop.address) {
            if (typeof prop.address === "string") {
                _self.address = String(prop.address);
            } else if (Object.prototype.toString.call(prop.address) === "[object Object]") {
                copy = prop.address.constructor();
                for (attr in prop.address) {
                    if (prop.address.hasOwnProperty(attr)) {
                        copy[attr] = prop.address[attr];
                    }
                }
                _self.address = copy;
            }
        }
        if (tizen1_utils.isValidArray(prop.phoneNumbers)) {
            _self.phoneNumbers = [];
            for (i in prop.phoneNumbers) {
                _self.phoneNumbers.push(String(prop.phoneNumbers[i]));
            }
        }
        if (prop.geometry) {
            _self.geometry = new POIGeometry(prop.geometry.position, prop.geometry.viewport, prop.geometry.wkt);
        }
        if (tizen1_utils.isValidArray(prop.urls)) {
            _self.urls = [];
            for (i in prop.urls) {
                _self.urls.push(String(prop.urls[i]));
            }
        }
        if (typeof prop.rating === "number") {
            _self.rating = prop.rating;
        }
        if (Object.prototype.toString.call(prop.tags) === "[object Object]") {
            copy = prop.tags.constructor();
            for (attr in prop.tags) {
                if (prop.tags.hasOwnProperty(attr)) {
                    copy[attr] = prop.tags[attr];
                }
            }
            _self.tags = copy;
        }
    }

    return _self;
}

module.exports = function (prop) {

    var _self = new lbs.LocationServiceProvider(prop);

    if (prop.metaData) {
        _security = prop.metaData;
    }

    _self.__defineGetter__("supportedFilterTypes", function () {
        return [];
    });

    _self.__defineGetter__("supportedPOIFilterAttributes", function () {
        return [];
    });

    _self.__defineGetter__("supportedCategories", function () {
        /* reference: http://wiki.openstreetmap.org/wiki/Map_Features#Amenity */
        return ["bar", "bbq", "biergarten", "cafe", "drinking_water", "fast_food", "food_court", "ice_cream",
                "pub", "restaurant", "college", "kindergarten", "library", "school", "university",
                "bicycle_parking", "bicycle_rental", "bus_station", "car_rental", "car_sharing", "car_wash",
                "ev_charging", "ferry_terminal", "fuel", "grit_bin", "parking", "parking_entrance",
                "parking_space", "taxi", "atm", "bank", "bureau_de_change", "baby_hatch", "clinic",
                "dentist", "doctors", "hospital", "nursing_home", "pharmacy", "social_facility", "veterinary",
                "arts_centre", "cinema", "community_centre", "fountain", "nightclub", "social_centre",
                "stripclub", "studio", "swingerclub", "theatre", "bench", "brothel", "clock", "courthouse",
                "crematorium", "embassy", "fire_station", "grave_yard", "hunting_stand", "marketplace",
                "place_of_worship", "police", "post_box", "post_office", "prison", "public_building",
                "recycling", "sauna", "shelter", "shower", "telephone", "toilets", "townhall", "vending_machine",
                "waste_basket", "waste_disposal", "watering_place"];
    });

    _self.__defineGetter__("capabilities", function () {
        /* The set is empty, indicating that this provider supports only 'find' operations */
        return [];
    });

    _self.find = function (point, successCallback, errorCallback, options) {
        /* This provider only supports searching by "GeoRectBounds" due to MapQuest XAPI limitation */

        function _find() {
            var searchStr, pois = [], isTypeOK = false,
                id, providerName, name, categories = [], geometry;

            if (Object.prototype.toString.call(point) === "[object Object]") {
                if (point.southWest && point.northEast) {
                    if (typeof point.southWest.latitude === "number" &&
                        typeof point.southWest.longitude === "number" &&
                        typeof point.northEast.latitude === "number" &&
                        typeof point.northEast.longitude === "number") {
                        isTypeOK = true;
                    }
                }
            }

            if (!isTypeOK) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }

            searchStr = "http://open.mapquestapi.com/xapi/api/0.6/node";
            if (options && tizen1_utils.isValidArray(options.categories) &&
                options.categories.length > 0 && typeof options.categories[0] === "string") {
                /* xapi support single amenity only */
                searchStr += "[amenity=" + options.categories[0] + "]";
            }
            searchStr += "[bbox=" + point.southWest.longitude + "," + point.southWest.latitude + "," +
                point.northEast.longitude + "," + point.northEast.latitude + "]";

            /* use Open MapQuest online xapi service. (http://open.mapquestapi.com/xapi/) */
            $.ajax({
                type: "GET",
                url: searchStr,
                dataType: "xml",
                timeout: 15000, /* 15 secs timeout */
                success: function (xml) {
                    providerName = $(xml).find("osm").attr("generator");
                    $(xml).find("node").each(function () {
                        var $item = $(this);
                        categories = [];
                        id = $item.attr("id");
                        geometry = new POIGeometry(new SimpleCoordinates($item.attr("lat"), $item.attr("lon")));
                        $item.find("tag").each(function () {
                            if ($(this).attr("k") === "name") {
                                name = $(this).attr("v");
                            } else if ($(this).attr("k") === "amenity") {
                                categories.push($(this).attr("v"));
                            }
                        });
                        pois.push(new POIPublic({id: id, providerName: providerName, name: name,
                                                categories: categories, geometry: geometry}));
                    });
                    successCallback(pois);
                },
                error: function (obj, msg) {
                    if (errorCallback) {
                        if (msg === "timeout") {
                            setTimeout(function () {
                                errorCallback(new WebAPIError(errorcode.TIMEOUT_ERR));
                            }, 1);
                        } else {
                            setTimeout(function () {
                                errorCallback(new WebAPIError(errorcode.NETWORK_ERR));
                            }, 1);
                        }
                    }
                }
            });
        }

        if (!_security.all && !_security.find) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "find", _find);
    };

    _self.update = function (poi, successCallback, errorCallback) {
        if (!_security.all && !_security.update) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
    };

    _self.add = function (poi, successCallback, errorCallback) {
        if (!_security.all && !_security.add) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
    };

    _self.remove = function (poi, successCallback, errorCallback) {
        if (!_security.all && !_security.remove) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/CalendarEventId', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (uid, rid) {
    var _self = {};

    _self.uid = (uid) ? String(uid) : "";
    _self.rid = (rid) ? String(rid) : "";

    return _self;
};

});
define('ripple/platform/tizen/2.0/application', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    applicationService = require('ripple/platform/tizen/2.0/ApplicationService'),
    _security = {
        "http://tizen.org/api/application": [],
        "http://tizen.org/api/application.launch": ["launch", "launchService"],
        "http://tizen.org/api/application.kill": ["kill"],
        "http://tizen.org/api/application.read": [""],
        all: true
    },
    _data = {
        applications : null,
        applicationContexts : [],
        activeApp : null,
        listeners : {}
    },
    _self;

/* applications
 * [{appId: "org.tizen.apps.alarm", appInfo: {}, appServices: []}]
 */

/* applicationContexts
 * [{id: Math.uuid(null, 16), appId: "org.tizen.apps.alarm", parent: null, children: [], service: {}}]
 */

function _initialize() {
    event.trigger("appsInit", [_data]);
}

_initialize();

_self = function () {
    // private
    function getHandle() {
        var handle;
        do {
            handle = Math.uuid(10, 10);
        } while (handle.toString().indexOf('0') === 0);
        return handle;
    }

    function sortNumber(a, b) {
        return b - a;
    }

    function getChildren(id) {
        var i, j, k, temp, children = [], index = [];

        for (i in _data.applicationContexts) {
            if (_data.applicationContexts[i].appId === id) {
                children = _data.applicationContexts[i].children;
                index.push(i);
                break;
            }
        }
        do {
            temp = [];
            for (j in children) {
                for (k in _data.applicationContexts) {
                    if (_data.applicationContexts[k].appId === children[j]) {
                        index.push(k);
                        temp = temp.concat(_data.applicationContexts[k].children);
                    }
                }
            }
            children = temp;
        } while (children.length !== 0);

        return index;
    }

    function clearChildren(id, index) {
        var i, j, k, temp;

        for (i in _data.applicationContexts) {
            if ((i !== index) && (_data.applicationContexts[i].children.length !== 0)) {
                temp = [];
                for (j in _data.applicationContexts[i].children) {
                    if (_data.applicationContexts[i].children[j] === id) {
                        temp.push(j);
                    }
                }
                if (temp.length !== 0) {
                    temp.sort(sortNumber);
                    for (k in temp) {
                        _data.applicationContexts[i].children.splice(temp[k], 1);
                    }
                }
            }
        }
    }

    function closeApp(id, successCallback, errorCallback) {
        var i, children = getChildren(id);

        children.sort(sortNumber);

        for (i in children) {
            _data.applicationContexts.splice(children[i], 1);
        }
        if (successCallback) {
            successCallback();
        }
    }

    // public
    function launch(id, successCallback, errorCallback, argument) {
        var i, j, context, isRunning = false;

        if (!_security.all && !_security.launch)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if (typeof id !== "string")
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        for (i in _data.applications) {
            if (_data.applications[i].appId === id) {
                for (j in _data.applicationContexts) {
                    if (_data.applicationContexts[j].appId === id) {
                        isRunning = true;
                        context = _data.applicationContexts[j];
                        break;
                    }
                }
                if (!isRunning) {
                    context = {id : Math.uuid(null, 16), appId : id, parent : "", children : [], service : {}};
                    _data.applicationContexts.push(context);
                }
                _data.activeApp = context;
                if (successCallback) {
                    successCallback();
                }
                return;
            }
        }
        if (errorCallback) {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
        }
    }

    function kill(contextId, successCallback, errorCallback) {
        var i, j, appId;

        if (!_security.all && !_security.kill)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if (typeof contextId !== "string")
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        for (i in _data.applicationContexts) {
            if (_data.applicationContexts[i].id === contextId) {
                appId = _data.applicationContexts[i].appId;
                j = i;
            }
        }
        if (!appId) {
            if (errorCallback)
                errorCallback();
            return;
        }
        closeApp(appId, successCallback, errorCallback);
    }

    function exit() {
        if (!_data.activeApp)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        closeApp(_data.activeApp.appId, null, null);
        if (_data.applicationContexts.length > 0) {
            _data.activeApp = _data.applicationContexts[_data.applicationContexts.length - 1];
        } else {
            _data.activeApp = null;
        }
    }

    function hide() {
        var i;

        if (!_data.activeApp)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        if (_data.applicationContexts.length === 1) {
            _data.activeApp = null;
            return;
        }
        for (i in _data.applicationContexts) {
            if (_data.applicationContexts[i].appId === _data.activeApp.appId) {
                if (_data.applicationContexts.length > 0) {
                    _data.activeApp = _data.applicationContexts[_data.applicationContexts.length - 1];
                } else {
                    _data.activeApp = null;
                }
                break;
            }
        }
    }

    function launchService(service, id, successCallback, errorCallback, replyCB) {
        var i, j, k, isRunning = false, appContext, activeApp;

        if (!_security.all && !_security.launch)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if ((typeof service !== "object") ||
            (typeof service.operation !== "string") ||
            (service.uri && (typeof service.uri !== "string")) ||
            (service.mime && (typeof service.mime !== "string")) ||
            (!service.data instanceof Array) ||
            (typeof service.replyResult !== "function") ||
            (typeof service.replyFailure !== "function"))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (id && (typeof id !== "string"))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (replyCB && ((typeof replyCB !== "object") ||
            (replyCB.onsuccess && (typeof replyCB.onsuccess !== "function")) ||
            (replyCB.fail && (typeof replyCB.fail !== "function"))))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (id) {
            for (i in _data.applications) {
                if (_data.applications[i].appId === id) {
                    for (j in _data.applicationContexts) {
                        if (_data.applicationContexts[j].appId === _data.activeApp.appId) {
                            _data.applicationContexts[j].children.push(id);
                            clearChildren(id, j);
                        }
                        if (_data.applicationContexts[j].appId === id) {
                            _data.applicationContexts[j].service = service;
                            _data.applicationContexts[j].parent = _data.activeApp.appId;
                            activeApp = _data.applicationContexts[j];
                            isRunning = true;
                        }
                    }
                    if (isRunning) {
                        _data.activeApp = activeApp;
                        return;
                    }
                    appContext = {id : Math.uuid(null, 16), appId : id, parent : _data.activeApp.appId, children : [], service : service};
                    _data.applicationContexts.push(appContext);
                    _data.activeApp = appContext;
                    service.replyResult(service.data);
                    if (successCallback) {
                        successCallback();
                    }
                    if (replyCB) {
                        replyCB.onsuccess(service.data);
                    }
                    return;
                }
            }
        } else {
            for (i in _data.applications) {
                for (j in _data.applications[i].appServices) {
                    if (service.operation === _data.applications[i].appServices[j].operation) {
                        for (k in _data.applicationContexts) {
                            if (_data.applicationContexts[k].appId === _data.activeApp.appId) {
                                _data.applicationContexts[k].children.push(_data.applications[i].appId);
                                clearChildren(id, k);
                            }
                            if (_data.applicationContexts[k].appId === _data.applications[i].appId) {
                                activeApp = _data.applicationContexts[k];
                                _data.applicationContexts[k].service = service;
                                _data.applicationContexts[k].parent = _data.activeApp.appId;
                                isRunning = true;
                            }
                        }
                        if (isRunning) {
                            _data.activeApp = activeApp;
                            return;
                        }
                        appContext = {id : Math.uuid(null, 16), appId : _data.applications[i].appId, parent : _data.activeApp.id, children : [], service : service};
                        _data.applicationContexts.push(appContext);
                        _data.activeApp = appContext;
                        service.replyResult(service.data);
                        if (successCallback) {
                            successCallback();
                        }
                        if (replyCB) {
                            replyCB.onsuccess(service.data);
                        }
                        return;
                    }
                }
            }
        }
        if (replyCB) {
            replyCB.onfail();
        }
        if (errorCallback) {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
        }
    }

    function getAppService() {
        if (!_data.activeApp)
            throw new WebAPIError(errorcode.UNKNOWN_ERR);

        return _data.activeApp.service;
    }

    function getAppsContext(successCallback, errorCallback) {
        var i, context, appsContext = [];

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        for (i in _data.applicationContexts) {
            context = {id : _data.applicationContexts[i].id, appId : _data.applicationContexts[i].appId};
            appsContext.push(context);
        }
        successCallback(appsContext);
    }

    function getAppContext(id) {
        var i, contextId, appContext;

        if (id && (typeof id !== "string"))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        contextId = id || _data.activeApp.appId;
        for (i in _data.applicationContexts) {
            if (_data.applicationContexts[i].id === contextId) {
                appContext = {
                    id : _data.applicationContexts[i].id,
                    appId : _data.applicationContexts[i].appId
                };
                break;
            }
        }

        if (!appContext)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        return appContext;
    }

    function getAppsInfo(successCallback, errorCallback) {
        var i, appsInfo = [];

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        for (i in _data.applications) {
            appsInfo.push(_data.applications[i].appInfo);
        }
        successCallback(appsInfo);
    }

    function getAppInfo(id) {
        var i, appId, appInfo;

        if (typeof id !== "string")
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        appId = id || _data.activeApp.appId;

        for (i in _data.applications) {
            if (_data.applications[i].appId === appId) {
                appInfo = _data.applications[i].appInfo;
                break;
            }
        }

        if (!appInfo)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        return appInfo;
    }

    function addAppInfoEventListener(eventCallback, errorCallback) {
        var handle;

        if (!eventCallback ||
            (errorCallback && (typeof errorCallback !== "function")) ||
            (eventCallback && (typeof eventCallback !== "object")) ||
            (eventCallback.oninstalled && (typeof eventCallback.oninstalled !== "function")) ||
            (eventCallback.onupdated && (typeof eventCallback.onupdated !== "function")) ||
            (eventCallback.onuninstalled && (typeof eventCallback.onuninstalled !== "function")))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        handle = getHandle();
        _data.listeners[handle] = eventCallback;

        return handle;
    }

    function removeAppInfoEventListener(listenerID) {
        if (typeof listenerID !== "number")
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (!_data.listeners[listenerID])
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        delete _data.listeners[listenerID];
    }

    function handleSubFeatures(subFeatures) {
        for (var subFeature in subFeatures) {
            if (_security[subFeature].length === 0) {
                _security.all = true;
                return;
            }
            _security.all = false;
            utils.forEach(_security[subFeature], function (method) {
                _security[method] = true;
            });
        }
    }

    var application = {
        launch : launch,
        kill : kill,
        exit : exit,
        hide : hide,
        launchService : launchService,
        getAppService : getAppService,
        getAppsContext : getAppsContext,
        getAppContext : getAppContext,
        getAppsInfo : getAppsInfo,
        getAppInfo : getAppInfo,
        addAppInfoEventListener : addAppInfoEventListener,
        removeAppInfoEventListener : removeAppInfoEventListener,
        handleSubFeatures : handleSubFeatures
    };

    return application;
};

event.on("programChanged", function (status, param) {
    var callback, id;

    switch (status) {
    case "installed":
    case "updated":
    case "uninstalled":
        callback = "on" + status;
        break;

    default:
        return;
    }

    for (id in _data.listeners) {
        _data.listeners[id][callback](param);
    }
});

module.exports = _self;

});
define('ripple/platform/tizen/2.0/mediacontent', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    db = require('ripple/db'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    PendingObject = require('ripple/platform/tizen/2.0/pendingObject'),
    PendingOperation = require('ripple/platform/tizen/2.0/pendingoperation'),
    MediaSource,
    _data = {
        DB_MEDIACONTENT_KEY: "tizen1-db-mediacontent",
        mediaSource: null,
        folders: [],
        items: []
    },
    _self;

function _defaultMediaContent() {
    var video1 = {
        id: Math.uuid(null, 16),
        editableAttibutes: ["title", "description", "rating", "playedTime", "artists", "album"],
        title: "olympic",
        type: "VIDEO",
        mimeType: "video/x-msvideo",
        duration: 1245,
        width: 480,
        height: 240,
        itemURI : "videos/olympic.avi",
        rating: 4,
        playedTime: 1230,
        description: "Olympic Games",
        createdDate: new Date(),
        artists: ["olympic"],
        album: "olympic"
    },
    video2 = {
        id: Math.uuid(null, 16),
        editableAttibutes: ["title", "description", "rating", "playCount"],
        title: "galaxy",
        type: "VIDEO",
        duration: 156,
        width: 220,
        height: 180,
        itemURI : "videos/galaxy.rmvb",
        description: "Universe Spectacle",
        rating: 5,
        playCount: 2,
        createdDate: new Date(),
        modifiedDate: new Date()
    },
    image1 = {
        id: Math.uuid(null, 16),
        editableAttibutes: ["title", "orientation", "description", "rating"],
        title: "greatwall",
        type: "IMAGE",
        width: 480,
        height: 240,
        size: 1024,
        description: "GREATEWALL",
        itemURI: "images/greatwall.jpg",
        createdDate: new Date(),
        rating: 1,
        orientation: "NORMAL"
    },
    image2 = {
        id: Math.uuid(null, 16),
        editableAttibutes: ["title", "orientation", "description", "rating"],
        title: "seagull",
        type: "IMAGE",
        width: 480,
        height: 240,
        itemURI: "images/seagull.gif",
        createdDate: new Date(),
        description: "SEAGULL",
        rating: 2,
        orientation: "ROTATE_180"
    },
    audio1 = {
        id: Math.uuid(null, 16),
        editableAttibutes: ["title", "album", "genres", "artists", "composers"],
        title: "rock",
        type: "AUDIO",
        itemURI: "music/rock.mp3",
        createdDate: new Date(),
        album: "rock",
        genres: ["R&B"],
        artists: ["eminem"],
        composers: ["eminem"],
        copyright: "Copyright Rocky",
        bitrate: 128
    },
    audio2 = {
        id: Math.uuid(null, 16),
        editableAttibutes: ["title", "album", "genres", "artists", "composers"],
        title: "jazz",
        type: "AUDIO",
        itemURI: "music/jazz.acc",
        createdDate: new Date(),
        album: "jazz",
        genres: ["jazz"],
        artists: ["jackson"],
        composers: ["johnson"],
        copyright: "Copyright Rocky",
        bitrate: 128
    },
    videoFolder = {
        id: Math.uuid(null, 16),
        folderURI: "videos/",
        title: "videos",
        storageType: "INTERNAL",
        modifiedDate: new Date(),
    },
    audioFolder = {
        id: Math.uuid(null, 16),
        folderURI: "music/",
        title: "music",
        storageType: "EXTERNAL",
        modifiedDate: new Date(),
    },
    imageFolder = {
        id: Math.uuid(null, 16),
        folderURI: "images/",
        title: "images",
        storageType: "EXTERNAL",
        modifiedDate: new Date(),
    },
    mc = {
        folders: [videoFolder, audioFolder, imageFolder],
        items: [video1, video2, image1, image2, audio1, audio2]
    };

    db.saveObject(_data.DB_MEDIACONTENT_KEY, mc);

    return mc;
}

function _initialize() {
    var mc = db.retrieveObject(_data.DB_MEDIACONTENT_KEY) || _defaultMediaContent();

    _data.mediaSource = new MediaSource();
    _data.items       = mc.items;
    _data.folders     = mc.folders;
}

_self = {
    getLocalMediaSource: function () {
        return _data.mediaSource;
    }
};

MediaSource = function () {
    // private
    function find(successCallback, errorCallback, src, filter, sortMode, count, offset) {
        var items;

        if (src.length === 0) {
            if (errorCallback) {
                setTimeout(function () {
                    errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                }, 1);
            }
            return;
        }

        items = tizen1_utils.query(src, filter, sortMode, count, offset);
        successCallback(utils.copy(items));
    }

    function update(items, successCallback, errorCallback) {
        var i, j, mc, count = 0, isFound = false, matched = [];

        if (tizen1_utils.isValidArray(items)) {
            for (i in items) {
                for (j in _data.items) {
                    if (items[i].id === _data.items[j].id) {
                        ++count;
                        matched.push(j);
                        break;
                    }
                }
            }

            if (count === items.length) {
                for (i in matched) {
                    _data.items[matched[i]] = utils.copy(items[i]);
                }
                isFound = true;
            }
        } else {
            for (i in _data.items) {
                if (_data.items[i].id === items.id) {
                    _data.items[i] = utils.copy(items);
                    isFound = true;
                    break;
                }
            }
        }

        if (isFound) {
            mc = {folders: _data.folders, items: _data.items};
            db.saveObject(_data.DB_MEDIACONTENT_KEY, mc);
            if (successCallback) {
                successCallback();
            }
        } else if (errorCallback) {
            setTimeout(function () {
                errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
            }, 1);
        }
    }

    // public
    function updateItem(item) {
        update(item);
    }

    function updateItemsBatch(items, successCallback, errorCallback) {
        function _updateItemsBatch() {
            update(items, successCallback, errorCallback);
        }
        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "mediacontent:updateItemsBatch", _updateItemsBatch);
    }

    function getFolders(successCallback, errorCallback) {
        function _getFolders() {
            if (_data.folders.length === 0) {
                if (errorCallback) {
                    setTimeout(function () {
                        errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                    }, 1);
                }
                return;
            }

            successCallback(_data.folders);
        }
        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "mediacontent:getFolders", _getFolders);
    }

    function findItems(successCallback, errorCallback, folderId, filter, sortMode, count, offset) {
        function _findItems() {
            var src = [], i, folderURI, parentURI;

            if (!folderId) {
                src = _data.items;
            } else {
                if (_data.folders.length === 0) {
                    if (errorCallback) {
                        setTimeout(function () {
                            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                        }, 1);
                    }
                    return;
                }

                for (i in _data.folders) {
                    if (_data.folders[i].id === id) {
                        folderURI = _data.folders[i].folderURI;
                        break;
                    }
                    if (!folderURI) {
                        if (errorCallback) {
                            setTimeout(function () {
                                errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
                            }, 1);
                        }
                        return;
                    }
                }

                for (i in _data.items) {
                    parentURI = _data.items[i].itemURI;
                    parentURI = parentURI.slice(0, parentURI.lastIndexOf('/'));
                    if (parentURI === folderURI) {
                        src.push(_data.items[i]);
                    }
                }

                if (src.length === 0) {
                    if (errorCallback) {
                        setTimeout(function () {
                            errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
                        }, 1);
                    }
                    return;
                }
            }

            find(successCallback, errorCallback, src, filter, sortMode, count, offset);
        }

        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "mediacontent:findItems", _findItems);
    }

    this.updateItem       = updateItem;
    this.updateItemsBatch = updateItemsBatch;
    this.getFolders       = getFolders;
    this.findItems        = findItems;
};

_initialize();

module.exports = _self;

});
define('ripple/platform/tizen/2.0/DeviceOrientationEvent', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Event = require('ripple/platform/tizen/2.0/EventBase');

module.exports = function () {
    var _self = {
            alpha: null,
            beta: null,
            gamma: null,
            absolute: false,
        };

    Event.call(this);

    this.__defineGetter__("alpha", function () {
        return _self.alpha;
    });

    this.__defineGetter__("beta", function () {
        return _self.beta;
    });

    this.__defineGetter__("gamma", function () {
        return _self.gamma;
    });

    this.__defineGetter__("absolute", function () {
        return _self.absolute;
    });

    this.initDeviceOrientationEvent = function (orientationType, orientationBubbles, orientationCancelable,
                                               alphaData, betaData, gammaData, isAbsolute) {
        this.initEvent(orientationType, orientationBubbles, orientationCancelable);

        _self.alpha    = alphaData;
        _self.beta     = betaData;
        _self.gamma    = gammaData;
        _self.absolute = isAbsolute;
    };
};


});
define('ripple/platform/tizen/2.0/route', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    ProviderNominatim = require('ripple/platform/tizen/2.0/routeBackend_navigation'), // navigation route service
    _getProviders,
    _providers,
    _self;

function _initialize() {
    _providers = [new ProviderNominatim({name : "Nominatim", connectivity : "ONLINE"})];
}

_initialize();

_self = {
    getDefaultProvider : function () {
        if (arguments.length !== 0) {
            throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
        }
        return _providers[0];
    },
    getProviders : function () {
        if (arguments.length !== 0) {
            throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
        }
        return _providers;
    }
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/POIBase', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    POIGeometry = require('ripple/platform/tizen/2.0/POIGeometry'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');


module.exports = function (prop) {
    var _self, i, copy, attr;
    _self = {
        name : null,
        categories : [],
        address : null,
        phoneNumbers : [],
        geometry : null,
        urls : [],
        rating : null,
        tags : null,
        toGeoJSON : function () {
            throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
        }
    };

    _self.__defineGetter__("id", function () {
        return null;
    });

    _self.__defineGetter__("providerName", function () {
        return null;
    });

    if (prop) {
        if (prop.name) {
            _self.name = String(prop.name);
        }
        if (tizen1_utils.isValidArray(prop.categories)) {
            _self.categories = [];
            for (i in prop.categories) {
                _self.categories.push(String(prop.categories[i]));
            }
        }
        if (prop.address) {
            if (typeof prop.address === "string") {
                _self.address = String(prop.address);
            } else if (Object.prototype.toString.call(prop.address) === "[object Object]") {
                copy = prop.address.constructor();
                for (attr in prop.address) {
                    if (prop.address.hasOwnProperty(attr)) {
                        copy[attr] = prop.address[attr];
                    }
                }
                _self.address = copy;
            }
        }
        if (tizen1_utils.isValidArray(prop.phoneNumbers)) {
            _self.phoneNumbers = [];
            for (i in prop.phoneNumbers) {
                _self.phoneNumbers.push(String(prop.phoneNumbers[i]));
            }
        }
        if (prop.geometry) {
            _self.geometry = new POIGeometry(prop.geometry.position, prop.geometry.viewport, prop.geometry.wkt);
        }
        if (tizen1_utils.isValidArray(prop.urls)) {
            _self.urls = [];
            for (i in prop.urls) {
                _self.urls.push(String(prop.urls[i]));
            }
        }
        if (typeof prop.rating === "number") {
            _self.rating = prop.rating;
        }
        if (Object.prototype.toString.call(prop.tags) === "[object Object]") {
            copy = prop.tags.constructor();
            for (attr in prop.tags) {
                if (prop.tags.hasOwnProperty(attr)) {
                    copy[attr] = prop.tags[attr];
                }
            }
            _self.tags = copy;
        }
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/lbs_utils', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    _self;

function CoordinateProperties(prop) {
    var _self;
    _self = {
        latitude : prop.latitude || 0,
        longitude : prop.longitude || 0,
        altitude : prop.altitude || 0,
        accuracy : prop.accuracy || 0,
        altitudeAccuracy : prop.altitudeAccuracy || 0,
        heading : prop.heading || 0,
        speed : prop.speed || 0
    };
    return _self;
}

function _checkAddressProperties(p, dst) {
    if (p.country !== null && p.country !== undefined)
        dst.country = String(p.country);
    if (p.region !== null && p.region !== undefined)
        dst.region = String(p.region);
    if (p.county !== null && p.county !== undefined)
        dst.county = String(p.county);
    if (p.city !== null && p.city !== undefined)
        dst.city = String(p.city);
    if (p.street !== null && p.street !== undefined)
        dst.street = String(p.street);
    if (p.streetNumber !== null && p.streetNumber !== undefined)
        dst.streetNumber = String(p.streetNumber);
    if (p.premises !== null && p.premises !== undefined)
        dst.premises = String(p.premises);
    if (p.additionalInformation !== null && 
        p.additionalInformation !== undefined)
        dst.additionalInformation = String(p.additionalInformation);
    if (p.postalCode !== null && p.postalCode !== undefined)
        dst.postalCode = String(p.postalCode);
}

function AddressProperties(prop) {
    var _self;
    _self = {
        country : null,
        region : null,
        county : null,
        city : null,
        street : null,
        streetNumber : null,
        premises : null,
        additionalInformation : null,
        postalCode : null
    };
    if (prop) {
        if (_checkAddressProperties(prop, _self) === false)
            return undefined;
    }
    return _self;
}

_self = {
    LocationServiceProvider : function (prop) {
        var _self;
        _self = {
            name : "",
            metaData : Object,
            attribution : "",
            supportedOptions : [],
            setOptions : function (options, successCB, errorCB) {},
            connectivity : "" // "ONLINE" "OFFLINE" "HYBRID"
        };

        if (prop.name !== null && prop.name !== undefined)
            _self.name = String(prop.name); 
        if (prop.metaData !== null && prop.metaData !== undefined)
            _self.metaData = prop.metaData;

        if (prop.attribution !== null && prop.attribution !== undefined)
            _self.attribution = String(prop.attribution);

        if (prop.supportedOptions !== null && prop.supportedOptions !== undefined)
            _self.supportedOptions = [prop.supportedOptions];

        if (prop.setOptions !== null && prop.setOptions !== undefined)
            _self.setOptions = prop.setOptions;

        if (prop.connectivity !== null && prop.connectivity !== undefined)
            _self.connectivity = String(prop.connectivity);

        return _self;
    },

    GeoCoordinates : function (prop) {
        var _self = new CoordinateProperties(prop);
        if (tizen1_utils.isEmptyObject(_self)) {
            return undefined;
        }

        return _self;
    },
    
    StructuredAddress : function (prop) {
        var _self;
        _self = new AddressProperties(prop);
        if (tizen1_utils.isEmptyObject(_self)) {
            return undefined;
        }

        return _self;
    }
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/geoBackend_nominatim', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var lbs = require('ripple/platform/tizen/2.0/lbs_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    GeocodeResult = require('ripple/platform/tizen/2.0/GeocodeResult');

function _concatAddrString(addr) {
    var ret = "", i, pieces;
    if (typeof addr === "string") {
        pieces = addr.split(" ");
        for (i = 0; i < pieces.length; i++) {
            ret = ret + pieces[i] + "+";
        }
    } else if (typeof addr === "object") {
        if (addr.premises !== null && addr.premises !== undefined) {
            ret = ret + addr.premises + "+";
        }
        if (addr.streetNumber !== null && addr.streetNumber !== undefined) {
            ret = ret + addr.streetNumber + "+";
        }
        if (addr.street !== null && addr.street !== undefined) {
            ret = ret + addr.street + "+";
        }
        if (addr.city !== null && addr.city !== undefined) {
            ret = ret + addr.city + "+";
        }
        if (addr.county !== null && addr.county !== undefined) {
            ret = ret + addr.county + "+";
        }
        if (addr.region !== null && addr.region !== undefined) {
            ret = ret + addr.region + "+";
        }
        if (addr.postalCode !== null && addr.postalCode !== undefined) {
            ret = ret + addr.postalCode + "+";
        }
        if (addr.country !== null && addr.country !== undefined) {
            ret = ret + addr.country + "+";
        }
    } else {
        return undefined;
    }
    ret = ret.slice(0, -1);
    return ret;
}

module.exports = function (prop) {
    var _self = new lbs.LocationServiceProvider(prop);
    
    _self.geocode = function (address, successCB, errorCB, options) {
        function _geocode() {
            var i, searchStr, coordinates = [], result;

            searchStr = _concatAddrString(address);
            if (searchStr === undefined) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            searchStr = "http://nominatim.openstreetmap.org/search?q=" + searchStr + "&format=json&polygon=1&addressdetails=1";

            /* use nominatim online geo service. (http://nominatim.openstreetmap.org) */
            $.getJSON(searchStr, function (data) {
                for (i = 0; i < data.length; i++) {
                    result = new GeocodeResult(parseFloat(data[i].lat), parseFloat(data[i].lon));
                    coordinates.push(result);
                }
                successCB(coordinates);
            }).error(function () {
                if (errorCB) {
                    setTimeout(function () {
                        errorCB(new WebAPIError(errorcode.NETWORK_ERR));
                    }, 1);
                }
            });
        }

        tizen1_utils.validateTypeMismatch(successCB, errorCB, "geocode", _geocode); 
    };

    _self.reverseGeocode = function (coordinates, successCB, errorCB, options) {
        function _reverseGeocode() {
            var searchStr = "";
            if (typeof coordinates !== "object" ||
                typeof coordinates.latitude !== "number" ||
                typeof coordinates.longitude !== "number") {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            searchStr = "http://nominatim.openstreetmap.org/reverse?format=json&lat=" +
                        coordinates.latitude + "&lon=" + coordinates.longitude + "&zoom=18&addressdetails=1";

            /* use nominatim online geo service. (http://nominatim.openstreetmap.org) */
            $.getJSON(searchStr, function (data) {
                var addr;

                if (options && options.resultType === "STRUCTURED") {
                    addr = new lbs.StructuredAddress({
                        country : data.address.country,
                        region : data.address.state,
                        county : data.address.county,
                        city : data.address.city,
                        street : data.address.road,
                        streetNumber : data.address.streetNumber,
                        postalCode : data.address.postcode
                    });
                } else {
                    addr = data.display_name;
                }
                successCB([addr]);
            }).error(function () {
                if (errorCB) {
                    setTimeout(function () {
                        errorCB(new WebAPIError(errorcode.NETWORK_ERR));
                    }, 1);
                }
            });
        }

        tizen1_utils.validateTypeMismatch(successCB, errorCB, "reverseGeocode", _reverseGeocode);
    };

    return _self;
};


});
define('ripple/platform/tizen/2.0/touchEvent', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var emulatorBridge = require('ripple/emulatorBridge'),
    event = require('ripple/event'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    Touch,
    TouchList,
    TouchEvent,
    _touchCanvasElements = [],
    _dataEnlargeRatio = 4,
    _self;

function _isValidTouch(touches) {
    var touche, _touches = [], i;
    if (!touches) {
        return false;
    }
    if (!tizen1_utils.isValidArray(touches)) {
        _touches = [touches];
    }

    for (i = 0; i < _touches.length; i++) {
        touche = _touches[i];
        if ((touche !== undefined) &&
            ((typeof touche !== "object") ||
            (typeof touche.target !== "object") ||
            (touche.identifier !== undefined) && (typeof touche.identifier !== "number") ||
            (touche.screenX !== undefined) && (typeof touche.screenX !== "number") ||
            (touche.screenY !== undefined) && (typeof touche.screenY !== "number") ||
            (touche.clientX !== undefined) && (typeof touche.clientX !== "number") ||
            (touche.clientY !== undefined) && (typeof touche.clientY !== "number") ||
            (touche.pageX !== undefined) && (typeof touche.pageX !== "number") ||
            (touche.pageY !== undefined) && (typeof touche.pageY !== "number")))
            return false;
    }
    return true;
}

function _dispatchAllEvents(event) {
    _touchCanvasElements.forEach(function (value) {
        if (value !== undefined) {
            value.dispatchEvent(event);
        }
    });
}

function _touchMove(event) {
    var data = event.data,
        touches = [],
        removedTouches = [],
        touchList,
        simulatedEvent,
        dataId,
        ids = [],
        intervalId,
        currentIndex,
        item = {};

    if (_touchCanvasElements.length === 0)
        return;

    for (dataId in data) {
        if (!data[dataId].length || data[dataId].length === 0)
            return;

        ids.push(dataId);
        item = data[dataId][0];
        touches.push(new Touch(item.target, dataId, item.pageX * _dataEnlargeRatio, item.pageY * _dataEnlargeRatio, item.screenX * _dataEnlargeRatio,
                               item.screenY * _dataEnlargeRatio, item.offsetX * _dataEnlargeRatio, item.offsetY * _dataEnlargeRatio));
    }

    // touch start
    touchList = new TouchList(touches);
    simulatedEvent = new TouchEvent("touchstart", true, true, touchList, touchList, touchList, event.altKey, event.metaKey, event.ctrlKey, event.shiftKey);
    _dispatchAllEvents(simulatedEvent);
    currentIndex = 0;

    // touch move and touch end
    intervalId = setInterval(function () {
        touches = [];
        removedTouches = [];

        ids.forEach(function (id) {
            var points = data[id],
                touchItem, removedItem;

            if (currentIndex < points.length) {
                touchItem = points[currentIndex];
            } else {
                removedItem = points[points.length - 1];
            }

            if (touchItem)
                touches.push(new Touch(touchItem.target, id, touchItem.pageX * _dataEnlargeRatio, touchItem.pageY * _dataEnlargeRatio, touchItem.screenX * _dataEnlargeRatio,
                                       touchItem.screenY * _dataEnlargeRatio, touchItem.offsetX * _dataEnlargeRatio, touchItem.offsetY * _dataEnlargeRatio));
            if (removedItem)
                removedTouches.push(new Touch(removedItem.target, id, removedItem.pageX * _dataEnlargeRatio, removedItem.pageY * _dataEnlargeRatio, removedItem.screenX * _dataEnlargeRatio,
                                    removedItem.screenY * _dataEnlargeRatio, removedItem.offsetX * _dataEnlargeRatio, removedItem.offsetY * _dataEnlargeRatio));
        });

        if (touches.length > 0) {
            simulatedEvent = new TouchEvent("touchmove", true, true, new TouchList(touches), new TouchList(touches), new TouchList(touches),
                event.altKey, event.metaKey, event.ctrlKey, event.shiftKey);
            _dispatchAllEvents(simulatedEvent);
        } else {
            clearInterval(intervalId);
        }

        if (removedTouches.length > 0) {
            simulatedEvent = new TouchEvent("touchend", true, true, new TouchList(removedTouches), new TouchList(removedTouches), new TouchList(removedTouches),
                event.altKey, event.metaKey, event.ctrlKey, event.shiftKey);
            _dispatchAllEvents(simulatedEvent);
        }
        currentIndex++;
    }, 50);
}

function _touchCancel(event) {
    var mousedownEvent = event.touchEvent,
        simulatedEvent;

    simulatedEvent = new TouchEvent("touchcancel", true, true, new TouchList([]), new TouchList([]), new TouchList([]),
        event.altKey, event.metaKey, event.ctrlKey, event.shiftKey);
    _dispatchAllEvents(simulatedEvent);
}

function _initialize() {
    event.on("touchCancel", _touchCancel);
    event.on("touchEvent", _touchMove);
}

Touch = function (target, identifier, pageX, pageY, screenX, screenY, clientX, clientY) {
    var _identifier = Number(identifier) || 0,
        _screenX = Number(screenX) || 0,
        _screenY = Number(screenY) || 0,
        _clientX = Number(clientX) || 0,
        _clientY = Number(clientY) || 0,
        _pageX = Number(pageX) || 0,
        _pageY = Number(pageY) || 0;

    this.__defineGetter__("identifier", function () {
        return _identifier;
    });
    this.__defineGetter__("target", function () {
        return target;
    });
    this.__defineGetter__("screenX", function () {
        return _screenX;
    });
    this.__defineGetter__("screenY", function () {
        return _screenY;
    });
    this.__defineGetter__("clientX", function () {
        return _clientX;
    });
    this.__defineGetter__("clientY", function () {
        return _clientY;
    });
    this.__defineGetter__("pageX", function () {
        return _pageX;
    });
    this.__defineGetter__("pageY", function () {
        return _pageY;
    });
};

TouchList = function (touches) {
    var _touches = _isValidTouch(touches) ? tizen1_utils.copy(touches) : [],
        i, _self;

    _self = {
        item : function (index) {
            if (typeof index !== "number") {
                return null;
            }
            if (index.toString().indexOf(".") !== -1) {
                return null;
            }
            if (/^\\d+$/.test(index) || index >= _touches.length) {
                return null;
            }
            if (!_touches) {
                return null;
            }
            return _touches[index];
        },

        identifiedTouch : function (identifier) {
            if (typeof identifier !== "number") {
                return null;
            }
            if (!_touches) {
                return null;
            }
            for (var i in _touches) {
                if (_touches[i].identifier === identifier) {
                    return _touches[i];
                }
            }
            return null;
        }
    };

    for (i = 0; i < _touches.length; i++) {
        _self.__defineGetter__(i, (function (index) {
            return function () {
                return _touches[index];
            };
        }(i)));
    }

    _self.__defineGetter__("length", function () {
        return _touches.length;
    });

    return _self;
};

TouchEvent = function (type, canBubble, cancelable, touches, targetTouches, changedTouches, altKey, metaKey, ctrlKey, shiftKey) {
    var touchEvent = emulatorBridge.document().createEvent("UIEvents");
    touchEvent.initUIEvent(type, canBubble, cancelable, emulatorBridge.window(), 1);

    touchEvent.__defineGetter__("touches", function () {
        return touches;
    });
    touchEvent.__defineGetter__("targetTouches", function () {
        return targetTouches;
    });
    touchEvent.__defineGetter__("changedTouches", function () {
        return changedTouches;
    });
    touchEvent.__defineGetter__("altKey", function () {
        return altKey;
    });
    touchEvent.__defineGetter__("metaKey", function () {
        return metaKey;
    });
    touchEvent.__defineGetter__("ctrlKey", function () {
        return ctrlKey;
    });
    touchEvent.__defineGetter__("shiftKey", function () {
        return shiftKey;
    });
    return touchEvent;
};

_self = {
    mask: function (frame) {
        frame.addEventListener("DOMContentLoaded", function () {
            /*
            var widgetDocument = frame.contentDocument,
                getElementByIdOri = widgetDocument.getElementById;

            widgetDocument.getElementById = function () {
                var element, addEventListenerOri;

                element = getElementByIdOri.apply(widgetDocument, Array.prototype.slice.call(arguments));

                if (element) {
                    addEventListenerOri = element.addEventListener;
                    element.addEventListener = function (event, callback, useCapture) {
                        if (event === "touchstart") {
                            _touchCanvasElements.push(element);
                        }
                        addEventListenerOri.apply(element, arguments);
                    };
                }
                return element;
            };

            widgetDocument.createTouch = function (view, target, identifier, pageX, pageY, screenX, screenY) {
                return new Touch(view, target, identifier, pageX, pageY, screenX, screenY);
            };

            widgetDocument.createTouchList = function (pattern) {
                if (arguments.length !== 1) {
                    return null;
                }
                return new TouchList(pattern);
            };
            */
        });
    }
};

_initialize();

module.exports = _self;

});
define('ripple/platform/tizen/2.0/CalendarAttendee', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (attendeeInitDict) {
    var _self;

    if (attendeeInitDict) {
        _self.uri          = (attendeeInitDict.uri) ? attendeeInitDict.uri : "";
        _self.name         = (attendeeInitDict.name) ? attendeeInitDict.name : "";
        _self.role         = (attendeeInitDict.role) ? attendeeInitDict.role : "";
        _self.status       = (attendeeInitDict.status) ? attendeeInitDict.status : "";
        _self.RSVP         = (attendeeInitDict.RSVP) ? attendeeInitDict.RSVP : "";
        _self.type         = (attendeeInitDict.type) ? attendeeInitDict.type : "";
        _self.group        = (attendeeInitDict.group) ? attendeeInitDict.group : "";
        _self.delegatorURI = (attendeeInitDict.delegatorURI) ? attendeeInitDict.delegatorURI : "";
        _self.delegateURI  = (attendeeInitDict.delegateURI) ? attendeeInitDict.delegateURI : "";
        _self.contactRef   = (attendeeInitDict.contactRef) ? attendeeInitDict.contactRef : "";
    } else {
        _self.uri          = "";
        _self.name         = "";
        _self.role         = "";
        _self.status       = "";
        _self.RSVP         = "";
        _self.type         = "";
        _self.group        = "";
        _self.delegatorURI = "";
        _self.delegateURI  = "";
        _self.contactRef   = "";
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/filesystem', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    utils = require('ripple/utils'),
    dbfs  = require('ripple/platform/tizen/2.0/dbfs'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    _maxPathLength = 256,
    _virtualRoots = ["documents", "images", "music", "videos", "downloads", "wgt-package", "wgt-private", "wgt-private-tmp", "removable", "attachments"],
    _security = {
        "http://tizen.org/api/filesystem": [],
        "http://tizen.org/api/filesystem.read": ["copyTo", "moveTo", "createDirectory", "createFile", "deleteDirectory", "deleteFile", "openStreamR"],
        "http://tizen.org/api/filesystem.write": ["readAsText", "openStreamW"],
        all: true
    },
    _realRoots = dbfs.roots,
    _r2vmap = {},
    _v2rmap = {},
    _initialized = false,
    _readOnly  = false,
    _writeOnly = false,
    _defaultMode = "rw",
    _storages = [], // filesystem storages
    _observers = [],
    File,
    FileStream,
    FileFilter,
    FileSystemStorage;

function _isValidChar(c) {
    return  (c >= '0' && c <= '9') ||
        (c >= 'a' && c <= 'z') ||
        (c >= 'A' && c <= 'Z') ||
        (c === ' ') ||
        (c === '_') ||
        (c === '-') ||
        (c === '.');
}

function _isValidFileName(name) {
    var _valid = true,
        _c;

    if (name === '' || name === '.' || name === '..' || (name.length > _maxPathLength)) {
        _valid = false;
    } else {
        for (_c = 0; _c < name.length; _c++) {
            if (!_isValidChar(name[_c])) {
                _valid = false;
                break;
            }
        }
    }

    return _valid;
}

function _initialize() {
    var _i;

    _storages.push(FileSystemStorage("InternalFlash", "INTERNAL", "MOUNTED" ));
    _storages.push(FileSystemStorage("MMC", "EXTERNAL", "REMOVED"));
    dbfs.initialize();

    // set up the map between real path and virtual path
    for (_i = 0; _i < _virtualRoots.length; _i++) {
        _r2vmap[_realRoots[_i]] = _virtualRoots[_i];
    }

    utils.forEach(_r2vmap, function (value, key) {
        _v2rmap[value] = key;
    });
}

function _resolveSync(srcLocation, onSuccess, onError, accessMode) {
    var _parts = srcLocation.replace(/\/$/, '').split("/"),
        _header, _fullPath,
        _i;

    // TODO: Initialize at bootstrap and emulatorBridge.link
    if (!_initialized) {
        _initialize();
        _initialized = true;
    }

    for (_i = 0; _i < _parts.length; _i++) {
        if (!_isValidFileName(_parts[_i])) {
            if (onError) {
                onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
            }
            return;
        }
    }

    _header = _v2rmap[_parts[0]];
    if (_header === undefined) {
        if (onError) {
            onError(new WebAPIError(errorcode.NOT_FOUND_ERR));
        }
        return;
    }

    if (_parts.length === 1) {
        _fullPath = _header;
    } else {
        _fullPath = _header + "/" + _parts.splice(1, _parts.length - 1).join("/");
    }

    dbfs.stat(_fullPath,
            function (entry) {
                onSuccess(new File(entry, accessMode));
            },
            function () {
                if (onError) {
                    onError(new WebAPIError(errorcode.NOT_FOUND_ERR));
                }
            });
}

function _resolveAsync(onSuccess, onError, srcLocation, accessMode) {
    _resolveSync(srcLocation,
                function (file) {
                    setTimeout(function () {
                        onSuccess(file);
                    }, 1);
                },
                function (e) {
                    setTimeout(function () {
                        onError(e);
                    }, 1);
                },
                accessMode);
}

File = function (entry, mode) {
    var _entry = entry,
        _mode = mode,
        _parent,
        _self;

    function _r2v(rpath) {
        var i, v, r, regExp;

        for (i = 0; i < _virtualRoots.length; i++) {
            v = _virtualRoots[i];
            r = _v2rmap[v];
            if (rpath.match("^" + r)) {
                regExp = new RegExp("^" + r);
                return rpath.replace(regExp, v);
            }
        }

        return "";
    }

    function _v2r(vpath) {
        var i, v, r, regExp;

        for (i = 0; i < _virtualRoots.length; i++) {
            v = _virtualRoots[i];
            r = _v2rmap[v];
            if (vpath.match("^" + v)) {
                regExp = new RegExp("^" + v);
                return vpath.replace(regExp, r);
            }
        }

        return "";
    }

    function _copyMoveInternal(onSuccess, onError, src, dst, overwrite, func) {
        var _srcName = String(src),
            _dstName = String(dst),
            _src = null,
            _dst = null,
            _error = false,
            _dstParent = null,
            _dstParts  = _dstName.split("/"),
            _dstParentName = _dstParts.splice(0, _dstParts.length - 1).join("/");

        if (!_entry.isDirectory) {
            if (onError) {
                setTimeout(function () {
                    onError(new WebAPIError(errorcode.IO_ERR));
                }, 1);
            }
            return undefined;
        }

        _resolveSync(_srcName,
                function (file) {
                    _src = file;
                },
                function (e) {
                    setTimeout(function () {
                        onError(e);
                    }, 1);
                },
                _mode);

        if (_src) {
            if (_src.parent.fullPath === _self.fullPath) {
                if (!_readOnly && _mode !== "r") {
                    _resolveSync(_dstParentName,
                            function (file) {
                                _dstParent = file;
                            },
                            function (e) {
                                setTimeout(function () {
                                    onError(e);
                                }, 1);
                            },
                            _mode);

                    if (_dstParent === null) {
                        return undefined;
                    }

                    _resolveSync(_dstName,
                            function (file) {
                                _dst = file;
                            },
                            function (e) {
                                if (e.code !== errorcode.NOT_FOUND_ERR) {
                                    setTimeout(function () {
                                        onError(e);
                                    }, 1);
                                    _error = true;
                                }
                            },
                            _mode);

                    if (_error) {
                        return undefined;
                    }

                    if (_src.isFile) {
                        if (_dst === null) {
                            func(_v2r(_srcName), _v2r(_dstName),
                                    function () {
                                        setTimeout(function () {
                                            onSuccess();
                                        }, 1);
                                    },
                                    function () {});
                            return null;
                        } else {
                            if (_dst.isFile && Boolean(overwrite) && (_srcName !== _dstName)) {
                                func(_v2r(_srcName), _v2r(_dstName),
                                        function () {
                                            setTimeout(function () {
                                                onSuccess();
                                            }, 1);
                                        },
                                        function () {});
                                return null;
                            } else {
                                setTimeout(function () {
                                    onError(new WebAPIError(errorcode.IO_ERR));
                                }, 1);
                            }
                        }
                    } else {
                        if (_dst === null) {
                            func(_v2r(_srcName), _v2r(_dstName),
                                function () {
                                    setTimeout(function () {
                                        onSuccess();
                                    }, 1);
                                },
                                function () {});
                            return null;
                        } else {
                            setTimeout(function () {
                                onError(new WebAPIError(errorcode.IO_ERR));
                            }, 1);
                        }
                    }
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                }
            } else {
                if (onError) {
                    setTimeout(function () {
                        onError(new WebAPIError(errorcode.IO_ERR));
                    }, 1);
                }
            }
        }

        return undefined;
    }

    _self = {
        toURI: function () {
            return "file://" + _entry.fullPath;
        },
        listFiles: function (onSuccess, onError, filter) {
            var _filter = Object(filter),
                _filterName = _filter.name,
                _startModified = _filter.startModified,
                _endModified   = _filter.endModified;

            function _matchName(fileName) {
                var _matched = true,
                    _name1 = String(_filterName).toLowerCase(),
                    _name2 = fileName.toLowerCase(),
                    _pattern;

                if (_filterName !== undefined && _filterName !== null) {
                    if (!_name1.match("\\\\%")) {
                        if (_name1.match("%")) {
                            _pattern = new RegExp("^" + _name1.replace(/%/g, ".*") + "$");
                            _matched = _name2.match(_pattern) ? true : false;
                        } else {
                            _matched = (_name1 === _name2);
                        }
                    } else {
                        // % is not allowed as a part of file name
                        _matched = false;
                    }
                }

                return _matched;
            }

            function _matchDate(date) {
                var _matched = true;

                if (_startModified !== undefined && _startModified !== null) {
                    _matched = (date.getTime() >= _startModified.getTime());
                }

                if (_matched && (_endModified !== undefined && _endModified !== null)) {
                    _matched = (date.getTime() <= _endModified.getTime());
                }

                return _matched;
            }

            function _matchFilter(entry) {
                return _matchName(entry.name) && _matchDate(entry.lastModifiedDate);
            }

            function _listFiles() {
                var _files = [];

                if ((_startModified !== undefined && !tizen1_utils.isValidDate(_startModified)) ||
                    (_endModified !== undefined && !tizen1_utils.isValidDate(_endModified))) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (!_entry.isDirectory) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.IO_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                utils.forEach(_entry.children, function (child) {
                    if (_matchFilter(child)) {
                        _files.push(new File(child, _mode));
                    }
                });

                setTimeout(function () {
                    onSuccess(_files);
                }, 1);

                return null;
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "listFiles", _listFiles);
        },
        openStream: function (mode, onSuccess, onError, encoding) {
            function _openStream() {
                var  _openMode = String(mode),
                    _encoding = encoding ? String(encoding) : "UTF-8";

                if (_openMode !== "r" && _openMode !== "w" && _openMode !== "a") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (!_security.all && ((!_security.openStreamR && _openMode === "r") || (!_security.openStreamW && _openMode === "w"))) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                if (_encoding !== "UTF-8" && _encoding !== "ISO-8859-1") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (((_readOnly || _mode === "r") && (_openMode === "w" || _openMode === "a")) ||
                    (_writeOnly && _openMode === "r")) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                setTimeout(function () {
                    onSuccess(new FileStream(_entry, _openMode, _encoding));
                }, 1);

                return null;
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "openStream", _openStream);
        },
        readAsText: function (onSuccess, onError, encoding) {
            if (!_security.all && !_security.readAsText) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            function _readAsText() {
                var _encoding = encoding ? String(encoding) : "UTF-8";
                if (_encoding !== "UTF-8" && _encoding !== "ISO-8859-1") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (_writeOnly) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (_self.isFile) {
                    dbfs.read(_entry.fullPath,
                            function (data) {
                                setTimeout(function () {
                                    onSuccess(data);
                                }, 1);
                            },
                            function () {});
                    return null;
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.IO_ERR));
                        }, 1);
                    }
                }

                return undefined;
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "readAsText", _readAsText);
        },
        copyTo: function (src, dst, overwrite, onSuccess, onError) {
            if (!_security.all && !_security.copyTo) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            function _copyTo() {
                return _copyMoveInternal(onSuccess, onError, src, dst, overwrite, dbfs.cp);
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "copyTo", _copyTo);
        },
        moveTo: function (src, dst, overwrite, onSuccess, onError) {
            if (!_security.all && !_security.moveTo) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            function _moveTo() {
                return _copyMoveInternal(onSuccess, onError, src, dst, overwrite, dbfs.mv);
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "moveTo", _moveTo);
        },
        createDirectory: function (dirPath) {
            var _path  = String(dirPath),
                _parts = _path.replace(/\/$/, "").split("/"),
                _dir   = null,
                _exist = null,
                _current = _entry.fullPath,
                _i;

            if (!_security.all && !_security.createDirectory) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            function onSuccess(entry) {
                _dir = entry;
            }

            for (_i = 0; _i < _parts.length; _i++) {
                if (!_isValidFileName(_parts[_i])) {
                    throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                }
            }

            if (!entry.isDirectory) {
                throw new WebAPIError(errorcode.IO_ERR);
            }

            _exist = _parts.reduce(function (obj, token) {
                return token === "" ? obj : (obj.children ? obj.children[token] || null : null);
            }, _entry);

            if (_exist) {
                throw new WebAPIError(errorcode.IO_ERR);
            }

            if (_readOnly || _mode === "r") {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            for (_i = 0; _i < _parts.length; _i++) {
                _current = _current + "/" + _parts[_i];
                dbfs.mkdir(_current, onSuccess);
            }

            return new File(_dir, _mode);
        },
        createFile: function (filePath) {
            var _name = String(filePath),
                _file = null;

            if (!_security.all && !_security.createFile) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (!_isValidFileName(_name)) {
                throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
            }

            if (!entry.isDirectory || (_entry.children && _entry.children[_name])) {
                throw new WebAPIError(errorcode.IO_ERR);
            }

            if (_readOnly || _mode === "r") {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            dbfs.touch(_entry.fullPath + "/" + _name,
                        function (entry) {
                            _file = new File(entry, _mode);
                        },
                        function () {});

            return _file;
        },
        resolve: function (filePath) {
            var _fullPath = _self.fullPath + "/" + String(filePath),
                _file = null;

            if (!_entry.isDirectory) {
                throw new WebAPIError(errorcode.IO_ERR);
            }

            _resolveSync(_fullPath,
                    function (file) {
                        _file = file;
                    },
                    function (e) {
                        throw (e);
                    },
                    _mode);

            return _file;
        },
        deleteDirectory: function (directory, recursive, onSuccess, onError) {
            if (!_security.all && !_security.deleteDirectory) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            function _deleteDirectory() {
                var _dir = null,
                    _dirName = String(directory);
                _resolveSync(_dirName,
                        function (file) {
                            _dir = file;
                        },
                        function (e) {
                            setTimeout(function () {
                                onError(e);
                            }, 1);
                        },
                        _mode);

                if (_dir) {
                    if (_dir.isDirectory &&
                        _dir.parent.fullPath === _self.fullPath &&
                        (!recursive && _dir.length === 0)) {
                        if (!_readOnly && _mode !== "r") {
                            dbfs.rmdir(_v2r(_dirName),
                                    function () {
                                        setTimeout(function () {
                                            onSuccess();
                                        }, 1);
                                    },
                                    function () {});
                            return null;
                        } else {
                            if (onError) {
                                setTimeout(function () {
                                    onError(new WebAPIError(errorcode.SECURITY_ERR));
                                }, 1);
                            }
                        }
                    } else {
                        if (onError) {
                            setTimeout(function () {
                                onError(new WebAPIError(errorcode.IO_ERR));
                            }, 1);
                        }
                    }
                }

                return undefined;
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "deleteDirectory", _deleteDirectory);
        },
        deleteFile: function (fileName, onSuccess, onError) {
            if (!_security.all && !_security.deleteFile) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            function _deleteFile() {
                var _file = null;
                _resolveSync(String(fileName),
                        function (file) {
                            _file = file;
                        },
                        function (e) {
                            if (onError) {
                                setTimeout(function () {
                                    onError(e);
                                }, 1);
                            }
                        },
                        _mode);

                if (_file) {
                    if (_file.isFile && _file.parent.fullPath === _self.fullPath) {
                        if (!_readOnly && _mode !== "r") {
                            dbfs.rm(_v2r(fileName),
                                    function () {
                                        setTimeout(function () {
                                            onSuccess();
                                        }, 1);
                                    },
                                    function () {});
                            return null;
                        } else {
                            if (onError) {
                                setTimeout(function () {
                                    onError(new WebAPIError(errorcode.SECURITY_ERR));
                                }, 1);
                            }
                        }
                    } else {
                        if (onError) {
                            setTimeout(function () {
                                onError(new WebAPIError(errorcode.IO_ERR));
                            }, 1);
                        }
                    }
                }

                return undefined;
            }

            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "deleteFile", _deleteFile);
        }
    };

    _self.__defineGetter__("parent", function () {
        var _parts = _self.fullPath.split("/");

        if (_parent === undefined) {
            if (_parts.length === 1) {
                // virtual root's parent is null
                _parent = null;
            } else {
                _resolveSync(_parts.splice(0, _parts.length - 1).join("/"),
                        function (file) {
                            _parent = file;
                        },
                        function () {},
                        _mode);
            }
            return _parent;
        } else {
            return _parent;
        }
    });

    _self.__defineGetter__("readOnly", function () {
        return false;
    });

    _self.__defineGetter__("isFile", function () {
        return !_entry.isDirectory;
    });

    _self.__defineGetter__("isDirectory", function () {
        return _entry.isDirectory;
    });

    _self.__defineGetter__("created", function () {
        return undefined;
    });

    _self.__defineGetter__("modified", function () {
        if (_entry.isDirectory) {
            return undefined;
        } else {
            return _entry.lastModifiedDate;
        }
    });

    _self.__defineGetter__("path", function () {
        var _parts = _self.fullPath.split("/");

        if (_parts.length === 1) {
            // virtual root
            return _parts.join("");
        } else {
            return _parts.splice(0, _parts.length - 1).join("/") + "/";
        }
    });

    _self.__defineGetter__("name", function () {
        return _entry.name;
    });

    _self.__defineGetter__("fullPath", function () {
        return _r2v(_entry.fullPath);
    });

    _self.__defineGetter__("fileSize", function () {
        if (_entry.isDirectory) {
            return undefined;
        } else {
            return _entry.data.length;
        }
    });

    _self.__defineGetter__("length", function () {
        var _l = 0;
        if (_entry.isDirectory) {
            utils.forEach(_entry.children, function () {
                _l++;
            });
            return _l;
        } else {
            return undefined;
        }
    });

    return _self;
};

FileStream = function (entry, mode, encoding) {
    var _entry = entry,
        _data = entry.data,
        _mode = mode,
        _position = (_mode === "a" ? _data.length : 0),
        _self;

    _self = {
        close: function () {
            var _element;
            if (mode === "a" || mode === "w") {
                dbfs.write(_entry.fullPath, _data, function () {}, function () {});
            }
            for (_element in _self) {
                delete _self[_element];
            }
        },
        read: function (charCount) {
            var _count  = charCount | 0,
                _substr = _data.substring(_position, _position + _count);

            if (_position + _count > _data.length) {
                _position = _data.length;
            } else {
                _position += _count;
            }

            return _substr;
        },
        readBytes: function (byteCount) {
            var _substr = _self.read(byteCount),
                _bytes = [],
                _i;

            for (_i = 0; _i < _substr.length; _i++) {
                _bytes.push(_substr.charCodeAt(_i));
            }

            return _bytes;
        },
        readBase64: function (byteCount) {
            var _substr = _self.read(byteCount);

            return window.atob(_substr);
        },
        write: function (stringData) {
            var _stringData = String(stringData),
                _substr = _data.substring(0, _position);

            _data = _substr.concat(_stringData);
            _position = _data.length;
        },
        writeBytes: function (byteData) {
            _self.write(String.fromCharCode.apply(String, byteData));
        },
        writeBase64: function (base64Data) {
            _self.write(window.btoa(String(base64Data)));
        }
    };

    _self.__defineGetter__("eof", function () {
        return _position === _data.length;
    });

    _self.__defineGetter__("position", function () {
        return _position;
    });

    _self.__defineSetter__("position", function (value) {
        var _value = value | 0;

        if (_value >= 0 && _value <= _data.length) {
            _position = _value;
        } else {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }
    });

    _self.__defineGetter__("bytesAvailable", function () {
        return (_data.length - _position) || -1;
    });

    return _self;
};

FileFilter = function (name, startModified, endModified, startCreated, endCreated) {
    var _self = {
        name: name,
        startModified: utils.copy(startModified),
        endModified: utils.copy(endModified),
        endCreated: utils.copy(endCreated)
    };

    return _self;
};

FileSystemStorage = function (label, type, state) {
    var _self = {
        label: label,
        type: type,
        state: state
    };

    return _self;
};

module.exports = {
    maxPathLength: _maxPathLength,
    resolve: function (srcLocation, onSuccess, onError, accessMode) {
        function _resolve() {
            var _mode = accessMode ? String(accessMode) : _defaultMode;

            if (_mode === "r" || _mode === "rw") {
                _resolveAsync(onSuccess, onError, String(srcLocation), _mode);
                return null;
            } else {
                if (onError) {
                    setTimeout(function () {
                        onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                    }, 1);
                }
            }
            return undefined;
        }

        return tizen1_utils.validateTypeMismatch(onSuccess, onError, "resolve", _resolve);
    },

    getStorage: function (label, onSuccess, onError) {
        var i, storage = null, _label = String(label);

        _storages.some(function (value) {
            if (value.label === _label) {
                storage = utils.copy(value);
                setTimeout(function () {
                    onSuccess(storage);
                }, 1);
                return true;
            }
        });

        if (!storage) {
            if(onError) {
                setTimeoout(function () {
                    onError(new WebAPIError(errorcode.NOT_FOUND_ERR));
                }, 1);

            } else {
                throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }
        }
    },

    listStorages: function (onSuccess, onError) {
        function _listStorages() {
            setTimeout(function () {
                onSuccess(utils.copy(_storages));
            }, 1);
        }

        return tizen1_utils.validateTypeMismatch(onSuccess, onError, "listStorages", _listStorages);
    },

    addStorageStateChangeListener: function(onSuccess, onError) {
        function _addStorageStateChangeListener() {
            var watchId = (new Date()).getTime() || 0;
            _observers[watchId] = function(storage) {//storage is which state is changed
		        onSuccess(storage);
		    };

            // This event should be triggered from outside
		    event.on("StateChange", _observers[watchId]);
		    return Number(watchId);
        }

        return tizen1_utils.validateTypeMismatch(onSuccess, onError, "addStorageStateChangeListener", _addStorageStateChangeListener);
    },

    removeStorageStateChangeListener: function (watchId) {
        if (!watchId || typeof watchId !== "number") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }
        watchId = String(watchId);

        if (_observers[watchId]) {
            event.deleteEventHandler("StateChange", _observers[watchId]);
            delete _observers[watchId];
        } else {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }
    },

    handleSubFeatures: function (subFeatures) {
        function setSecurity(_security) {
            return function (method) {
                _security[method] = true;
            };
        }

        for (var subFeature in subFeatures) {
            if (_security[subFeature].length === 0) {
                _security.all = true;
                return;
            }
            _security.all = false;
            utils.forEach(_security[subFeature], setSecurity);
        }
    }
};


});
define('ripple/platform/tizen/2.0/CalendarAlarm', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    TZDate = require('ripple/platform/tizen/2.0/TZDate'),
    TimeDuration = require('ripple/platform/tizen/2.0/TimeDuration'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    _alarmMethods = ["SOUND", "DISPLAY"];

module.exports = function (triggerTime, method, description) {
    var absoluteDate = null,
        before = null,
        isValid = false,
        _self;

    if (triggerTime instanceof TZDate) {
        absoluteDate = new TZDate(triggerTime);
    } else if (triggerTime instanceof TimeDuration) {
        before = triggerTime;
    } else {
        throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }

    isValid = utils.arrayContains(_alarmMethods, method);
    if (!isValid)
        throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

    if (method.equals("DISPLAY") && description === null)
        throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

    _self.absoluteDate = absoluteDate;
    _self.before       = before;
    _self.method       = method;
    _self.description  = description;

    return _self;
};

});
define('ripple/platform/tizen/2.0/GeocodeResult', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates');

module.exports = function (lat, lon) {
    var _self, _coordinates, jsonStr, jsonObj;

    _coordinates = new SimpleCoordinates(lat, lon);

    jsonObj = { 
        "type" : "Point",
        "coordinates" : [lat, lon]
    };

    jsonStr = JSON.stringify(jsonObj);

    _self = {
        coordinates : _coordinates,
        toGeoJSON : function () {
            return jsonStr;
        }
    };
    return _self;
};


});
define('ripple/platform/tizen/2.0/CalendarTask', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var TZDate = require('ripple/platform/tizen/2.0/TZDate'),
    CalendarItem = require('ripple/platform/tizen/2.0/CalendarItem'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates');

module.exports = function (taskInitDict) {
    var _self;

    _self = new CalendarItem("TASK");

    if ((taskInitDict !== undefined) && (taskInitDict !== null)) {
        _self.dueDate       = tizen1_utils.isValidTZDate(taskInitDict.dueDate) ? (new TZDate(new Date(taskInitDict.dueDate))) : undefined;
        _self.completedDate = tizen1_utils.isValidTZDate(taskInitDict.completedDate) ? (new TZDate(new Date(taskInitDict.completedDate))) : undefined;
        _self.progress      = ((0 <= taskInitDict.progress) && (taskInitDict.progress <= 100)) ? Number(taskInitDict.progress) : 0;

        if (taskInitDict.description) {
            _self.description = String(taskInitDict.description);
        }
        if (taskInitDict.summary) {
            _self.summary = String(taskInitDict.summary);
        }
        if (taskInitDict.isAllDay && (typeof taskInitDict.isAllDay === "boolean")) {
            _self.isAllDay = taskInitDict.isAllDay;
        }
        if (taskInitDict.startDate && tizen1_utils.isValidTZDate(taskInitDict.startDate)) {
            _self.startDate = taskInitDict.startDate;
        }
        if (taskInitDict.duration && (typeof taskInitDict.duration === "object")) {
            _self.duration = new TZDate(new Date(taskInitDict.duration));
        }
        if (taskInitDict.location) {
            _self.location = String(taskInitDict.location);
        }
        if (taskInitDict.geolocation && taskInitDict.geolocation.latitude && taskInitDict.geolocation.longitude) {
            _self.geolocation = new SimpleCoordinates(taskInitDict.geolocation.latitude, taskInitDict.geolocation.longitude);
        }
        if (taskInitDict.organizer) {
            _self.organizer = String(taskInitDict.organizer);
        }
        if (taskInitDict.visibility) {
            _self.visibility = String(taskInitDict.visibility);
        }
        if (taskInitDict.status) {
            _self.status = String(taskInitDict.status);
        }
        if (taskInitDict.priority) {
            _self.priority = String(taskInitDict.priority);
        }
        if (taskInitDict.alarms && tizen1_utils.isValidArray(taskInitDict.alarms)) {
            var isInvalid = false;
            taskInitDict.alarms.some(function (alarm) {
                if (!alarm || alarm.method === undefined) {// 'method' is CalendarAlarm's property.
                    isInvalid = true;
                    return;
                }
            });
            if (!isInvalid) {
                _self.alarms = taskInitDict.alarms;
            }
        }
        if (taskInitDict.categories && tizen1_utils.isValidArray(taskInitDict.categories)) {
            var isInvalid = false;
            taskInitDict.categories.every(function (categorie) {
                if (!categorie || typeof categorie !== "string") {
                    isInvalid = true;
                    return;
                }
            });
            if (!isInvalid) {
                _self.categories = taskInitDict.categories;
            }
        }
        if (taskInitDict.attendees && tizen1_utils.isValidArray(taskInitDict.attendees)) {
            var isInvalid = false;
            taskInitDict.attendees.some(function (attendee) {
                if (!attendee || attendee.uri === undefined) {// 'uri' is CalendarAttendee's property.
                    isInvalid = true;
                    return;
                }
            });
            if (!isInvalid) {
                _self.attendees = taskInitDict.attendees;
            }
        }
    } else {
        _self.dueDate       = undefined;
        _self.completedDate = undefined;
        _self.progress      = 0;
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/POIFilter', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (attributeName, value) {
    var _self;

    _self = {
        attributeName: attributeName,
        value: value
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/contact', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    Contact = require('ripple/platform/tizen/2.0/ContactBase'),
    ContactName = require('ripple/platform/tizen/2.0/ContactName'),
    ContactOrganization = require('ripple/platform/tizen/2.0/ContactOrganization'),
    ContactWebSite = require('ripple/platform/tizen/2.0/ContactWebSite'),
    ContactAnniversary = require('ripple/platform/tizen/2.0/ContactAnniversary'),
    ContactAccount = require('ripple/platform/tizen/2.0/ContactAccount'),
    ContactAddress = require('ripple/platform/tizen/2.0/ContactAddress'),
    ContactPhoneNumber = require('ripple/platform/tizen/2.0/ContactPhoneNumber'),
    ContactEmailAddress = require('ripple/platform/tizen/2.0/ContactEmailAddress'),
    PendingObject = require('ripple/platform/tizen/2.0/pendingObject'),
    PendingOperation = require('ripple/platform/tizen/2.0/pendingoperation'),
    _self,
    _KEY = "tizen1-contact",
    _security = {
        "http://tizen.org/api/contact": [],
        "http://tizen.org/api/contact.read": ["find", "addChangeListener"],
        "http://tizen.org/api/contact.write": ["add", "addBatch", "update", "updateBatch", 
        "remove", "removeBatch"],
        all: true
    },
    _addressBooks = [],
    _PENDING_TIME = 10;

function _pendingOperate(operate) {
    var pendingObj, pendingOperation, i, argumentVector = [];

    for (i = 0; i < arguments.length - 1; i++) {
        argumentVector[i] = arguments[i + 1];
    }

    pendingObj = new PendingObject();

    pendingObj.pendingID = window.setTimeout(function () {
        pendingObj.setCancelFlag(false);
        operate.apply(this, argumentVector);
    }, _PENDING_TIME);

    pendingOperation = new PendingOperation(pendingObj);

    return pendingOperation;
}

function _validateCallbackType(onSuccess, onError, callback) {
    if (onSuccess) {
        tizen1_utils.validateArgumentType(onSuccess, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }
    if (onError) {
        tizen1_utils.validateArgumentType(onError, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }

    return callback && callback();
}

function _checkContactProperties(prop, checkIDEmpty) {
    var i;

    if (prop) {
        if (checkIDEmpty === true) {
            /* id should not be exist */
            if (prop.id !== null && prop.id !== undefined) {
                return false;
            }
        } else {
            if (typeof prop.id !== "string") {
                return false;
            }
        }

        /* if prop.addresses exists, it must be a array */
        if (prop.addresses && !tizen1_utils.isValidArray(prop.addresses)) {
            return false;
        }

        /* if prop.phoneNumbers exists, it must be a array */
        if (prop.phoneNumbers && !tizen1_utils.isValidArray(prop.phoneNumbers)) {
            return false;
        }

        /* if prop.emails exists, it must be a array */
        if (prop.emails && !tizen1_utils.isValidArray(prop.emails)) {
            return false;
        }

        /* if prop.birthday exists, its type is Date */
        if (prop.birthday && !tizen1_utils.isValidDate(prop.birthday)) {
            return false;
        }

        /* if prop.anniversaries exists, it must be a array */
        if (prop.anniversaries && !tizen1_utils.isValidArray(prop.anniversaries)) {
            for (i = 0; i < prop.anniversaries; i++) {
                if (tizen1_utils.isValidDate(prop.anniversaries[i].date)) {
                    return false;
                }
            }
        }

        /* if prop.notes exists, it must be a array */
        if (prop.notes && !tizen1_utils.isValidArray(prop.notes)) {
            return false;
        }

        /* if prop.urls exists, it must be a array */
        if (prop.urls && !tizen1_utils.isValidArray(prop.urls)) {
            return false;
        }

        /* if prop.isFavorite exists, its type is boolean */
        if (prop.isFavorite && typeof prop.isFavorite !== "boolean") {
            return false;
        }

        /* if prop.ringtoneURI exists, its type is string */
        if (prop.ringtoneURI && typeof prop.ringtoneURI !== "string") {
            return false;
        }

        /* if prop.categories exists, it must be a array */
        if (prop.categories && !tizen1_utils.isValidArray(prop.categories)) {
            return false;
        }
    }

    /* pass all check */
    return true;
}

/* check filter type (it's a recursive function)
   0: It is not a filter
   1: CompositeFilter
   2: AttributeFilter
   3: AttributeRangeFilter
 */
function _filterType(filter) {
    var i = 0, ret;

    if (Object.prototype.toString.call(filter) !== "[object Object]") {
        return 0; // 0: it is not a filter
    }

    /* check if it is CompositFilter or not */
    if (filter.type !== null && filter.type !== undefined) {
        /* attribute 'type' of CompositeFilter must be "UNION" or "INTERSECTION" */
        if (filter.type === "UNION" || filter.type === "INTERSECTION") {
            /*attribute 'filters' of CompositeFilter must be AbstractFilter array */
            if (tizen1_utils.isValidArray(filter.filters)) {
                for (i = 0; i < filter.filters.length; i++) {
                    /* recursive call */
                    if (_filterType(filter.filters[i]) === 0) {
                        return 0; // 0: it is not a filter
                    }
                }
            } else {
                return 0; // 0: it is not a filter
            }
        } else {
            return 0; // 0: it is not a filter
        }
        return 1; // CompositeFilter
    }

    /* AttributeFilter or AttributeRangeFilter must have attributeName */
    if (filter.attributeName === null || filter.attributeName === undefined) {
        return 0; // 0: it is not a filter
    } else {
        ret = 2; // assume it is an AttributeFilter
        if ((filter.initialValue !== null || filter.initialValue !== undefined) ||
            (filter.endValue !== null || filter.endValue !== undefined)) {
            ret = 3; // AttributeRangeFilter
        }
        return ret;
    }
}

function ContactPublic(prop) {
    var _self;

    if (typeof prop.id !== "string") {
        return undefined;
    }
    if (!tizen1_utils.isValidDate(prop.lastUpdated)) {
        return undefined;
    }
    _self = new Contact(prop);

    _self.__defineGetter__("id", function () {
        return prop.id;
    });
    _self.__defineGetter__("lastUpdated", function () {
        return prop.lastUpdated;
    });
    return _self;
}

function ContactPrivate(prop, newID) {
    var _self;
    _self = new Contact(prop);
    if (newID === true) {
        _self.id = Math.uuid(undefined, 16);
    } else {
        _self.id = prop.id;
    }
    _self.lastUpdated = new Date();
    return _self;
}

function AddressBook(id, name, readOnly, contacts) {
    var addressBook;
    
    addressBook = {
        _contacts : contacts,
        _listenerCount : 0,
        _listeners : {},
        get : function (id) {
            if (typeof id !== "string") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            if (this._contacts[id]) {
                return new ContactPublic(this._contacts[id]);
            } else {
                throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }
        },
        add : function (contact) {
            var item, item2;
            if (!_security.all && !_security.add) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (Object.prototype.toString.call(contact) !== "[object Object]") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            if (this.readOnly === true) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (_checkContactProperties(contact, true) === false) {
                throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
            }
            item = new ContactPrivate(contact, true);
            this._contacts[item.id] = item;
            _save();

            contact.id = item.id;
            contact.lastUpdated = item.lastUpdated;

            /* send changed notification */
            utils.forEach(this._listeners, function (listenerCB) {
                item2 = new ContactPublic(item);
                listenerCB.oncontactsadded([item2]);
            });
        },
        addBatch : function (contacts, successCB, errorCB) {
            var inner = this, 
                item, item2, listenArray;
            function _addBatch() {
                var ret, i;
                if (!_security.all && !_security.addBatch) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                if (!tizen1_utils.isValidArray(contacts)) {
                    throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                } else {
                    if (contacts.length === 0) {
                        throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                    }
                    for (i = 0; i < contacts.length; i++) {
                        if (_checkContactProperties(contacts[i], true) === false) {
                            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                        }
                    }
                }
                if (inner.readOnly === true) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                ret = _pendingOperate(function () {
                    var i;
                    for (i = 0; i < contacts.length; i++) {
                        item = new ContactPrivate(contacts[i], true);
                        contacts[i] = new ContactPublic(item);
                        inner._contacts[item.id] = item;
                    }
                    _save();
                    if (successCB) {
                        successCB(contacts);
                    }

                    /* send changed notification */
                    utils.forEach(inner._listeners, function (listenerCB) {
                        listenArray = [];
                        for (i = 0; i < contacts.length; i++) {
                            item2 = new ContactPublic(contacts[i]);
                            listenArray.push(item2);
                        }
                        listenerCB.oncontactsadded(listenArray);
                    });
                });
                return;
            }

            _validateCallbackType(successCB, errorCB, _addBatch);
        },
        update : function (contact) {
            var item, item2, inner = this;
            if (!_security.all && !_security.update) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (Object.prototype.toString.call(contact) !== "[object Object]") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            if (this.readOnly === true) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (_checkContactProperties(contact, false) === false) {
                throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
            }
            if (contact.id && this._contacts[contact.id]) {
                item = new ContactPrivate(contact, false);
                this._contacts[item.id] = item;
                _save();
            } else {
                throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }

            /* send changed notification */
            utils.forEach(this._listeners, function (listenerCB) {
                item2 = new ContactPublic(inner._contacts[contact.id]);
                listenerCB.oncontactsupdated([item2]);
            });
        },
        updateBatch : function (contacts, successCB, errorCB) {
            var inner = this, 
                item, listenArray, item2;
            function _updateBatch() {
                var ret, i;
                if (!_security.all && !_security.updateBatch) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                if (!tizen1_utils.isValidArray(contacts)) {
                    throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                } else {
                    if (contacts.length === 0) {
                        throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                    }
                    for (i = 0; i < contacts.length; i++) {
                        if (_checkContactProperties(contacts[i], false) === false) {
                            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                        }
                    }
                }
                if (inner.readOnly === true) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                ret = _pendingOperate(function () {
                    var i;
                    for (i = 0; i < contacts.length; i++) {
                        if (!contacts[i].id || !inner._contacts[contacts[i].id]) {
                            if (errorCB) {
                                errorCB(new WebAPIError(errorcode.NOT_FOUND_ERR));
                            }
                            return;
                        }
                    }
                    for (i = 0; i < contacts.length; i++) {
                        item = new ContactPrivate(contacts[i], false);
                        inner._contacts[item.id] = item;
                    }
                    _save();
                    if (successCB) {
                        successCB();
                    }

                    /* send changed notification */
                    utils.forEach(inner._listeners, function (listenerCB) {
                        listenArray = [];
                        for (i = 0; i < contacts.length; i++) {
                            item2 = new ContactPublic(inner._contacts[contacts[i].id]);
                            listenArray.push(item2);
                        }
                        listenerCB.oncontactsupdated(listenArray);
                    });
                });
                return;
            }

            _validateCallbackType(successCB, errorCB, _updateBatch);
        },
        remove : function (id) {
            if (!_security.all && !_security.remove) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (typeof id !== "string") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            if (this.readOnly === true) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (this._contacts[id]) {
                delete this._contacts[id];
                _save();
            } else {
                throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }

            /* send changed notification */
            utils.forEach(this._listeners, function (listenerCB) {
                listenerCB.oncontactsremoved([id]);
            });
        },
        removeBatch : function (ids, successCB, errorCB) {
            var inner = this;
            function _removeBatch() {
                var ret, i;
                if (!_security.all && !_security.removeBatch) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                if (!tizen1_utils.isValidArray(ids)) {
                    throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                } else {
                    if (ids.length === 0) {
                        throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                    }
                    for (i = 0; i < ids.length; i++) {
                        if (typeof ids[i] !== "string") {
                            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                        }
                    }
                }

                if (inner.readOnly === true) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                ret = _pendingOperate(function () {
                    var i;
                    for (i = 0; i < ids.length; i++) {
                        if (!inner._contacts[ids[i]]) {
                            if (errorCB) {
                                errorCB(new WebAPIError(errorcode.NOT_FOUND_ERR));
                            }
                            return;
                        }
                    }
                    for (i = 0; i < ids.length; i++) {
                        if (inner._contacts[ids[i]]) {
                            delete inner._contacts[ids[i]];
                        }
                    }
                    _save();
                    if (successCB) {
                        successCB();
                    }

                    /* send changed notification */
                    utils.forEach(inner._listeners, function (listenerCB) {
                        listenerCB.oncontactsremoved(ids);
                    });
                });
                return;
            }

            _validateCallbackType(successCB, errorCB, _removeBatch);
        },
        find : function (successCB, errorCB, filter, sortMode) {
            var inner = this;

            function _find() {
                var result = [], result2 = [], begin, end, ret, i,
                    atr, _re, errFlag = false, _rangeMatch, low, high, matched,
                    _existMatch, _arrayMatch;

                if (!_security.all && !_security.find) {
                    throw new WebAPIError(errorcode.SECURITY_ERR);
                }

                if (filter) {
                    switch (_filterType(filter)) {
                    case 0:
                        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                    case 1:
                        //TODO:
                        //"compositeFilter doesn't support"
                        throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
                    case 2:
                    case 3:
                        break;
                    }
                }

                /* return all contacts if no filter argument */
                if (filter === null || filter === undefined) {
                    utils.forEach(inner._contacts, function (contact) {
                        result.push(new ContactPublic(contact));
                    });
                    ret = _pendingOperate(function () {
                        successCB(result);
                    });
                    return ret;
                }

                /* check composition of filter.attributeName */
                switch (filter.attributeName) {
                case "id" :
                case "name.prefix" :
                case "name.firstName" :
                case "name.middleName" :
                case "name.lastName" :
                case "name.phoneticName" :
                case "name.displayName" :
                case "account.accountServiceId" :
                case "account.contactURI" :
                case "photoURI" :
                case "organization.name" :
                case "organization.department" :
                case "organization.office" :
                case "organization.title" :
                case "organization.role" :
                case "organization.logoURI" :
                case "ringtoneURI" :
                    result = tizen1_utils.matchAttributeFilter(inner._contacts,
                            filter.attributeName, filter.matchFlag, filter.matchValue);
                    break;
                case "name.nicknames" :
                case "notes" :
                case "categories" :
                    result = tizen1_utils.matchAttributeArrayFilter(inner._contacts,
                            filter.attributeName, filter.matchFlag, filter.matchValue);
                    break;
                case "addresses.country" :
                case "addresses.region" :
                case "addresses.city" :
                case "addresses.streetAddress" :
                case "addresses.additionalInformation" :
                case "addresses.postalCode" :
                case "phoneNumbers.number" :
                case "emails.email" :
                case "anniversaries.label" :
                case "urls.url" :
                case "urls.type" :
                    atr = filter.attributeName.split(".");
                    _existMatch = function (obj, index) {
                        return (obj[atr[0]] !== undefined);
                    };

                    if (filter.matchValue === undefined || filter.matchFlag === "EXISTS") {
                        result = utils.filter(inner._contacts, _existMatch);
                        break;
                    }

                    errFlag = false;

                    switch (filter.matchFlag)
                    {
                    case "EXACTLY":
                        _re = new RegExp("^" + filter.matchValue + "$");
                        break;
                    case "FULLSTRING":
                        _re = new RegExp("^" + filter.matchValue + "$", "i");
                        break;
                    case "CONTAINS":
                        _re = new RegExp(filter.matchValue, "i");
                        break;
                    case "STARTSWITH":
                        _re = new RegExp("^" + filter.matchValue, "i");
                        break;
                    case "ENDSWITH":
                        _re = new RegExp(filter.matchValue + "$", "i");
                        break;
                    default:
                        errFlag = true;
                    }

                    if (errFlag) {
                        result = [];
                        break;
                    }

                    _arrayMatch = function (obj, index) {
                        return (obj[atr[0]].some(function (o) {
                            if (typeof o[atr[1]] !== "string") {
                                return false;
                            } else {
                                return (o[atr[1]].search(_re) !== -1);
                            }
                        }));
                    };

                    result = utils.filter(inner._contacts, _arrayMatch);
                    break;
                case "addresses.types" :
                case "phoneNumbers.types" :
                case "emails.types" :
                    atr = filter.attributeName.split(".");
                    _existMatch = function (obj, index) {
                        return (obj[atr[0]].some(function (o) {
                            return (o[atr[1]] !== undefined);
                        }));
                    };

                    if (filter.matchValue === undefined || filter.matchFlag === "EXISTS") {
                        result = utils.filter(inner._contacts, _existMatch);
                        break;
                    }

                    errFlag = false;

                    switch (filter.matchFlag)
                    {
                    case "EXACTLY":
                        _re = new RegExp("^" + filter.matchValue + "$");
                        break;
                    case "FULLSTRING":
                        _re = new RegExp("^" + filter.matchValue + "$", "i");
                        break;
                    case "CONTAINS":
                        _re = new RegExp(filter.matchValue, "i");
                        break;
                    case "STARTSWITH":
                        _re = new RegExp("^" + filter.matchValue, "i");
                        break;
                    case "ENDSWITH":
                        _re = new RegExp(filter.matchValue + "$", "i");
                        break;
                    default:
                        errFlag = true;
                    }

                    if (errFlag) {
                        result = [];
                        break;
                    }

                    _arrayMatch = function (obj, index) {
                        return (obj[atr[0]].some(function (o) {
                            if (!tizen1_utils.isValidArray(o[atr[1]])) {
                                return false;
                            } else {
                                return (o[atr[1]].some(function (t) {
                                    return (t.search(_re) !== -1);
                                }));
                            }
                        }));
                    };

                    result = utils.filter(inner._contacts, _arrayMatch);
                    break;
                case "anniversaries.date" :
                    low = filter.initialValue;
                    high = filter.endValue;
                    atr = filter.attributeName.split(".");

                    if (low !== undefined && low !== null) {
                        if (!tizen1_utils.isValidDate(low)) {
                            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                        }
                    }
                    if (high !== undefined && high !== null) {
                        if (!tizen1_utils.isValidDate(high)) {
                            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                        }
                    }

                    _rangeMatch = function (obj, index) {
                        matched = true;
                        if (low !== null && low !== undefined) {
                            if (!tizen1_utils.isValidArray(obj[atr[0]])) {
                                matched = false;
                            } else {
                                matched = (obj[atr[0]].some(function (o) {
                                    return (o[atr[1]] >= low);
                                }));
                            }
                        }
                        if (matched && (high !== null && high !== undefined)) {
                            if (!tizen1_utils.isValidArray(obj[atr[0]])) {
                                matched = false;
                            } else {
                                matched = (obj[atr[0]].some(function (o) {
                                    return (o[atr[1]] <= high);
                                }));
                            }
                        }
                        return matched;
                    };

                    result = utils.filter(inner._contacts, _rangeMatch);
                    break;
                case "isFavorite" :
                    if (filter.matchFlag !== "EXACTLY" || typeof filter.matchValue !== "boolean") {
                        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                    } else {
                        result = tizen1_utils.matchAttributeBooleanFilter(inner._contacts,
                                filter.attributeName, filter.matchValue);
                    }
                    break;
                case "birthday" :
                    begin = filter.initialValue;
                    end = filter.endValue;

                    if (begin !== null && begin !== undefined) {
                        if (!tizen1_utils.isValidDate(begin)) {
                            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                        }
                    }

                    if (end !== null && end !== undefined) {
                        if (!tizen1_utils.isValidDate(end)) {
                            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                        }
                    }
                    
                    result = tizen1_utils.matchAttributeRangeFilter(inner._contacts,
                            filter.attributeName, begin, end);
                    break;
                default:
                    throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
                }
                ret = _pendingOperate(function () {
                    for (i = 0; i < result.length; i++) {
                        result2.push(new ContactPublic(result[i]));
                    }
                    successCB(result2);
                });
                return ret;
            }

            tizen1_utils.validateTypeMismatch(successCB, errorCB, "find", _find);
        },
        addChangeListener : function (successCB, errorCB) {
            var inner = this,
                id;

            if (!_security.all && !_security.addChangeListener) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            if (Object.prototype.toString.call(successCB) === "[object Object]") {
                /* oncontactsadded, oncontactsupdated, oncontactsremoved all are not optional */
                if (typeof successCB.oncontactsadded !== "function" ||
                    typeof successCB.oncontactsupdated !== "function" ||
                    typeof successCB.oncontactsremoved !== "function") {
                    throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                }
            } else {
                /* AddressBookChangedCB is not a set of functions */
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

            if (errorCB) {
                if (typeof errorCB !== "function") {
                    throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
                }
            }

            id = ++inner._listenerCount;
            inner._listeners[id] = successCB;
            return id;
        },
        removeChangeListener : function (id) {
            if (typeof id !== "number") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            
            if (this._listeners[id]) {
                delete this._listeners[id];
            }
        }
    };

    addressBook.__defineGetter__("id", function () {
        return id;
    });

    addressBook.__defineGetter__("name", function () {
        return name;
    });

    addressBook.__defineGetter__("readOnly", function () {
        return readOnly;
    });

    return addressBook;
}

function _get() {
    var array = [],
        data = db.retrieveObject(_KEY);

    utils.forEach(data, function (addrBook) {
        var i, j;
        for (i in addrBook._contacts) {
            if (addrBook._contacts[i].lastUpdated !== undefined &&
                addrBook._contacts[i].lastUpdated !== null) {
                addrBook._contacts[i].lastUpdated = new Date(addrBook._contacts[i].lastUpdated);
            }
            if (addrBook._contacts[i].birthday !== undefined &&
                addrBook._contacts[i].birthday !== null) {
                addrBook._contacts[i].birthday = new Date(addrBook._contacts[i].birthday);
            }
            if (addrBook._contacts[i].anniversaries &&
                tizen1_utils.isValidArray(addrBook._contacts[i].anniversaries)) {
                for (j = 0; j < addrBook._contacts[i].anniversaries.length; j++) {
                    // Skip checking "date" exist or not due to it is mandatory 
                    addrBook._contacts[i].anniversaries[j].date = new Date(addrBook._contacts[i].anniversaries[j].date);
                }
            }
        }
        array.push(new AddressBook(addrBook.id, addrBook.name, addrBook.readOnly, addrBook._contacts));
    });

    /* add default addressbook if database is empty */
    if (array.length === 0) {
        array = [new AddressBook(Math.uuid(undefined, 16), "Phone address book", false, {}), 
                 new AddressBook(Math.uuid(undefined, 16), "SIM address book", false, {})];
    }

    return array;
}

function _save() {
    db.saveObject(_KEY, _addressBooks);
}

_self = function () {
    var contact = {
        getAddressBooks: function (successCB, errorCB) {
            function _getAddressBooks() {
                if (_addressBooks.length === 0) {
                    _addressBooks = _get();
                }
                successCB(_addressBooks);
            }
            tizen1_utils.validateTypeMismatch(successCB, errorCB, "getAddressBooks", _getAddressBooks);
        },

        getDefaultAddressBook: function () {
            if (_addressBooks.length === 0) {
                _addressBooks = _get();
            }
            return _addressBooks[0];
        },

        getAddressBook: function (id) {
            var i;
            if (typeof id !== "string") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            if (_addressBooks.length === 0) {
                _addressBooks = _get();
            }
            for (i = 0; i < _addressBooks.length; i++) {
                if (_addressBooks[i].id === id) {
                    return _addressBooks[i];
                }
            }

            /* Cannot found */
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);
        },

        handleSubFeatures: function (subFeatures) {
            var i, subFeature;
            for (subFeature in subFeatures) {
                if (_security[subFeature].length === 0) {
                    _security.all = true;
                    return;
                }
                _security.all = false;
                for (i = 0; i < _security[subFeature].length; i++) {
                    _security[_security[subFeature][i]] = true;
                }
            }
        }
    };

    return contact;
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/AttributeRangeFilter', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

module.exports = function (_attributeName, _initialValue, _endValue) {
    return {
        attributeName: _attributeName,
        initialValue: _initialValue,
        endValue: _endValue
    };
};

});
define('ripple/platform/tizen/2.0/geocoder', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    ProviderLocal = require('ripple/platform/tizen/2.0/geoBackend_local'),
    ProviderNominatim = require('ripple/platform/tizen/2.0/geoBackend_nominatim'), // Nominatim geocode service
    _getProviders,
    _providers,
    _self;

function _initialize() {
    _providers = [new ProviderNominatim({name : "Nominatim", connectivity : "ONLINE"})
                  /* ,new ProviderLocal({name : "Tizen Database", connectivity : "OFFLINE"}) */];
}

_initialize();

_self = {
    getDefaultProvider : function () {
        return _providers[0];
    },
    getProviders : function () {
        return _providers;
    }
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/systeminfo', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    deviceSettings = require('ripple/deviceSettings'),
    event = require('ripple/event'), 
    tizen_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    _systemInfoProperties = ["Power", "Cpu", "Storage", "Display", "Device", "Network", "WifiNetwork", "CellularNetwork", "EthernetNetwork", "SIM"],
    _propertyMap = {}, // Object like: {"Power": ["level", "isCharging"], ...}
    _watches = {},
    _powerData = {},
    _self;

function _asynchErrorCallback(errorCallback, errorCode) {
    if (errorCallback) {
        setTimeout(function () {
            errorCallback(errorCode);
        }, 1);
    }
}

function _getValue(aspect, successCallback, errorCallback) {
    var properties = [], value, index = 0, property, obj = {};

    if (aspect === "Power") {
        successCallback(utils.copy(_powerData));
        return;
    }

    properties = _propertyMap[aspect];
    for (; index < properties.length; index++) {
        property = properties[index];

        value = deviceSettings.retrieve(aspect + "." + property);
        if (value === undefined || value === null) {

            errorCallback(new WebAPIError(errorcode.SECURITY_ERR));
            return null;
        }

        obj[property] = value;
    }

    successCallback(obj);
}

function _initialize() {
    var aspectName, index, i;

    for (index = 0; index < _systemInfoProperties.length; index++) {
        aspectName = _systemInfoProperties[index];
        _propertyMap[aspectName] = [];
        for (i in deviceSettings.retrieve(aspectName)) {
            _propertyMap[aspectName].push(i);
        }
    }

    _propertyMap.Power.push("level");
    _propertyMap.Power.push("isCharging");

    event.on("BatteryEvent", function (status) {
        _powerData.isCharging = status.charging;
        _powerData.level = status.level;
    });
}

function _isPropertyFound(propertyId) {
    if (tizen_utils.isEmptyObject(_propertyMap)) {
        _initialize();
    }

    if (_propertyMap[propertyId]) {
        return true;
    }

    return false;
}

_self = {
    isSupported: function (propertyId) {
        return _isPropertyFound(propertyId);
    },

    getPropertyValue: function (propertyId, successCallback, errorCallback) {
        return tizen_utils.validateTypeMismatch(successCallback, errorCallback, "getPropertyValue", function () {
            if (_isPropertyFound(propertyId) === false) {
                _asynchErrorCallback(errorCallback, new WebAPIError(errorcode.NOT_FOUND_ERR));
                return undefined;
            }

            setTimeout(_getValue(propertyId, successCallback, errorCallback), 1); // Simulate a async operation

            return null;
        });
    },

    addPropertyValueChangeListener: function (propertyId, successCallback, errorCallback, options) {  
        return tizen_utils.validateTypeMismatch(successCallback, errorCallback, "addPropertyValueChangeListener", function () {
            if (_isPropertyFound(propertyId) === false) {
                _asynchErrorCallback(errorCallback, new WebAPIError(errorcode.NOT_FOUND_ERR));
                return undefined;
            }

            var watchId = (new Date()).getTime() | 0,
                _options = Object(options),
                properties, property, index = 0, deviceEventType, watchObj;

            // A listener will listen all the properties of one aspect, each of the property
            // will have an internal watchObj to record the information.
            _watches[watchId] = [];

            // Immediately returns and then asynchronously starts a watch ...
            setTimeout(function () {
                _getValue(propertyId, successCallback, errorCallback);

                properties = _propertyMap[propertyId];
                
                for (; index < properties.length; index++) {
                    property = properties[index];
                    if (propertyId === "Power") {
                        deviceEventType = "BatteryEvent";
                    }
                    else {
                        deviceEventType = deviceSettings.retrieve(propertyId)[property].event;
                    }

                    // These two items are needed when delete an event listener.
                    watchObj = {
                        eventType: deviceEventType,
                        onEvent: function (newValue) {
                            if (watchObj.timeout) {
                                clearInterval(watchObj.intervalId);
                                watchObj.intervalId = setInterval(function () {
                                    _getValue(propertyId, successCallback, errorCallback);
                                }, watchObj.timeout);
                            }

                            if ((watchObj.highThreshold && (newValue < watchObj.highThreshold)) ||
                                (watchObj.lowThreshold && (newValue > watchObj.lowThreshold))) {
                                return;
                            }

                            _getValue(propertyId, successCallback, errorCallback);
                        }
                    };

                    if (options && _options.timeout) {
                        watchObj.intervalId = setInterval(function () {
                            _getValue(propertyId, successCallback, errorCallback);
                        }, _options.timeout);
                    }

                    if (options && _options.highThreshold) {
                        watchObj.highThreshold = _options.highThreshold;
                    }

                    if (options && _options.lowThreshold) {
                        watchObj.lowThreshold = _options.lowThreshold;
                    }
                
                    _watches[watchId].push(watchObj);
                    if (watchObj.eventType) {
                        event.on(watchObj.eventType, watchObj.onEvent);
                    }
                }

            }, 1);

            return watchId;
        });
    },

    removePropertyChangeListener: function (listenerID) {
        var _handler = listenerID | 0, index = 0, watchObjs = [], watchObj;

        watchObjs = _watches[_handler];
        if (watchObjs) {
            for (; index < watchObjs.length; index++) {
                watchObj = watchObjs[index];
                event.deleteEventHandler(watchObj.eventType, watchObj.onEvent);
                if (watchObj.intervalId) {
                    clearInterval(watchObj.intervalId);
                }
            }
            delete(_watches[_handler]);
        }
        return null;
    }
};

module.exports = _self;


});
define('ripple/platform/tizen/2.0/ContactBase', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    ContactName = require('ripple/platform/tizen/2.0/ContactName'),
    ContactOrganization = require('ripple/platform/tizen/2.0/ContactOrganization'),
    ContactWebSite = require('ripple/platform/tizen/2.0/ContactWebSite'),
    ContactAnniversary = require('ripple/platform/tizen/2.0/ContactAnniversary'),
    ContactAccount = require('ripple/platform/tizen/2.0/ContactAccount'),
    ContactAddress = require('ripple/platform/tizen/2.0/ContactAddress'),
    ContactPhoneNumber = require('ripple/platform/tizen/2.0/ContactPhoneNumber'),
    ContactEmailAddress = require('ripple/platform/tizen/2.0/ContactEmailAddress');

function _clone(obj) {
    var copy = obj.constructor(), attr;
    for (attr in obj) {
        if (obj.hasOwnProperty(attr))
            copy[attr] = obj[attr];
    }
    /* remove these two attribute */
    copy.id = null;
    copy.lastUpdated = null;
    return copy;
}

module.exports = function (prop) {
    var _self, i;
    _self = {
        id : null,
        lastUpdated : null,
        name : null,
        account : null,
        addresses : [],
        photoURI : null,
        phoneNumbers : undefined,
        emails : undefined,
        birthday : null,
        anniversaries : null,
        organization : null,
        notes : [],
        urls : [],
        isFavorite : false,
        ringtoneURI : null,
        categories : [],
        convertToString : function (format) {
            //TODO
            console.log("convert to VCard String...");
        },
        clone : function () {
            return _clone(this);
        },
    };
    
    if (prop) {
        /* id: (readonly)
        By default, this attribute is set to null.
        This attribute will be generated when adding to the AddressBook */

        /* lastUpdated: (readonly)
        By default, this attribute is set to null.
        This attribute will be generated when adding to the AddressBook */

        if (prop.name) {
            _self.name = new ContactName(prop.name);
        }
        if (prop.account) {
            _self.account = new ContactAccount(prop.account.accountServiceId, prop.account.contactURI);
        }
        if (tizen1_utils.isValidArray(prop.addresses)) {
            for (i = 0; i < prop.addresses.length; i++) {
                _self.addresses.push(new ContactAddress(prop.addresses[i]));
            }
        }
        if (prop.photoURI) {
            _self.photoURI = String(prop.photoURI);
        }
        if (tizen1_utils.isValidArray(prop.phoneNumbers)) {
            _self.phoneNumbers = [];
            for (i = 0; i < prop.phoneNumbers.length; i++) {
                _self.phoneNumbers.push(new ContactPhoneNumber(
                            prop.phoneNumbers[i].number, prop.phoneNumbers[i].types));
            }
        }
        if (tizen1_utils.isValidArray(prop.emails)) {
            _self.emails = [];
            for (i = 0; i < prop.emails.length; i++) {
                _self.emails.push(new ContactEmailAddress(
                            prop.emails[i].email, prop.emails[i].types));
            }
        }
        if (tizen1_utils.isValidDate(prop.birthday)) {
            _self.birthday = new Date(prop.birthday);
        }
        if (tizen1_utils.isValidArray(prop.anniversaries)) {
            _self.anniversaries = [];
            for (i = 0; i < prop.anniversaries.length; i++) {
                _self.anniversaries.push(new ContactAnniversary(
                            prop.anniversaries[i].date, prop.anniversaries[i].label));
            }
        }
        if (prop.organization) {
            _self.organization = new ContactOrganization(prop.organization);
        }
        if (tizen1_utils.isValidArray(prop.notes)) {
            for (i = 0; i < prop.notes.length; i++) {
                _self.notes.push(String(prop.notes[i]));
            }
        }
        if (tizen1_utils.isValidArray(prop.urls)) {
            for (i = 0; i < prop.urls.length; i++) {
                _self.urls.push(new ContactWebSite(
                            prop.urls[i].url, prop.urls[i].type));
            }
        }
        if (typeof prop.isFavorite === "boolean") {
            _self.isFavorite = prop.isFavorite;
        }
        if (prop.ringtoneURI) {
            _self.ringtoneURI = String(prop.ringtoneURI);
        }
        if (tizen1_utils.isValidArray(prop.categories)) {
            for (i = 0; i < prop.categories.length; i++) {
                _self.categories.push(String(prop.categories[i]));
            }
        }
    }
    
    return _self;
};

});
define('ripple/platform/tizen/2.0/Conversation', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"),
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils');

module.exports = function (opt) {
    var conv = {}, priv = utils.copy(opt);

    conv.__defineGetter__("id", function () {
        return priv.id;
    });
    conv.__defineGetter__("type", function () {
        return priv.type;
    });
    conv.__defineGetter__("timestamp", function () {
        return priv.timestamp;
    });
    conv.__defineGetter__("messageCount", function () {
        return priv.messageCount;
    });
    conv.__defineGetter__("unreadMessages", function () {
        return priv.unreadMessages;
    });
    conv.__defineGetter__("preview", function () {
        return priv.preview;
    });
    conv.__defineGetter__("subject", function () {
        return priv.subject;
    });
    conv.__defineGetter__("isRead", function () {
        return priv.isRead;
    });
    conv.__defineGetter__("from", function () {
        return priv.from;
    });
    conv.__defineGetter__("to", function () {
        return priv.to;
    });
    conv.__defineGetter__("cc", function () {
        return priv.cc;
    });
    conv.__defineGetter__("bcc", function () {
        return priv.bcc;
    });
    conv.__defineGetter__("lastMessageId", function () {
        return priv.lastMessageId;
    });
    return conv;
};

});
define('ripple/platform/tizen/2.0/GeoRectBounds', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (_southWest, _northEast) {
    var southWest, northEast;
    southWest = _southWest || null;
    northEast = _northEast || null;

    this.__defineGetter__("southWest", function () {
        return southWest;
    });

    this.__defineGetter__("northEast", function () {
        return northEast;
    });
};

});
define('ripple/platform/tizen/2.0/URLDownload', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (url, destination, fileName) {
    var _self;
    _self = {
        url: url || null,
        destination: destination || null,
        fileName: fileName || null
    };
    return _self;
};

});
define('ripple/platform/tizen/2.0/PowerStateRequest', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (resource, state) {
    var _self,
        _state = state || null,
        _resource = resource || null;

    _self = {
        resource : _resource,
        minimalState : _state
    };
    return _self;
};

});
define('ripple/platform/tizen/2.0/EventBase', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function () {
    var _self = {
        CAPTURING_PHASE: 1,
        AT_TARGET:  2,
        BUBBLING_PHASE: 3,

        type: '',
        target: null, //new EventTarget(),
        currentTarget: null, //new EventTarget(),
        eventPhase: 0,
        bubbles: false,
        cancelable: false,
        timeStamp: 0
    };

    this.__defineGetter__("type", function () {
        return _self.type;
    });

    this.__defineGetter__("target", function () {
        return _self.target;
    });

    this.__defineGetter__("currentTarget", function () {
        return _self.currentTarget;
    });

    this.__defineGetter__("eventPhase", function () {
        return _self.eventPhase;
    });

    this.__defineGetter__("bubbles", function () {
        return _self.bubbles;
    });

    this.__defineGetter__("cancelable", function () {
        return _self.cancelable;
    });

    this.__defineGetter__("timeStamp", function () {
        return _self.timeStamp;
    });

    this.stopPropagation = function () {};

    this.preventDefault = function () {};

    this.initEvent = function (eventTypeArg, canBubbleArg, cancelableArg) {
        _self.type = eventTypeArg;
        _self.bubbles = canBubbleArg;
        _self.cancelable = cancelableArg;

        _self.timeStamp = (new Date()).getTime();
    };

    return _self;
};


});
define('ripple/platform/tizen/2.0/ContactRef', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (addressBookId, contactId) {
    var _self, _addressBookId,
        _contactId;
    
    if (typeof addressBookId !== "string") {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }

    if (typeof contactId !== "string") {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }

    _self = {
        addressBookId : _addressBookId,
        contactId : _contactId
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/timezone_info', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _self,
    _timezone_data = {
    "Samoa": {diff: -11, abbr: "WST"},
    "Hawaii": {diff: -10, abbr: "HAST"},
    "Alaska": {diff: -9, abbr: "AKST"},
    "Baja California": {diff: -8, abbr: "PST"},
    "Arizona": {diff: -7, abbr: "MST"},
    "Chihuahua, La Paz, Mazatlan": {diff: -7, abbr: "MST"},
    "Guadalajara, Mexico City, Monterrey": {diff: -6, abbr: "CST"},
    "Bogota, Lima, Quito": {diff: -5, abbr: "PET"},
    "Asuncion": {diff: -4, abbr: "PYST"},
    "Cuiaba": {diff: -4, abbr: "AMST"},
    "Georgetown, La Paz, Manaus, San Juan": {diff: -4, abbr: "BOT"},
    "Santiago": {diff: -4, abbr: "CLST"},
    "Brasilia": {diff: -3, abbr: "BRST"},
    "Buenos Aires": {diff: -3, abbr: "ART"},
    "Cayenne, Fortaleza": {diff: -3, abbr: "GFT"},
    "Greenland": {diff: -3, abbr: "WGT"},
    "Montevideo": {diff: -3, abbr: "UYST"},
    "Azores": {diff: -1, abbr: "AZOT"},
    "Casablanca": {diff: 0, abbr: "UTC"},
    "Coordinated Universal Time": {diff: 0, abbr: "UTC"},
    "Dublin, Edinburgh, Lisbon, London": {diff: 0, abbr: "UTC"},
    "Monrovia, Reykjavik": {diff: 0, abbr: "UTC"},
    "Amsterdam, Berlin, Bern": {diff: 1, abbr: "CET"},
    "Rome, Stockholm, Vienna": {diff: 1, abbr: "CET"},
    "Belgrade, Bratislava, Budapest": {diff: 1, abbr: "CET"},
    "Ljubljana, Prague": {diff: 1, abbr: "CET"},
    "Brussels, Copenhagen, Madrid, Paris": {diff: 1, abbr: "CET"},
    "Sarajevo, Skopje, Warsaw, Zagreb": {diff: 1, abbr: "CET"},
    "Windhoek": {diff: 1, abbr: "WAST"},
    "Amman": {diff: 2, abbr: "EEST"},
    "Athens, Bucharest": {diff: 2, abbr: "EET"},
    "Beirut": {diff: 2, abbr: "EET"},
    "Cairo": {diff: 2, abbr: "EET"},
    "Damascus": {diff: 2, abbr: "EET"},
    "Harare, Pretoria": {diff: 2, abbr: "SAST"},
    "Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius": {diff: 2, abbr: "EET"},
    "Istanbul": {diff: 2, abbr: "EET"},
    "Jerusalem": {diff: 2, abbr: "IST"},
    "Baghdad": {diff: 3, abbr: "AST"},
    "Kuwait, Riyadh": {diff: 3, abbr: "AST"},
    "Nairobi": {diff: 3, abbr: "EAT"},
    "Abu Dhabi, Muscat": {diff: 4, abbr: "GST"},
    "Baku": {diff: 4, abbr: "AZT"},
    "Moscow, St. Petersburg, Volgograd": {diff: 4, abbr: "MSK"},
    "Tbilisi": {diff: 4, abbr: "GET"},
    "Yerevan": {diff: 4, abbr: "AMT"},
    "Islamabad, Karachi": {diff: 5, abbr: "PKT"},
    "Tashkent": {diff: 5, abbr: "UZT"},
    "Astana": {diff: 6, abbr: "ALMT"},
    "Dhaka": {diff: 6, abbr: "BST"},
    "Ekaterinburg": {diff: 6, abbr: "YEKT"},
    "Bangkok, Hanoi, Jakarta": {diff: 7, abbr: "ICT"},
    "Novosibirsk": {diff: 7, abbr: "NOVT"},
    "Beijing, Chongqing, Hong Kong, Urumqi": {diff: 8, abbr: "CST"},
    "Krasnoyarsk": {diff: 8, abbr: "KRAT"},
    "Kuala Lumpur, Singapore": {diff: 8, abbr: "SGT"},
    "Perth": {diff: 8, abbr: "WST"},
    "Taipei": {diff: 8, abbr: "CST"},
    "Ulaanbaatar": {diff: 8, abbr: "ULAT"},
    "Irkutsk": {diff: 9, abbr: "IRKT"},
    "Osaka, Sapporo, Tokyo": {diff: 9, abbr: "JST"},
    "Seoul": {diff: 9, abbr: "KST"},
    "Brisbane": {diff: 10, abbr: "EST"},
    "Canberra, Melbourne, Sydney": {diff: 10, abbr: "EST"},
    "Guam, Port Moresby": {diff: 10, abbr: ""},
    "Hobart": {diff: 10, abbr: "EDT"},
    "Yakutsk": {diff: 10, abbr: "YAKT"},
    "Solomon Is., New Caledonia": {diff: 11, abbr: "SBT"},
    "Vladivostok": {diff: 11, abbr: "VLAT"},
    "Auckland, Wellington": {diff: 12, abbr: "NZDT"},
    "Fiji": {diff: 12, abbr: "FJST"},
    "Magadan": {diff: 12, abbr: "MAGT"}
};

module.exports = {
    getAllTimezone: function () {
        var i, ret = [];
        for (i in _timezone_data)
            ret.push(i);
        return ret;
    },
    getTimezoneDiff: function (zone) {
        return _timezone_data[zone].diff;
    },
    getTimezoneAbbr: function (zone) {
        return _timezone_data[zone].abbr;
    },
    isValidTimezone: function (zone) {
        return (_timezone_data[zone] === undefined) ? false : true;
    }
};


});
define('ripple/platform/tizen/2.0/bluetooth', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    db = require('ripple/db'),
    event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    BluetoothDevice = require('ripple/platform/tizen/2.0/BluetoothDevice'),
    BluetoothClassDeviceMajor = require('ripple/platform/tizen/2.0/BluetoothClassDeviceMajor'),
    BluetoothClassDeviceMinor = require('ripple/platform/tizen/2.0/BluetoothClassDeviceMinor'),
    BluetoothClassDeviceService = require('ripple/platform/tizen/2.0/BluetoothClassDeviceService'),
    BluetoothServiceHandler = require('ripple/platform/tizen/2.0/BluetoothServiceHandler'),
    BluetoothAdapter,
    _data = {
        DB_BLUETOOTH_KEY : "tizen1-db-bluetooth_adapter-name",
        DEFAULT_ADAPTER_NAME: "Tizen BT Adapter",
        DEFAULT_ADAPTER_ADDRESS: "12:34:56:78:90:AB",
        availableDevsChanging : false,
        DEFAULT_VISIBLE_TIME : 180000,
        DISCOVER_TIME : 10000,
        DISCOVER_INTERVAL : 1000,
        bluetoothClassDeviceMajor : {},
        bluetoothClassDeviceMinor : {},
        bluetoothClassDeviceService : {},
        adapter : {},
        historyDevs : {},
        availableDevs : {},
        localServices : {},
    },
    _security = {
        "http://tizen.org/api/bluetooth": [],
        "http://tizen.org/api/bluetooth.admin": ["setName", "setPowered", "setVisible"],
        "http://tizen.org/api/bluetooth.gap": ["discoverDevices", "stopDiscovery", "getKnownDevices", "getDevice", "createBonding", "destroyBonding"],
        "http://tizen.org/api/bluetooth.spp": ["registerRFCOMMServiceByUUID", "connectToServiceByUUID", "unregister", "writeData", "readData", "close"],
        all: true
    },
    _self;

function _initialize() {
    var adapterName;

    _data.bluetoothClassDeviceMajor = new BluetoothClassDeviceMajor();
    _data.bluetoothClassDeviceMinor = new BluetoothClassDeviceMinor();
    _data.bluetoothClassDeviceService = new BluetoothClassDeviceService();
    adapterName = db.retrieveObject(_data.DB_BLUETOOTH_KEY) || _data.DEFAULT_ADAPTER_NAME;
    _data.adapter = new BluetoothAdapter(adapterName, _data.DEFAULT_ADAPTER_ADDRESS);
}

function _validateDiscoverDevicesType(onSuccess, onError) {
    if (typeof onSuccess !== "object") {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }
    if (onError) {
        tizen1_utils.validateArgumentType(onError, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }
    tizen1_utils.validateArgumentType(onSuccess.onstarted, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    tizen1_utils.validateArgumentType(onSuccess.ondevicefound, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    tizen1_utils.validateArgumentType(onSuccess.ondevicedisappeared, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    tizen1_utils.validateArgumentType(onSuccess.onfinished, "function",
            new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
}

BluetoothAdapter = function (devName, devAddress) {
    var adapter,
        timeoutVar,
        _devName = devName,
        _devAddress = devAddress,
        _devPowered = false,
        _devVisible = false,
        _isDiscovering = false,
        discoverInterval;

    // private
    function _updatePowerStatus(status) {
        if (_devPowered === status) {
            return;
        }
        if (!status) {
            _updateVisibleStatus(false);
            utils.forEach(_data.historyDevs, function (dev) {
                event.trigger("bt-service-state-update", [dev.address, false]);
                Object.defineProperty(dev, "isBonded", {value: false, writable: false});
                event.trigger("bt-device-bonded-changed", [dev.address, false]);
                jQuery("#service-transfer-textarea-" + dev.address.replace(/:/g, "")).val("");
                jQuery("#service-receive-textarea-" + dev.address.replace(/:/g, "")).html("");
            });
        }
        _devPowered = status;
        event.trigger("bt-adapter-power-changed", [_devPowered]);
    }

    function _updateVisibleStatus(status, time) {
        if (!_devPowered)
            return;
        _devVisible = status;
        event.trigger("bt-adapter-visible-changed", [_devVisible]);
        if (_devVisible) {
            if (time > 0) {
                timeoutVar = setTimeout(function () {
                    _devVisible = false;
                    event.trigger("bt-adapter-visible-changed", [_devVisible]);
                }, time);
            }
        } else {
            clearTimeout(timeoutVar);
        }
    }

    // public
    function setName(name, successCallback, errorCallback) {
        if (!_security.all && !_security.setName) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (typeof name !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        _devName = name;
        db.saveObject(_data.DB_BLUETOOTH_KEY, _devName);
        event.trigger("bt-adapter-name-changed", [_devName]);
        if (successCallback) {
            successCallback();
        }
    }

    function setPowered(state, successCallback, errorCallback) {
        if (!_security.all && !_security.setPowered) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (typeof state !== "boolean") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        _updatePowerStatus(state);
        if (successCallback) {
            successCallback();
        }
    }

    function setVisible(mode, successCallback, errorCallback, timeout) {
        var time;

        if (!_security.all && !_security.setVisible) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (typeof mode !== "boolean") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        if (typeof timeout === "number") {
            if (timeout < 0) {
                time = _data.DEFAULT_VISIBLE_TIME;
            } else {
                time = timeout * 1000;
            }
        } else {
            time = _data.DEFAULT_VISIBLE_TIME;
        }
        _updateVisibleStatus(mode, time);
        if (successCallback) {
            successCallback();
        }
    }

    function discoverDevices(successCallback, errorCallback) {
        var interval;

        if (!_security.all && !_security.discoverDevices) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        _validateDiscoverDevicesType(successCallback, errorCallback);

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        // already discovering
        if (_isDiscovering) {
            return;
        }
        _isDiscovering = true;
        _data.historyDevs = {};

        successCallback.onstarted();
        _data.availableDevsChanging = false;
        utils.forEach(_data.availableDevs, function (item) {
            _data.historyDevs[item.address] = item;
            successCallback.ondevicefound(utils.copy(item));
        });

        discoverInterval = setTimeout(function () {
            var devs = [];
            clearInterval(interval);
            utils.forEach(_data.historyDevs, function (item) {
                devs.push(utils.copy(item));
            });
            successCallback.onfinished(devs);
            _isDiscovering = false;
        }, _data.DISCOVER_TIME);

        interval = setInterval(function () {
            var removeList = [], i;
            if (!_isDiscovering) {
                clearInterval(interval);
                return;
            }

            if (_data.availableDevsChanging === true) {
                _data.availableDevsChanging = false;
                utils.forEach(_data.historyDevs, function (item) {
                    if (!_data.availableDevs[item.address]) {
                        removeList.push(item.address);
                    }
                });
                for (i in removeList) {
                    successCallback.ondevicedisappeared(removeList[i]);
                    delete _data.historyDevs[removeList[i]];
                }
                utils.forEach(_data.availableDevs, function (item) {
                    if (!_data.historyDevs[item.address]) {
                        _data.historyDevs[item.address] = item;
                        successCallback.ondevicefound(utils.copy(item));
                    }
                });
            }
        }, _data.DISCOVER_INTERVAL);
    }

    function stopDiscovery(successCallback, errorCallback) {
        if (!_security.all && !_security.stopDiscovery) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        if (_isDiscovering) {
            clearTimeout(discoverInterval);
        }
        _isDiscovering = false;
        if (successCallback) {
            successCallback();
        }
    }

    function getKnownDevices(successCallback, errorCallback) {
        var devs = [];

        if (!_security.all && !_security.getKnownDevices) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        tizen1_utils.validateArgumentType(successCallback, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        if (errorCallback) {
            tizen1_utils.validateArgumentType(errorCallback, "function",
                    new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }
        utils.forEach(_data.historyDevs, function (item) {
            devs.push(utils.copy(item));
        });
        successCallback(devs);
    }

    function getDevice(address, successCallback, errorCallback) {
        if (!_security.all && !_security.getDevice) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (typeof address !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        tizen1_utils.validateArgumentType(successCallback, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        if (errorCallback) {
            tizen1_utils.validateArgumentType(errorCallback, "function",
                    new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        if (_data.historyDevs[address]) {
            successCallback(utils.copy(_data.historyDevs[address]));
        } else {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
        }
    }

    function createBonding(address, successCallback, errorCallback) {
        if (!_security.all && !_security.createBonding) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (typeof address !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        tizen1_utils.validateArgumentType(successCallback, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        if (errorCallback) {
            tizen1_utils.validateArgumentType(errorCallback, "function",
                    new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        if (_data.historyDevs[address]) {
            Object.defineProperty(_data.historyDevs[address], "isBonded", {value: true, writable: false});
            event.trigger("bt-device-bonded-changed", [address, true]);
            successCallback(utils.copy(_data.historyDevs[address]));
        } else if (errorCallback) {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
        }
    }

    function destroyBonding(address, successCallback, errorCallback) {
        if (!_security.all && !_security.destroyBonding) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (typeof address !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        tizen1_utils.validateCallbackType(successCallback, errorCallback);

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        if (_data.historyDevs[address]) {
            event.trigger("bt-service-state-update", [address, false]);
            Object.defineProperty(_data.historyDevs[address], "isBonded", {value: false, writable: false});
            event.trigger("bt-device-bonded-changed", [address, false]);
            if (successCallback) {
                successCallback();
            }
        } else if (errorCallback) {
            errorCallback(new WebAPIError(errorcode.NOT_FOUND_ERR));
        }
    }

    function registerRFCOMMServiceByUUID(uuid, name, successCallback, errorCallback, securityLevel) {
        if (!_security.all && !_security.registerRFCOMMServiceByUUID) {
            throw new WebAPIError(errorcode.SECURITY_ERR);
        }

        if (typeof name !== "string" || typeof uuid !== "string") {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }

        tizen1_utils.validateArgumentType(successCallback, "function",
                new WebAPIError(errorcode.TYPE_MISMATCH_ERR));

        if (errorCallback) {
            tizen1_utils.validateArgumentType(errorCallback, "function",
                    new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (securityLevel) {
            if (securityLevel !== "LOW" && securityLevel !== "MEDIUM" && securityLevel !== "HIGH") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
        }

        if (!_devPowered) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.SERVICE_NOT_AVILABLE_ERR));
            }
            return;
        }

        _data.localServices[uuid] = new BluetoothServiceHandler({uuid: uuid, name: name, isConnected: false, metaData: _security});
        successCallback(_data.localServices[uuid]);
    }

    event.on("bt-simulated-devices-changed", function () {
        var devs = db.retrieveObject("bt-simulated-devices");
        utils.forEach(_data.availableDevs, function (item) {
            if (!devs[item.address]) {
                delete _data.availableDevs[item.address];
            }
        });
        utils.forEach(devs, function (item) {
            if (!_data.availableDevs[item.address]) {

                _data.availableDevs[item.address] = new BluetoothDevice({
                    name: item.name,
                    address: item.address,
                    deviceClass: item.deviceClass,
                    isBonded: false,
                    isTrusted: item.isTrusted,
                    isConnected: false,
                    services: item.services,
                    metaData: _security
                });
            }
        });
        _data.availableDevsChanging = true;
    });

    event.on("bt-unregister-service", function (uuid, successCallback, errorCallback) {
        if (!_data.localServices[uuid]) {
            if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
            return;
        }
        delete _data.localServices[uuid];
        if (successCallback) {
            successCallback();
        }
    });

    adapter = {
        setName : setName,
        setPowered : setPowered,
        setVisible : setVisible,
        discoverDevices : discoverDevices,
        stopDiscovery : stopDiscovery,
        getKnownDevices : getKnownDevices,
        getDevice : getDevice,
        createBonding : createBonding,
        destroyBonding : destroyBonding,
        registerRFCOMMServiceByUUID : registerRFCOMMServiceByUUID
    };

    adapter.__defineGetter__("name", function () {
        return _devName;
    });
    adapter.__defineGetter__("address", function () {
        return _devAddress;
    });
    adapter.__defineGetter__("powered", function () {
        return _devPowered;
    });
    adapter.__defineGetter__("visible", function () {
        return _devVisible;
    });

    return adapter;
};

_initialize();

_self = function () {
    function getDefaultAdapter() {
        if (arguments.length > 0)
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (!_data.adapter)
            throw new WebAPIError(errorcode.UNKNOWN_ERR);

        return _data.adapter;
    }

    function handleSubFeatures(subFeatures) {
        for (var subFeature in subFeatures) {
            if (_security[subFeature].length === 0) {
                _security.all = true;
                return;
            }
            _security.all = false;
            utils.forEach(_security[subFeature], function (method) {
                _security[method] = true;
            });
        }
    }

    var bluetooth = {
        getDefaultAdapter : getDefaultAdapter,
        handleSubFeatures : handleSubFeatures
    };

    bluetooth.__defineGetter__("deviceMajor", function () {
        return _data.bluetoothClassDeviceMajor;
    });
    bluetooth.__defineGetter__("deviceMinor", function () {
        return _data.bluetoothClassDeviceMinor;
    });
    bluetooth.__defineGetter__("deviceService", function () {
        return _data.bluetoothClassDeviceService;
    });

    return bluetooth;
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/StatusNotification', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var NotificationBase = require('ripple/platform/tizen/2.0/NotificationBase'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    _self;

function _checkServiceProperties(service) {
    if (typeof service !== "object") {
        return false;
    }

    if (typeof service.operation !== "string") {
        return false;
    }

    if (service.uri && typeof service.uri !== "string") {
        return false;
    }

    if (service.mime && typeof service.mime !== "string") {
        return false;
    }

    if (service.data && !tizen1_utils.isValidArray(service.data)) {
        return false;
    }

    if (typeof service.replyResult !== "function") {
        return false;
    }

    if (typeof service.replyFailure !== "function") {
        return false;
    }

    return true;
}

function _checkDictProperties(dict) {
    if (dict) {
        if (typeof dict !== "object") {
            return false;
        }

        if (dict.content && typeof dict.content !== "string") {
            return false;
        }

        if (dict.iconPath && typeof dict.iconPath !== "string") {
            return false;
        }

        if (dict.soundPath && typeof dict.soundPath !== "string") {
            return false;
        }

        if (dict.vibration && typeof dict.vibration !== "boolean") {
            return false;
        }

        if (dict.service && !_checkServiceProperties(dict.service)) {
            return false;
        }

        if (dict.progressValue && typeof dict.progressValue !== "number") {
            return false;
        }
    }
    return true;
}

_self = function (_statusType, title, notificationInitDict) {
    var statusType,
        notification;

    if (typeof _statusType !== "string" || !(_statusType === "SIMPLE" || _statusType === "ONGOING" || _statusType === "PROGRESS") ||
        typeof title !== "string" ||
        !_checkDictProperties(notificationInitDict)) {
        throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }

    if (notificationInitDict && _statusType === "PROGRESS" && notificationInitDict.progressValue &&
        (notificationInitDict.progressValue < 1 || notificationInitDict.progressValue > 100)) {
        throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
    }

    statusType = _statusType;
    notification = new NotificationBase(title);
    notification.__defineGetter__("statusType", function () {
        return statusType;
    });

    if (notificationInitDict) {
        notification.content = notificationInitDict.content ? notificationInitDict.content : undefined;
        notification.iconPath = notificationInitDict.iconPath ? notificationInitDict.iconPath : undefined;
        notification.soundPath = notificationInitDict.soundPath ? notificationInitDict.soundPath : undefined;
        notification.vibration = notificationInitDict.vibration !== undefined ? notificationInitDict.vibration : undefined;
        notification.service = notificationInitDict.service ? notificationInitDict.service : undefined;
        notification.progressValue = (statusType === "PROGRESS" && notificationInitDict.progressValue) ? notificationInitDict.progressValue : undefined;
    }

    return notification;
};

module.exports = _self;
});
define('ripple/platform/tizen/2.0/pendingObject', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (pendingObj) {
    var cancelFlag = true;
    this.setCancelFlag = function (flag) {
        cancelFlag = flag;
    };
    this.getCancelFlag = function () {
        return cancelFlag;
    };
    this.userCancel = null;
    this.pendingID = null;
};

});
define('ripple/platform/tizen/2.0/download', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    filesystem = require('ripple/platform/tizen/2.0/filesystem'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    DownloadState = {
        QUEUED: "QUEUED",
        DOWNLOADING: "DOWNLOADING",
        PAUSED: "PAUSED",
        ABORTED: "ABORTED",
        COMPLETED: "COMPLETED",
        FAILED: "FAILED"
    },
    DB_DOWNLOAD_KEY = "tizen1-db-download",
    DownloadItem, _isInitialized = false, INTERVAL = 1000,
    _downloads = [], _resources = [], _self;

function _checkDownloadParamters(download, callback) {
    if (download === undefined || download === null || download.url === null) {
        throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }
    if (callback !== undefined && callback !== null &&
        (typeof callback.onprogress !== 'function' ||
         typeof callback.onpaused !== 'function' ||
         typeof callback.onaborted !== 'function' ||
         typeof callback.oncompleted !== 'function' ||
         typeof callback.onfailed !== 'function')) {
        throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
    }
}

function _initDownloadItem(download) {
    var url, index, isExist = false;
    url = download.url;
    if (download.destination === null) {
        download.destination = "downloads";
    }
    if (download.fileName === null) {
        index = url.lastIndexOf('\/') + 1;
        download.fileName = url.substring(index);
    }
    if (!_isInitialized) {
        initializeResource();
    }
    _resources.some(function (value) {
        if (value.url === url) {
            download.size           = value.size;
            download.speed          = Number(value.speed);
            download.estimatedTime = Math.round(value.estimatedTime * 100) / 100;
            isExist =  true;
            return;
        }
    });
    if (!isExist) {
        _exec(download.callback, 'onfailed', download.id, new WebAPIError(errorcode.NOT_FOUND_ERR));
        return;
    }
    return download;
}

function _exec(callback, name, downloadId, arg1, arg2) {
    if (callback === null) {
        return;
    }
    switch (name) {
    case "onprogress" :
        callback[name](downloadId, arg1, arg2);
        break;
    case "onpaused" :
        callback[name](downloadId);
        break;
    case "onaborted" :
        callback[name](downloadId);
        break;
    case "oncompleted" :
        callback[name](downloadId, arg1);
        break;
    case "onfailed" :
        callback[name](downloadId, arg1);
        break;
    default:
        break;
    }
}

function _getDownloadObjById(id) {
    var isFound = false, backObj;
    if (id === null || id === undefined) {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }
    id = Number(id);
    _downloads.some(function (obj) {
        if (obj.id === id) {
            backObj = obj;
            isFound = true;
            return;
        }
    });
    if (!isFound) {
        throw new WebAPIError(errorcode.NOT_FOUND_ERR);
    }
    return backObj;
}

function initializeResource() {
    _resources = db.retrieveObject(DB_DOWNLOAD_KEY);
    _isInitialized = true;
}

function _saveFile(downloadObj, callback) {
    var name, path, content;

    name = downloadObj.fileName;
    path = downloadObj.destination;
    content = 'size|' + downloadObj.size + ',speed|' + downloadObj.speed + ',url|' + downloadObj.url + ',estimatedTime|' + downloadObj.estimatedTime;
    function onsuccess(fs) {
        fs.write(content);
        fs.close();
    }
    function onerror(e) {
        _exec(downloadObj.callback, 'onfailed', downloadObj.id, e);
    }
    function rename(name) { //index.html==>index_1.html
        var index, c;
        index = name.lastIndexOf('.');
        if (index < 0) {
            index = name.length;
        }
        c = name.substr(index - 2, 1);
        if (c === '_') {
            name = name.substr(0, index - 1) + (Number(name.substr(index - 1, 1)) + 1) + name.substring(index);
        } else {
            name = name.substr(0, index) + "_1" + name.substring(index);
        }
        return name;
    }

    filesystem.resolve(path, function (dir) {
        var file, isExist = true;
        while (isExist) {
            try {
                file = dir.resolve(name);
                name = rename(name);
            } catch (e) {
                isExist = false;
            }
        }
        file = dir.createFile(name);
        file.openStream('w', onsuccess, onerror, 'UTF-8');
        callback(name);
    }, onerror, "rw");
}

DownloadItem = function (download, callback) {
    var _self;
    _self = {
        id           : Number(Math.uuid(8, 10)),
        url          : download.url,
        state        : DownloadState.QUEUED,
        fileName     : download.fileName || null,
        destination  : download.destination || null,
        callback     : callback || null
    };
    return _self;
};

_self = {
    start: function (download, downloadCallback) {
        var downloadObj, fileSize, increment, receivedSize = 0, intervalId;

        _checkDownloadParamters(download, downloadCallback);
        downloadObj = new DownloadItem(download, downloadCallback);
        downloadObj = _initDownloadItem(downloadObj);
        downloadObj.state = DownloadState.DOWNLOADING;
        _downloads.push(downloadObj);

        fileSize = downloadObj.size;
        increment = downloadObj.speed;
        intervalId = setInterval(function () {
            if (receivedSize >= fileSize) {//Finish downloading
                receivedSize = fileSize;
                _saveFile(downloadObj, function (fileName) {
                    _exec(downloadObj.callback, 'oncompleted', downloadObj.id, fileName);
                });
                clearInterval(intervalId);
            } else { // Continue downloading
                receivedSize += increment;
                downloadObj.receivedSize = receivedSize;
                _exec(downloadObj.callback, 'onprogress', downloadObj.id, receivedSize, fileSize);
            }
        }, INTERVAL);
        downloadObj.intervalId = intervalId;
        return downloadObj.id;
    },

    abort: function (downloadId) {
        var downloadObj = _getDownloadObjById(downloadId);
        clearInterval(downloadObj.intervalId);
        downloadObj.state = DownloadState.ABORTED;
        _exec(downloadObj.callback, 'onaborted', downloadObj.id);
    },

    pause: function (downloadId) {
        var downloadObj = _getDownloadObjById(downloadId);
        clearInterval(downloadObj.intervalId);
        downloadObj.state = DownloadState.PAUSED;
        _exec(downloadObj.callback, 'onpaused', downloadObj.id);
    },

    resume: function (downloadId) {
        var downloadObj, fileSize, receivedSize, increment, intervalId;

        downloadObj  = _getDownloadObjById(downloadId);
        fileSize     = downloadObj.size;
        receivedSize = downloadObj.receivedSize;
        increment    = downloadObj.speed;

        if (downloadObj.state !== DownloadState.PAUSED) {
            _exec(downloadObj.callback, 'onfailed', downloadObj.id, new WebAPIError(errorcode.INVALID_VALUES_ERR));
            return;
        }
        downloadObj.state = DownloadState.DOWNLOADING;
        intervalId = setInterval(function () {
            if (receivedSize >= fileSize) {//Finish downloading
                receivedSize = fileSize;
                _saveFile(downloadObj, function (fileName) {
                    _exec(downloadObj.callback, 'oncompleted', downloadObj.id, fileName);
                });
                clearInterval(intervalId);
            } else {// Continue downloading
                receivedSize += increment;
                downloadObj.receivedSize = receivedSize;
                _exec(downloadObj.callback, 'onprogress', downloadObj.id, receivedSize, fileSize);
            }
        }, INTERVAL);
        downloadObj.intervalId = intervalId;
    },

    getState: function (downloadId) {
        var downloadObj = _getDownloadObjById(downloadId);
        return downloadObj.state;
    }

};

event.on('downloadResourceChanged', function () {
    _isInitialized = false;
});
module.exports = _self;


});
define('ripple/platform/tizen/2.0/time', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var TZDate = require('ripple/platform/tizen/2.0/TZDate'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    db = require('ripple/db'),
    tz = require('ripple/platform/tizen/2.0/timezone_info'),
    _timeFormat = "h:m:s ap", _shortDateFormat = "d/m/y",
    _longDateFormat = "D, M d y", _self;

_self = {
    getCurrentDateTime: function () {
        return new TZDate();
    },
    setCurrentDateTime: function (dt) {
        throw new WebAPIError(errorcode.NOT_SUPPORTED_ERR);
    },
    getLocalTimezone: function () {
        var tz = db.retrieve("tizen-timezone") || "Coordinated Universal Time";
        return tz;
    },
    getAvailableTimezones: function () {
        var ret = tz.getAllTimezone();
        return ret;
    },
    getDateFormat: function (shortformat) {
        if (shortformat !== undefined && shortformat !== null &&
            typeof shortformat !== 'boolean') {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }
        if (shortformat) {
            return _shortDateFormat;
        } else {
            return _longDateFormat;
        }
    },
    getTimeFormat: function () {
        return _timeFormat;
    },
    isLeapYear: function (year) {
        if (typeof year !== 'number') {
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }
        return ((year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0));
    }
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/messaging', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _self, service, i,
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    MessagingService = require('ripple/platform/tizen/2.0/MessagingService'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    TIZEN_MESSAGING_SMS = "messaging.sms",
    TIZEN_MESSAGING_MMS = "messaging.mms",
    TIZEN_MESSAGING_EMAIL = "messaging.email",
    _security_check = {send: false, read: false, write: false},
    _sms_service = null,
    _mms_service = null,
    _email_service = null;

_self = function () {
    this.getMessageServices = function (messageServiceType, onSuccess, onError, serviceId) {
        var _getMsgServices, ret = [];

        if (serviceId !== null && serviceId !== undefined &&
            typeof serviceId !== 'string') {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (typeof messageServiceType !== 'string') {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        _getMsgServices = function () {
            switch (messageServiceType) {
            case "messaging.sms":
                if (_sms_service === null) {
                    _sms_service = [new MessagingService("Tizen SMS Service 1", "SMS Service Name 1", TIZEN_MESSAGING_SMS, _security_check), new MessagingService("Tizen SMS Service 2", "SMS Service Name 2", TIZEN_MESSAGING_SMS, _security_check)];
                }
                service = _sms_service;
                break;
            case "messaging.mms":
                if (_mms_service === null) {
                    _mms_service = [new MessagingService("Tizen MMS Service", "MMS Service Name", TIZEN_MESSAGING_MMS, _security_check)];
                }
                service = _mms_service;
                break;
            case "messaging.email":
                if (_email_service === null) {
                    _email_service = [new MessagingService("Tizen Email Service", "Email Service Name", TIZEN_MESSAGING_EMAIL, _security_check)];
                }
                service = _email_service;
                break;
            default:
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
            }
            if ((serviceId !== null) && (serviceId !== undefined)) {
                for (i = 0; i < service.length; i++) {
                    if (service[i].id === serviceId) {
                        ret.push(service[i]);
                    }
                }
                if (ret.length === 0) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                } else {
                    setTimeout(function () {
                        onSuccess(ret);
                    }, 1);
                }
            } else {
                setTimeout(function () {
                    onSuccess(service);
                }, 1);
            }
        };
        return tizen1_utils.validateTypeMismatch(onSuccess, onError,
                   "messaging:getMessageServices", _getMsgServices);
    };
    this.handleSubFeatures = function (subFeatures) {
        if (tizen1_utils.isEmptyObject(subFeatures) ||
            subFeatures["http://tizen.org/api/messaging"]) {
            // all ok
            _security_check.send = true;
            _security_check.read = true;
            _security_check.write = true;
            return;
        }
        if (subFeatures["http://tizen.org/api/messaging.send"]) {
            _security_check.send = true;
        }
        if (subFeatures["http://tizen.org/api/messaging.read"]) {
            _security_check.send = true;
        }
        if (subFeatures["http://tizen.org/api/messaging.write"]) {
            _security_check.send = true;
        }
    };
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/calendar', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    db = require('ripple/db'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    TZDate = require('ripple/platform/tizen/2.0/TZDate'),
    CalendarItem = require('ripple/platform/tizen/2.0/CalendarItem'),
    CalendarEvent = require('ripple/platform/tizen/2.0/CalendarEvent'),
    CalendarTask = require('ripple/platform/tizen/2.0/CalendarTask'),
    CalendarRecurrenceRule = require('ripple/platform/tizen/2.0/CalendarRecurrenceRule'),
    Calendar,
    CalendarStorage,
    CalendarItemsStorage,
    _DB_CALENDARS_KEY = "tizen1-db-calendars",
    _watchers = [],
    _calendars = {
        EVENT: {},
        TASK: {}
    },
    _calendarsStorage,
    _security = {
        "http://tizen.org/api/calendar": [],
        "http://tizen.org/api/calendar.read": ["find", "addChangeListener"],
        "http://tizen.org/api/calendar.write": ["add", "addBatch", "update", "updateBatch", "remove", "removeBatch"],
        all: true
    },
    _self;

function _isValidId(id) {
    return (/[a-z]|[A-Z]|[0-9]|[\-]/).test(id);
}

function retrieveCalendars() {
    _calendarsStorage = db.retrieveObject(_DB_CALENDARS_KEY) || {EVENT: {}, TASK: {}};
}

function saveCalendars() {
    db.saveObject(_DB_CALENDARS_KEY, _calendarsStorage);
}

_self = function () {
    var calendarManager;

    // private
    function isValidType(type) {
        for (var t in _calendars) {
            if (type === t)
                return true;
        }
        return false;
    }

    function loadCalendars(type) {
        var calsStorage, defCalendar, id, i, item;

        retrieveCalendars();
        calsStorage = _calendarsStorage[type];

        if (tizen1_utils.isEmptyObject(calsStorage)) {
            defCalendar = new Calendar(type, "DEF_CAL_" + type);

            _calendars[type][defCalendar.id] = defCalendar;
            calsStorage[defCalendar.id] = new CalendarStorage(defCalendar);
        } else {
            for (id in calsStorage) {
                for (i in calsStorage[id].items) {
                    item = calsStorage[id].items[i];
                }
                _calendars[type][id] = new Calendar(type, calsStorage[id].name, calsStorage[id].items, id, 0);
            }
        }
    }

    // public
    function getCalendar(type, id) {
        var calendar;

        if (!isValidType(type) || !_isValidId(id))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        loadCalendars(type);

        calendar = _calendars[type][id];
        if (calendar === undefined)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        return calendar;
    }

    function getCalendars(type, successCallback, errorCallback) {
        function _getCalendars() {
            if (!isValidType(type))
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

            loadCalendars(type);

            if (_calendars.length !== 0) {
                successCallback(utils.copy(_calendars[type]));
            } else if (errorCallback) {
                errorCallback(new WebAPIError(errorcode.UNKNOWN_ERR));
            }
        }

        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "calendar:getCalendars", _getCalendars);
    }

    function getDefaultCalendar(type) {
        var id, calendar;

        if (!isValidType(type))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        loadCalendars(type);

        for (id in _calendars[type]) {
            calendar = _calendars[type][id];
            break;
        }

        if (calendar === undefined)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        return calendar;
    }

    function handleSubFeatures(subFeatures) {
        for (var subFeature in subFeatures) {
            if (_security[subFeature].length === 0) {
                _security.all = true;
                return;
            }
            _security.all = false;
            utils.forEach(_security[subFeature], function (method) {
                _security[method] = true;
            });
        }
    }

    calendarManager = {
        getCalendar:        getCalendar,
        getCalendars:       getCalendars,
        getDefaultCalendar: getDefaultCalendar,
        handleSubFeatures:  handleSubFeatures
    };

    return calendarManager;
};

Calendar = function (type, name, storageItems, id, accountServiceId) {
    var privateItems = {};
    id = id || Math.uuid(null, 16);
    accountServiceId = accountServiceId || 0;

    // private
    function createCalendarItem() {
        var calendarItem = null;

        switch (type) {
        case "EVENT":
            calendarItem = new CalendarEvent();
            break;

        case "TASK":
            calendarItem = new CalendarTask();
            break;

        default:
            break;
        }

        return calendarItem;
    }

    function isValidCalendarItemId(itemId) {
        var i;

        if (!_isValidId(itemId))
            return false;

        for (i in privateItems) {
            if (i === itemId)
                return true;
        }

        return false;
    }

    function loadCalendarItemInit(calendarItem, storageItem) {
        calendarItem.description    = utils.copy(storageItem.description);
        calendarItem.summary        = utils.copy(storageItem.summary);
        calendarItem.isAllDay       = utils.copy(storageItem.isAllDay);
        calendarItem.startDate      = new TZDate(new Date(storageItem.startDate));
        calendarItem.duration       = utils.copy(storageItem.duration);
        calendarItem.location       = utils.copy(storageItem.location);
        calendarItem.geolocation    = utils.copy(storageItem.geolocation);
        calendarItem.organizer      = utils.copy(storageItem.organizer);
        calendarItem.visibility     = utils.copy(storageItem.visibility);
        calendarItem.status         = utils.copy(storageItem.status);
        calendarItem.priority       = utils.copy(storageItem.priority);
        calendarItem.alarms         = utils.copy(storageItem.alarms);
        calendarItem.categories     = utils.copy(storageItem.categories);
        calendarItem.attendees      = utils.copy(storageItem.attendees);
    }

    function loadCalendarEventInit(calendarItem, storageItem) {
        loadCalendarItemInit(calendarItem, storageItem);

        calendarItem.endDate = new TZDate(new Date(storageItem.endDate));
        calendarItem.availability = utils.copy(storageItem.availability);
        calendarItem.recurrenceRule = utils.copy(storageItem.recurrenceRule);
        calendarItem.expandRecurrence = function (startDate, endDate, successCallback, errorCallback) {
            calendarItem.startDate = startDate;
            calendarItem.endDate   = endDate;
        };
        calendarItem.frequency       = utils.copy(storageItem.frequency);
        calendarItem.interval        = utils.copy(storageItem.interval);
        calendarItem.untilDate       = storageItem.untilDate?new TZDate(new Date(storageItem.untilDate)):storageItem.untilDate;
        calendarItem.occurrenceCount = utils.copy(storageItem.occurrenceCount);
        calendarItem.daysOfTheWeek   = utils.copy(storageItem.daysOfTheWeek);
        calendarItem.setPositions    = utils.copy(storageItem.setPositions);
        calendarItem.exceptions      = utils.copy(storageItem.exceptions);
    }

    function loadCalendarTaskInit(calendarItem, storageItem) {
        loadCalendarItemInit(calendarItem, storageItem);

        calendarItem.endDate       = new TZDate(new Date(storageItem.endDate));
        calendarItem.completedDate = storageItem.completedDate?new TZDate(new Date(storageItem.completedDate)):storageItem.completedDate;
        calendarItem.progress      = utils.copy(storageItem.progress);
    }

    function loadCalendarItems() {
        var i, calendarItem;

        if (storageItems === undefined)
            return;

        for (i in storageItems) {
            calendarItem = new CalendarItem(type, i, new TZDate(new Date(storageItems[i].lastModificationDate)));

            if (type === "EVENT") {
                loadCalendarEventInit(calendarItem, storageItems[i]);
            } else {
                loadCalendarTaskInit(calendarItem, storageItems[i]);
            }

            privateItems[i] = calendarItem;
        }
    }

    function saveCalendarItems() {
        _calendarsStorage[type][id].items = new CalendarItemsStorage(privateItems);
        saveCalendars();
    }

    // public
    function get(id) {
        if (!isValidCalendarItemId(id))
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        return privateItems[id];
    }

    function add(item) {
        if (!_security.all && !_security.add)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        // typecoerce
        privateItems[item.id] = utils.copy(item);

        saveCalendarItems();

        for (var i in _watchers) {
            _watchers[i].onitemsadded([utils.copy(item)]);
        }
    }

    function addBatch(items, successCallback, errorCallback) {
        if (!_security.all && !_security.addBatch)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        function _addBatch() {
            var i;

            // typecoerce items

            for (i in items) {
                privateItems[items[i].id] = utils.copy(items[i]);
            }

            saveCalendarItems();

            for (i in _watchers) {
                _watchers[i].onitemsadded(utils.copy(items));
            }

            successCallback(utils.copy(items));
        }

        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "calendar:addBatch", _addBatch);
    }

    function update(item, updateAllInstances) {
        var calendarItem, i, j, attr;

        if (!_security.all && !_security.update)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        // typecoerce item, updateAllInstances

        if (!isValidCalendarItemId(item.id))
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        if (updateAllInstances) {
            for (attr in privateItems[item.id]) {
                if ((attr !== "id") && (attr !== "lastModificationDate") && (item[attr] !== undefined))
                    privateItems[item.id][attr] = utils.copy(item[attr]);
            }
            for (i in _watchers) {
                _watchers[i].onitemsupdated([utils.copy(privateItems[item.id])]);
            }
        } else {
            calendarItem = createCalendarItem();

            for (attr in privateItems[item.id]) {
                if (attr !== "id" && attr !== "lastModificationDate") {
                    if (item[attr] !== undefined)
                        calendarItem[attr] = utils.copy(item[attr]);
                    else
                        calendarItem[attr] = utils.copy(privateItems[item.id][attr]);
                }
            }
            add(calendarItem);
            for (j in _watchers) {
                _watchers[j].onitemsupdated([utils.copy(calendarItem)]);
            }
        }
        saveCalendarItems();
    }

    function updateBatch(items, successCallback, errorCallback, updateAllInstances) {
        var calendarItems = [], updatedItems = [];

        if (!_security.all && !_security.updateBatch)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        function _updateBatch() {
            var i, j, attr, calendarItem;

            // typecoerce items updateAllInstances

            for (i in items) {
                if (!isValidCalendarItemId(items[i].id))
                    throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }

            if (updateAllInstances) {
                for (i in privateItems) {
                    for (j in items) {
                        if (i === items[j].id) {
                            for (attr in privateItems[i]) {
                                if (attr !== "id" && attr !== "lastModificationDate" && items[j][attr] !== undefined)
                                    privateItems[i][attr] = utils.copy(items[j][attr]);
                            }
                            saveCalendarItems();
                            updatedItems.push(utils.copy(privateItems[i]));
                        }
                    }
                }
            } else {
                for (i in items) {
                    calendarItem = createCalendarItem();

                    for (attr in privateItems[items[i].id]) {
                        if (attr !== "id" && attr !== "lastModificationDate") {
                            if (items[i][attr] !== undefined)
                                calendarItem[attr] = utils.copy(items[i][attr]);
                            else
                                calendarItem[attr] = utils.copy(privateItems[items[i].id][attr]);
                        }
                    }

                    add(calendarItem);
                    updatedItems.push(utils.copy(calendarItem));
                }
            }

            saveCalendarItems();
            for (i in _watchers) {
                _watchers[i].onitemsupdated(updatedItems);
            }
            successCallback(updatedItems);
        }

        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "calendar:updateBatch", _updateBatch);
    }

    function remove(id) {
        var isFound = false, i, removedItem;

        if (!_security.all && !_security.remove)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if (!_isValidId(id))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (!isValidCalendarItemId(id))
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        for (i in privateItems) {
            if (i === id) {
                removedItem = utils.copy(privateItems[i]);
                delete privateItems[i];
                isFound = true;
                break;
            }
        }

        if (!isFound)
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        saveCalendarItems();
        for (i in _watchers) {
            _watchers[i].onitemsremoved(removedItem);
        }
    }

    function removeBatch(ids, successCallback, errorCallback) {
        var i, j, isFound = false, removedItems = [];

        if (!_security.all && !_security.removeBatch)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        function _removeBatch() {
            var i, j;

            for (i in ids) {
                if (!_isValidId(ids[i]))
                    throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

                if (!isValidCalendarItemId(id))
                    throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }

            for (i in ids) {
                isFound = false;
                for (j in privateItems) {
                    if (j === ids[i])
                        isFound = true;
                }
                if (!isFound)
                    throw new WebAPIError(errorcode.NOT_FOUND_ERR);
            }

            for (i in ids) {
                for (j in privateItems) {
                    if (j === ids[i]) {
                        removedItems.push(utils.copy(privateItems[j]));
                        delete privateItems[j];
                    }
                }
            }

            saveCalendarItems();
            successCallback(removedItems);
            for (i in _watchers) {
                _watchers[i].onitemsremoved(utils.copy(removedItems));
            }
        }

        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "calendar:removeBatch", _removeBatch);
    }

    function find(successCallback, errorCallback, filter, sortMode) {
        if (!_security.all && !_security.find)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        function _find() {
            var i, calendarItems = [], result = [];

            for (i in privateItems) {
                calendarItems.push(privateItems[i]);
            }

            result = tizen1_utils.query(calendarItems, filter, sortMode);
            successCallback(result);
        }
        return tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "calendar:find", _find);
    }

    function addChangeListener(successCallback, errorCallback) {
        var watchId;

        if (!_security.all && !_security.addChangeListener)
            throw new WebAPIError(errorcode.SECURITY_ERR);

        if ((typeof successCallback !== "object") ||
            (typeof successCallback.onitemsadded   !== "function") ||
            (typeof successCallback.onitemsupdated !== "function") ||
            (typeof successCallback.onitemsremoved !== "function") ||
            (typeof errorCallback !== "function"))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        watchId = Math.uuid(null, 16);
        _watchers[watchId] = successCallback;

        return watchId;
    }

    function removeChangeListener(watchId) {
        if (!_isValidId(watchId))
            throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);

        if (!_watchers[watchId])
            throw new WebAPIError(errorcode.NOT_FOUND_ERR);

        delete _watchers[watchId];
    }

    loadCalendarItems(type, privateItems, storageItems);

    this.__defineGetter__("id", function () {
        return id;
    });
    this.__defineGetter__("accountServiceId", function () {
        return accountServiceId;
    });
    this.__defineGetter__("name", function () {
        return name;
    });

    this.get                  = get;
    this.add                  = add;
    this.addBatch             = addBatch;
    this.update               = update;
    this.updateBatch          = updateBatch;
    this.remove               = remove;
    this.removeBatch          = removeBatch;
    this.find                 = find;
    this.addChangeListener    = addChangeListener;
    this.removeChangeListener = removeChangeListener;
};

CalendarStorage = function (calendar) {
    this.id               = calendar.id;
    this.accountServiceId = calendar.accountServiceId;
    this.name             = calendar.name;

};

CalendarItemsStorage = function (privateItems) {
    var itemsStorage = {}, i, attr;

    for (i in privateItems) {
        itemsStorage[i] = {};
        for (attr in privateItems[i]) {
            if ((attr === "startDate" || attr === "endDate" || attr === "untilDate" || attr === "completedDate" || attr === "lastModificationDate") &&
                (privateItems[i][attr] !== undefined)) {
                itemsStorage[i][attr] = privateItems[i][attr].toString();
            } else if (typeof privateItems[i] !== "function") {
                itemsStorage[i][attr] = privateItems[i][attr];
            }
        }
    }

    return itemsStorage;
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/AlarmBase', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (id) {
    id = id || Math.uuid(null, 16);

    this.__defineGetter__("id", function () {
        return id;
    });
    this.__defineSetter__("id", function (_id) {
        id = _id;
    });
};

});
define('ripple/platform/tizen/2.0/vibration', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    event = require('ripple/event'),
    deviceSettings = require('ripple/deviceSettings'),
    constants = require('ripple/constants'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    emulatorBridge = require('ripple/emulatorBridge'),
    curPost,
    _self;

function isVibratorOn() {
    return deviceSettings.retrieve("Config.vibratingMode");
}

var vibrator = (function () {
    var vibratorPattern,
        isVibrating = false,
        runTime = 0,
        vibrateTimeout = null,
        MILLILSECONDS_OF_ONE_VIBRATION = 100,
        node = jQuery("#" + constants.COMMON.DEVICE_CONTAINER),
        movementIndex = 0,
        movement = [{ left: -10 }, { left: 0 }, { left: 10 }, { left: 0 },
                    {top: -10 }, { top: 0 }, {top: 10 }, { top: 0 }];

    function _clearTimeout() {
        if (vibrateTimeout) {
            clearInterval(vibrateTimeout);
            vibrateTimeout = null;        
        }
    }

    function stopVibrate() {
        isVibrating = false;
        _clearTimeout();
        node.css({left: 0, top: 0}, MILLILSECONDS_OF_ONE_VIBRATION);
    }
    
    function vibrate() {
        node.css(movement[movementIndex]);
        movementIndex = (movementIndex + 1) % 8;
    }
    
    function changePulse() {
        if (emulatorBridge.document().hidden) {
            return;
        }

        //run time
        runTime = runTime + MILLILSECONDS_OF_ONE_VIBRATION;
        if (curPost >= vibratorPattern.length) {
            setTimeout(stopVibrate, 1);
        }       
        if (runTime > vibratorPattern[curPost]) {
            curPost = curPost + 1;
            runTime = 0;
        } else {
            if ((curPost % 2) === 0) {
                vibrate();
            }
        }
    } 
  
    function startVibrate(_pattern) {
        if (!isVibratorOn()) 
            return;

        vibratorPattern = _pattern; 
        _clearTimeout();
        movementIndex = 0;      
        if (_pattern) {
            runTime = 0;
            vibrateTimeout = setInterval(changePulse, MILLILSECONDS_OF_ONE_VIBRATION);
        }    
        isVibrating = true;
    }
    
    return {
        isVibrating: isVibrating,
        startVibrate: startVibrate,
        stopVibrate: stopVibrate
    };
}());

_self = {
    vibrate: function () {
        var pattern = arguments[0],
            i; 

        // If vibrator is off, stop the vibration
        event.on("VibratingModeChanged", function (value) {
            if (value === false) {
                vibrator.stopVibrate();
            }
        });
        
        //1. If the hidden attribute [PAGE-VISIBILITY] is set to true, abort these steps.
        if (emulatorBridge.document().hidden) {
            return;
        }

        //2. Let pattern be the value of the first argument.                     
        if (!tizen1_utils.isValidArray(pattern)) {
            pattern |= 0;
        } else {
            for (i = 0; i < pattern.length; i++) {
                pattern[i] |= 0;
            }
        }

        //3. If pattern is 0, or an empty list, cancel the pre-existing instance of the processing vibration patterns algorithm, if any, and abort these steps.    
        if (pattern === 0 || (tizen1_utils.isValidArray(pattern) && pattern.length === 0)) {
            vibrator.stopVibrate();
            return;
        }
        
        //4. If pattern is a list, proceed to the next step. Otherwise run the following substeps:
        //a. Let list be an initially empty list, and add pattern to list.
        //b. Let pattern be list.       
        if (!tizen1_utils.isValidArray(pattern)) {
            pattern = [pattern];
        }

        //5. If any entry of pattern exceeds an implementation-dependent limit, then the user agent may throw a NotSupportedError exception and abort these steps.
              
        //6. If the length of pattern is even, then remove the last entry in pattern. 
        if (pattern.length % 2 === 0) {
            pattern.pop();
        }
        
        //7. Cancel the pre-existing instance of the processing vibration patterns algorithm, if any. 
        if (vibrator.isVibrating) {
            vibrator.stopVibrate();
        }

        curPost = 0;
        vibrator.startVibrate(pattern);
    }
}; 

module.exports = _self;

});
define('ripple/platform/tizen/2.0/MessageStorage', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    Message = require('ripple/platform/tizen/2.0/Message'),
    MessageBody = require('ripple/platform/tizen/2.0/MessageBody'),
    Conversation = require('ripple/platform/tizen/2.0/Conversation'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    PrivMessage = require('ripple/platform/tizen/2.0/PrivMessage'),
    MessageFolder = require('ripple/platform/tizen/2.0/MessageFolder'),
    msg_utils = require('ripple/platform/tizen/2.0/msg_utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    TIZEN_DEFAULT_MSG_FROM = {"messaging.sms": "13572468",
                              "messaging.mms": "13572468",
                              "messaging.email": "tizen.simulator@tizen.org"};

_self = function (messages, security_check) {
    var message_storage = {},
        _findMessage, _findConversation,
        _processMessageChange, _processConversationChange,
        _folders = {}, folderOpt = {},
        _msgListeners = {},
        _convListeners = {},
        _folderListeners = {},
        _security_check = security_check,
        _messages = messages;

    // init folders
    folderOpt = {id: "INBOX", serviceId: _messages.id, contentType: _messages.type,
                 path: "inbox", type: "INBOX", synchronizable: true};
    _folders.INBOX = new MessageFolder(folderOpt);
    folderOpt = {id: "OUTBOX", serviceId: _messages.id, contentType: _messages.type,
                 path: "outbox", type: "OUTBOX", synchronizable: false};
    _folders.OUTBOX = new MessageFolder(folderOpt);
    folderOpt = {id: "DRAFT", serviceId: _messages.id, contentType: _messages.type,
                 path: "draft", type: "DRAFTS", synchronizable: false};
    _folders.DRAFT = new MessageFolder(folderOpt);
    folderOpt = {id: "SENTBOX", serviceId: _messages.id, contentType: _messages.type,
                 path: "sentbox", type: "SENTBOX", synchronizable: false};
    _folders.SENTBOX = new MessageFolder(folderOpt);

    event.on("MsgRecv", function (msg) {
        // msg sent from panel to module
        if (msg.priv.type !== _messages.type ||
            msg.priv.serviceId !== _messages.id) {
            return;
        }
        // trigger Message add
        _processMessageChange([msg], "add");
        _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);

        if (_messages.conv[msg.priv.conversationId].messageCount === 1) {
            _processConversationChange([_messages.conv[msg.priv.conversationId]], "add");
        } else {
            _processConversationChange([_messages.conv[msg.priv.conversationId]], "update");
        }
    });

    event.on("OutsideMessageReceived", function (msg) {
        // msg sent from module to panel
        if (msg.msg.priv.type !== _messages.type ||
            msg.msg.priv.serviceId !== _messages.id) {
            return;
        }
        // trigger conversation/Message add
        _processMessageChange([msg.msg], "add");
        _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);

        if (_messages.conv[msg.msg.priv.conversationId].messageCount === 1) {
            _processConversationChange([_messages.conv[msg.msg.priv.conversationId]], "add");
        } else {
            _processConversationChange([_messages.conv[msg.msg.priv.conversationId]], "update");
        }
    });

    event.on("MsgSentRst", function (rst) {
        // ACK from panel when module sent a msg to panel
        if (rst.priv.type !== _messages.type ||
            rst.priv.serviceId !== _messages.id) {
            return;
        }
        // trigger conversation/Message Update
        _processMessageChange([rst], "update");
        _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);
        _processConversationChange([_messages.conv[rst.priv.conversationId]], "update");
    });

    _findMessage = function (src, filter) {
        var ret, foo = {};
        switch (filter.attributeName) {
        case "serviceId":
            foo[filter.attributeName] = _messages.id;
            ret = tizen1_utils.matchAttributeFilter([foo],
                      filter.attributeName, filter.matchFlag, filter.matchValue);
            if (ret.length === 0) {
                ret = [];
            } else {
                // make an array
                ret = utils.filter(src, function () { return true; });
            }
            break;
        case "type":
            foo[filter.attributeName] = _messages.type;
            ret = tizen1_utils.matchAttributeFilter([foo],
                      filter.attributeName, filter.matchFlag, filter.matchValue);
            if (ret.length === 0) {
                ret = [];
            } else {
                // make an array
                ret = utils.filter(src, function () { return true; });
            }
            break;
        case "id":
        case "conversationId":
        case "folderId":
        case "from":
        case "messageStatus":
            ret = tizen1_utils.matchAttributeFilter(src,
                      "priv." + filter.attributeName,
                      filter.matchFlag, filter.matchValue);
            break;
        case "hasAttachment":
            if (filter.matchFlag !== "EXACTLY" || typeof filter.matchValue !== "boolean") {
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                              "Support only matchFlag === 'EXACTLY' and typeof matchValue === 'boolean'"));
            }
            ret = tizen1_utils.matchAttributeBooleanFilter(src,
                      "priv." + filter.attributeName, filter.matchValue);
            break;
        case "to":
        case "cc":
        case "bcc":
            ret = tizen1_utils.matchAttributeArrayFilter(src,
                      filter.attributeName, filter.matchFlag, filter.matchValue);
            break;
        case "body":
            ret = tizen1_utils.matchAttributeFilter(src,
                      filter.attributeName + ".plainBody",
                      filter.matchFlag, filter.matchValue);
            break;
        case "subject":
        case "inResponseTo":
            ret = tizen1_utils.matchAttributeFilter(src, filter.attributeName,
                      filter.matchFlag, filter.matchValue);
            break;
        case "isRead":
        case "isHighPriority":
            if (filter.matchFlag !== "EXACTLY" || typeof filter.matchValue !== "boolean") {
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                              "Support only matchFlag === 'EXACTLY' and typeof matchValue === 'boolean'"));
            }
            ret = tizen1_utils.matchAttributeBooleanFilter(src,
                      filter.attributeName, filter.matchValue);
            break;
        case "timestamp":
            ret = tizen1_utils.matchAttributeRangeFilter(src,
                      "priv." + filter.attributeName,
                      filter.initialValue, filter.endValue);
            break;

        case "attachments":
            throw (new WebAPIError(errorcode.NOT_SUPPORTED_ERR,
                                  "not support find by " + filter.attributeName));
        default:
            throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                                   "invalid attributeName"));
        }
        return ret;
    };

    _processMessageChange = function (messages, type) {
        var i, j, ret = [], tmp,
            operation = {"add": "messagesadded",
                         "remove": "messagesremoved",
                         "update": "messagesupdated"};

        for (i in _msgListeners) {
            ret = [];
            if (_msgListeners[i].filter !== null) {
                tmp = _findMessage(messages, _msgListeners[i].filter);
            } else {
                tmp = messages;
            }
            if (tmp.length !== 0) {
                for (j = 0; j < tmp.length; j++) {
                    ret.push(new Message(tmp[j].priv.type, tmp[j]));
                }
                _msgListeners[i].callback[operation[type]](ret);
            }
        }
    };

    _findConversation = function (src, filter) {
        var ret, foo = {};
        switch (filter.attributeName) {
        case "type":
            foo[filter.attributeName] = _messages.type;
            ret = tizen1_utils.matchAttributeFilter([foo], filter.attributeName, filter.matchFlag, filter.matchValue);
            if (ret.length === 0) {
                ret = [];
            } else {
                // make an array
                ret = utils.filter(_messages.conv, function () { return true; });
            }
            break;
        case "id":
        case "preview":
        case "subject":
        case "from":
        case "lastMessageId":
            ret = tizen1_utils.matchAttributeFilter(src, filter.attributeName, filter.matchFlag, filter.matchValue);
            break;
        case "to":
        case "cc":
        case "bcc":
            ret = tizen1_utils.matchAttributeArrayFilter(src,
                      filter.attributeName, filter.matchFlag, filter.matchValue);
            break;
        case "isRead":
            if (filter.matchFlag !== "EXACTLY" || typeof filter.matchValue !== "boolean") {
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                              "Support only matchFlag === 'EXACTLY' and typeof matchValue === 'boolean'"));
            }
            ret = tizen1_utils.matchAttributeBooleanFilter(src,
                      filter.attributeName, filter.matchValue);
            break;
        case "timestamp":
        case "messageCount":
        case "unreadMessages":
            ret = tizen1_utils.matchAttributeRangeFilter(src,
                      filter.attributeName,
                      filter.initialValue, filter.endValue);
            break;
        default:
            throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                                   "invalid attributeName"));
        }
        return ret;
    };

    _processConversationChange = function (conversations, type) {
        var i, j, ret = [], tmp,
            operation = {"add": "conversationsadded",
                         "remove": "conversationsremoved",
                         "update": "conversationsupdated"};

        for (i in _convListeners) {
            ret = [];
            if (_convListeners[i].filter !== null) {
                tmp = _findConversation(conversations, _convListeners[i].filter);
            } else {
                tmp = conversations;
            }
            if (tmp.length !== 0) {
                for (j = 0; j < tmp.length; j++) {
                    ret.push(new Conversation(tmp[j]));
                }
                _convListeners[i].callback[operation[type]](ret);
            }
        }
    };

    message_storage = {
        addDraftMessage: function (_msg, onSuccess, onError) {
            var m, msg = {}, opt = {}, _addDraft;

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (msg_utils.setMsg(_msg, msg) === false) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            _addDraft = function () {
                opt.id = Math.uuid(8, 16);
                opt.serviceId = _messages.id;
                if ((msg.inResponseTo !== null) &&
                    (_messages.msg[msg.inResponseTo] !== undefined)) {
                    opt.conversationId = _messages.msg[msg.inResponseTo].conversationId;
                } else {
                    opt.conversationId = opt.id;
                }
                opt.folderId = "DRAFTS";
                opt.type = _messages.type;
                opt.timestamp = new Date();
                opt.from = TIZEN_DEFAULT_MSG_FROM[_messages.type];
                if (msg.attachments.length === 0) {
                    opt.hasAttachment = false;
                } else {
                    opt.hasAttachment = true;
                }
                opt.messageStatus = "DRAFT";

                m = new PrivMessage(msg, opt);
                _messages.msg[m.priv.id] = m;  // local
                msg_utils.saveMsg(_messages.msg[m.priv.id]);  // remote
                // trigger message add
                _processMessageChange([m], "add");
                setTimeout(function () {
                    onSuccess(new Message(m.priv.type, m));
                }, 1);
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messageStorage:addDraftMessage", _addDraft);
        },

        removeMessages: function (messages, onSuccess, onError) {
            var _removeMsg;

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (tizen1_utils.isValidArray(messages) === false) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            if (messages.length === 0) {
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
            }
            _removeMsg = function () {
                var i, c, na_msg = "", msgToDel = [], convToDel = {}, delConv = [], updateConv = [];
                // update conversation.
                _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);
                for (i = 0; i < messages.length; i++) {
                    if (_messages.msg[messages[i].id] === undefined) {
                        na_msg += messages[i].id + ", ";
                    } else {
                        msgToDel.push(utils.copy(_messages.msg[messages[i].id]));
                    }
                    if (_messages.conv[messages[i].conversationId] !== undefined) {
                        convToDel[messages[i].conversationId] = _messages.conv[messages[i].conversationId];
                    }
                }
                if (na_msg === "") {
                    for (i = 0; i < messages.length; i++) {
                        // conversation updated at remote when msg is deleted
                        msg_utils.delMsg(_messages.msg[messages[i].id]); // remote
                        delete _messages.msg[messages[i].id]; // local
                    }
                    // update conversation
                    _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);
                    for (c in convToDel) {
                        if (_messages.conv[c] === undefined) {
                            delConv.push(convToDel[c]);
                        } else {
                            updateConv.push(convToDel[c]);
                        }
                    }
                    setTimeout(function () {
                        onSuccess();
                    }, 1);
                    // trigger messages remove
                    _processMessageChange(msgToDel, "remove");
                    if (delConv.length > 0) {
                        _processConversationChange(delConv, "remove");
                    }
                    if (updateConv.length > 0) {
                        _processConversationChange(updateConv, "update");
                    }
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.NOT_FOUND_ERR,
                                    na_msg + "not found !!"));
                        }, 1);
                    }
                }
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messageStorage:removeMessage", _removeMsg);
        },

        updateMessages: function (messages, onSuccess, onError) {
            var _updateMsg;

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (tizen1_utils.isValidArray(messages) === false) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            if (messages.length === 0) {
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
            }
            _updateMsg = function () {
                var i, m, updateConv = {}, updateMsg = [], tmp,
                    na_msg = "", invalid_msg = "";

                // update conversation
                _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);
                for (i = 0; i < messages.length; i++) {
                    m = _messages.msg[messages[i].id];
                    if (m === undefined) {
                        // msg not found
                        na_msg += messages[i].id + ", ";
                    } else {
                        if (m.priv.messageStatus === "DRAFT") {
                            tmp = {};
                            // allow update all writeable attr in draft
                            if (msg_utils.setMsg(messages[i], tmp) === false) {
                                invalid_msg += messages[i].id + ", ";
                            }
                        }
                    }
                }
                if (invalid_msg !== "") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.INVALID_VALUES_ERR,
                                    invalid_msg + "invalid values"));
                        }, 1);
                    }
                    return;
                }
                if (na_msg !== "") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.NOT_FOUND_ERR,
                                    na_msg + "not found !!"));
                        }, 1);
                    }
                    return;
                }

                for (i = 0; i < messages.length; i++) {
                    m = _messages.msg[messages[i].id];
                    if (m.priv.messageStatus === "DRAFT") {
                        msg_utils.setMsg(messages[i], m);
                    } else {
                        // only allow update isRead in other folders
                        if (typeof messages[i].isRead === 'boolean') {
                            m.isRead = messages[i].isRead;
                            updateMsg.push(m);
                            updateConv[m.priv.conversationId] = _messages.conv[m.priv.conversationId];
                        }
                    }
                    msg_utils.saveMsg(m);
                }
                setTimeout(function () {
                    onSuccess();
                }, 1);

                // trigger Message update
                _processMessageChange(updateMsg, "update");

                _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);
                // trigger conversation update
                _processConversationChange(updateConv, "update");
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messageStorage:updateMessage", _updateMsg);
        },

        findMessages: function (filter, onSuccess, onError, sort, _limit, _offset) {
            var i, _findMsg, tmp, offset, limit, ret = [];

            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }

            _findMsg = function () {
                tmp = _findMessage(_messages.msg, filter);
                if (tmp.length === 0) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.NOT_FOUND_ERR));
                        }, 1);
                    }
                }

                if ((_offset !== null) && (_offset !== undefined)) {
                    offset = _offset;
                } else {
                    offset = 0;
                }
                if ((_limit !== null) && (_limit !== undefined)) {
                    limit = Math.min(_limit + offset, tmp.length);
                } else {
                    limit = tmp.length;
                }
                for (i = offset; i < limit; i++) {
                    ret.push(new Message(tmp[i].priv.type, tmp[i]));
                }
                setTimeout(function () {
                    onSuccess(ret);
                }, 1);
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError,
                       "messageStorage:findMessages", _findMsg);
        },

        findConversations: function (filter, onSuccess, onError, sort, _limit, _offset) {
            var i, _findConv, tmp, offset, limit, ret = [];

            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            // download conversation
            _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);

            _findConv = function () {
                tmp = _findConversation(_messages.conv, filter);
                if (tmp.length === 0) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.NOT_FOUND_ERR));
                        }, 1);
                    }
                }

                if ((_offset !== null) && (_offset !== undefined)) {
                    offset = _offset;
                } else {
                    offset = 0;
                }
                if ((_limit !== null) && (_limit !== undefined)) {
                    limit = Math.min(_limit + offset, tmp.length);
                } else {
                    limit = tmp.length;
                }
                for (i = offset; i < limit; i++) {
                    ret.push(new Conversation(tmp[i]));
                }
                setTimeout(function () {
                    onSuccess(ret);
                }, 1);
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError,
                       "messageStorage:findConversations", _findConv);
        },

        removeConversations: function (conversations, onSuccess, onError) {
            var i, _removeConv, na_msg = "", retConv = [], removeMsg = [];

            if (_security_check.write === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            // download conversation
            _messages.conv = msg_utils.loadConv(_messages.type, _messages.id);

            if (tizen1_utils.isValidArray(conversations) === false) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }
            if (conversations.length === 0) {
                throw (new WebAPIError(errorcode.INVALID_VALUES_ERR));
            }
            _removeConv = function () {
                for (i = 0; i < conversations.length; i++) {
                    if (_messages.conv[conversations[i].id] === undefined) {
                        na_msg += conversations[i].id + ", ";
                    } else {
                        retConv.push(_messages.conv[conversations[i].id]);
                        for (var m in _messages.msg) {
                            if (_messages.msg[m].priv.conversationId === conversations[i].id) {
                                removeMsg.push(_messages.msg[m]);
                            }
                        }
                    }
                }
                if (na_msg === "") {
                    for (i = 0; i < removeMsg.length; i++) {
                        // conversation updated at remote
                        msg_utils.delMsg(removeMsg[i]);  // remote
                        delete _messages.msg[removeMsg[i].priv.id]; // local
                    }
                    // trigger msg(retMsg)/conv(retConv) delete update
                    _processMessageChange(removeMsg, "remove");
                    _processConversationChange(retConv, "remove");
                    setTimeout(function () {
                        onSuccess();
                    }, 1);
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.NOT_FOUND_ERR,
                                    na_msg + "not found !!"));
                        }, 1);
                    }
                }
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError, "messageStorage:removeConversations", _removeConv);
        },

        findFolders: function (filter, onSuccess, onError) {
            var ret = [], tmp, i, _findFolders;

            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            _findFolders = function () {
                switch (filter.attributeName) {
                case "id":
                case "serviceId":
                case "contentType":
                case "name":
                case "path":
                case "type":
                    tmp = tizen1_utils.matchAttributeFilter(_folders,
                              filter.attributeName, filter.matchFlag,
                              filter.matchValue);
                    break;
                case "synchronizable":
                    if (filter.matchFlag !== "EXACTLY" ||
                        typeof filter.matchValue !== "boolean") {
                        throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                                      "Support only matchFlag === 'EXACTLY' and typeof matchValue === 'boolean'"));
                    }
                    tmp = tizen1_utils.matchAttributeBooleanFilter(_folders,
                              filter.attributeName, filter.matchValue);
                    break;
                case "parentId":
                    if (filter.matchValue === null) {
                        tmp = utils.filter(_folders, function (o) { return o.parentId === null; });
                    } else {
                        tmp = tizen1_utils.matchAttributeFilter(_folders,
                                  filter.attributeName, filter.matchValue);
                    }
                    break;
                default:
                    throw (new WebAPIError(errorcode.INVALID_VALUES_ERR,
                                           "invalid attributeName"));
                }
                if (tmp.length === 0) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new WebAPIError(errorcode.NOT_FOUND_ERR));
                        }, 1);
                    }
                }
                for (i = 0; i < tmp.length; i++) {
                    ret.push(new MessageFolder(tmp[i]));
                }
                setTimeout(function () {
                    onSuccess(ret);
                }, 1);
            };
            return tizen1_utils.validateTypeMismatch(onSuccess, onError,
                       "messageStorage:findFolders", _findFolders);
        },

        addMessagesChangeListener: function (msgCallback, filter) {
            var watchId, msgListener = {};

            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (msgCallback === undefined || msgCallback === null ||
                ((msgCallback !== undefined && msgCallback !== null) && (
                typeof msgCallback.messagesadded !== 'function' ||
                typeof msgCallback.messagesupdated !== 'function' ||
                typeof msgCallback.messagesremoved !== 'function'))) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }

            watchId = Number(Math.uuid(8, 10));
            msgListener.callback = msgCallback;
            msgListener.filter = filter || null;
            _msgListeners[watchId] = msgListener;
            return watchId;
        },

        addConversationsChangeListener: function (convCallback, filter) {
            var watchId, convListener = {};

            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (convCallback === undefined || convCallback === null ||
                ((convCallback !== undefined && convCallback !== null) && (
                typeof convCallback.conversationsadded !== 'function' ||
                typeof convCallback.conversationsupdated !== 'function' ||
                typeof convCallback.conversationsremoved !== 'function'))) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }

            watchId = Number(Math.uuid(8, 10));
            convListener.callback = convCallback;
            convListener.filter = filter || null;
            _convListeners[watchId] = convListener;
            return watchId;
        },

        addfoldersChangeListener: function (callback, filter) {
            var watchId, folderListener = {};

            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (callback === undefined || callback === null ||
                ((callback !== undefined && callback !== null) && (
                typeof callback.foldersadded !== 'function' ||
                typeof callback.foldersupdated !== 'function' ||
                typeof callback.foldersremoved !== 'function'))) {
                throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
            }

            watchId = Number(Math.uuid(8, 10));
            folderListener.callback = callback;
            folderListener.filter = filter || null;
            _folderListeners[watchId] = folderListener;
            return watchId;
        },

        removeChangeListener: function (watchid) {
            if (_security_check.read === false) {
                throw (new WebAPIError(errorcode.SECURITY_ERR));
            }
            if (_msgListeners[watchid] !== undefined) {
                delete _msgListeners[watchid];
                return;
            }
            if (_convListeners[watchid] !== undefined) {
                delete _convListeners[watchid];
                return;
            }
            if (_folderListeners[watchid] !== undefined) {
                delete _folderListeners[watchid];
                return;
            }
            throw (new WebAPIError(errorcode.NOT_FOUND_ERR));
        }

    };
    return message_storage;
};

module.exports = _self;

});
define('ripple/platform/tizen/2.0/routeBackend_navigation', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    db = require('ripple/db'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    lbs_utils = require('ripple/platform/tizen/2.0/lbs_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    RouteWaypoint,
    RouteDistance,
    RouteDuration,
    RouteStep,
    RouteSegment,
    RouteRequestOptions,
    RouteResultSummary,
    RouteResult,
    LocationServiceProvider = {},
    _data = {
        positionDistance: {},
        positionDuration: {},
        routeProvider: {},
        routes: [],
        RouteDistanceUnit: ["M", "KM", "MI", "FT"],
        providers: [],
        path: []
    }, 
    _self;

// The RouteWaypoint object
RouteWaypoint = function () {
    return {
        position: {
            latitude: 0,
            longitude: 0
        },
        isStopover: true
    };
};

// The RouteDistance object
RouteDistance = function () {
    return {
        text : "Distance",
        value : "0",
        unit : "KM "
    };
};

// The RouteDuration object
RouteDuration = function () {
    return {
        text : "Duration",
        value : "0" // The duration in a seconds
    };
};

// The RouteStep object
RouteStep = function () {
    var _self = {
        mode: "",        // The way of the travel, for example: car, bike, foot
        instruction: "", // The instruction of this step
        points: []       // The points of this step
    };

    _self.origin      = new SimpleCoordinates(0, 0);
    _self.destination = new SimpleCoordinates(0, 0);
    _self.distance    = new RouteDistance();
    _self.duration    = new RouteDuration();

    return _self;
};
// The RouteSegment object
RouteSegment = function () {
    var _self = {
        steps: []
    };

    _self.origin      = new SimpleCoordinates(0, 0);
    _self.destination = new SimpleCoordinates(0, 0);
    _self.distance    = new RouteDistance();
    _self.duration    = new RouteDuration();

    return _self;
};

// The RouteRequestOptions object
RouteRequestOptions = function () {
    return {
        mode: "", // CAR, BIKE
        unit: "KM",
        routeGoal: "SHORTEST",
        constraints: ["HIGHWAY", "TOLL", "UNPAVED"],
        wayPoints: [],
        maxResults: 1
    };
};

// The RouteResultSummary object
RouteResultSummary = function () {
    var _self = {};

    _self.origin        = new SimpleCoordinates(0, 0);
    _self.destination   = new SimpleCoordinates(0, 0);
    _self.totalDistance = new RouteDistance();
    _self.totalDuration = new RouteDuration();

    return _self;
};

// The RouteResult object
RouteResult = function () {
    var _self, jsonStr, jsonObj;
    jsonObj = { 
            "type" : "Point",
            "coordinates" : []
        };
    jsonStr = JSON.stringify(jsonObj);
    _self = {
        segments : [],
        toGeoJSON : function () {
                return jsonStr;
            }
    };
    _self.summary = new RouteResultSummary();
    return _self;
};

function calcDegree(distance) { 
    return distance * Math.PI / 180.0;
} 

//calcute the distance
function  calculateDistance(lat1, lat2, lon1, lon2) {
    var R = 6371, dLat, dLon, a, c, distance; // km
    dLat = calcDegree(parseFloat(lat2) - parseFloat(lat1));
    dLon = calcDegree(parseFloat(lon2) - parseFloat(lon1));
    
    lat1 = calcDegree(lat1);
    lat2 = calcDegree(lat2);

    a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
             Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2); 
    c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 
    distance = R * c;
    return distance;
}

function calculateDuration(mode, distance) {
    var duration, v;
    switch (mode) {
    case "motorcar" :
        v = 50;
        duration = distance / v;
        break;
    case "bicycle" :
        v = 20;
        duration = distance / v;
        break;
    case "foot" :
        v = 5;
        duration = distance / v;
        break;
    default:
        duration = 0;
    }
    return duration;
}

function optimalWay(points, mode) {
    var steps = [], startLatitude, startLongitude, originLocation, endLatitude, endLongitude,
    destinationLocation, step, distance, segment, result, i, routeDistance, routeDuration;
    for (i = 0;i < points.length - 1;i++) {
        startLatitude       = points[i].lat;
        startLongitude      = points[i].lon;
        originLocation      = new SimpleCoordinates(startLatitude, startLongitude);
        endLatitude         = points[i + 1].lat;
        endLongitude        = points[i + 1].lon;
        destinationLocation = new SimpleCoordinates(endLatitude, endLongitude);
        step                = new RouteStep();
        step.origin         = originLocation;
        step.destination    = destinationLocation;
        distance            = calculateDistance(startLatitude, endLatitude, startLongitude, endLongitude);
        routeDistance       = new RouteDistance();
        routeDistance.value = distance;
        routeDistance.unit  = "km";
        step.distance       = routeDistance;
        routeDuration       = new RouteDuration();
        routeDuration.value = calculateDuration(mode, distance);
        step.duration       = routeDuration;
        steps.push(step);
    }
    return steps;
}

function existInSupports(str, array) {
    for (var i in array) {
        if (str === array[i]) {
            return true;
        }
    }
    return false;
}

function navigation(searchStr, flat, flon, tlat, tlon, v, fast) {
    var positions = [];

    _data.positionDistance = {};
    _data.positionDuration = {};
    jQuery.ajax({
        type : "get",
        async : false,
        url : searchStr,
        data : {
            flat : flat,
            flon : flon,
            tlat : tlat,
            tlon : tlon,
            v : v,
            fast : fast,
            layer : 'mapnik',
            format : "geojson"
        },
        contentType : "application/json; charset=utf-8",
        dataType : "json",
        cache : false,
        success : function (data) {
            $.each(data.coordinates, function (i, item) {
                var point = {};
                point.lon = item[0];
                point.lat = item[1];
                positions.push(point);
            });
            $.each(data.properties, function (i, item) {
                if (typeof item === "number") {
                    _data.positionDistance = new RouteDistance();
                    _data.positionDistance.value = item;
                    _data.positionDistance.unit = "km";
                    _data.positionDuration = new RouteDuration();
                    _data.positionDuration.value = calculateDuration(v, item);
                }
            });
        },
        error : function (errorCB) {
            if (errorCB) {
                setTimeout(function () {
                    errorCB(new WebAPIError(errorcode.NETWORK_ERR));
                }, 1);
            }
        }
    });
    return positions;
}


function filterWaypoints(routeWaypoints) {
    var mathWaypoints = [], i;
    for (i in routeWaypoints) {
        if (routeWaypoints[i].position.latitude !== "" &&
            routeWaypoints[i].position.latitude !== undefined &&
            routeWaypoints[i].position.latitude !== null &&
            routeWaypoints[i].position.longitude !== null &&
            routeWaypoints[i].position.longitude !== "" &&
            routeWaypoints[i].position.longitude !== undefined) {
            mathWaypoints.push(routeWaypoints[i]);
        }
    }
    return mathWaypoints;
}

module.exports = function (prop) {
    var _self = new lbs_utils.LocationServiceProvider(prop);

    _self.supportedGoals       = ["SHORTEST", "FASTEST", "MOST_SCENIC", "SIMPLEST", "CHEAPEST", "SAFEST" ];
    _self.supportedModes       = ["motorcar", "bicycle", "foot"];
    _self.supportedConstraints = ["HIGHWAY", "TOLL", "UNPAVED", "BORDER", "GRAVEL_PAVING", "TUNNEL", "BRIDGE", "LEFT_TURN", "CARPOOL", "HAZARDOUS_CARGO" ];
    _self.supportsWayPoints    = true;
    _self.find = function (origin, destination, successCallback, errorCallback, options) {
        function _find() {
            var flat, flon, tlat, tlon, v, fast, layer, mapnik, format, searchStr, mode, result,
                points = [],
                routeWaypoints = [],
                segmentPositions = [],
                positions = [],
                segments = [],
                totalDistances = 0, totalDurations = 0,
                k, key, segment, startPosition, endPosition,
                summary, distance, duration;

            v = options.mode;
            //init
            if (!existInSupports(v, _self.supportedModes)) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            if (!existInSupports(options.routeGoal, _self.supportedGoals)) {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }
            switch (options.routeGoal) {
            case "SHORTEST":
                fast = 0;
                break;

            case "FASTEST":
                fast = 1;
                break;

            case "SIMPLEST":
                break;

            case "MOST_SCENIC":
                break;

            case "CHEAPEST":
                break;

            case "SAFEST":
                break;

            default:
                fast = 0;
            }
            searchStr      = "http://www.yournavigation.org/api/dev/gosmore.php";
            routeWaypoints = options.wayPoints;
            routeWaypoints = filterWaypoints(routeWaypoints);
            segmentPositions.push(origin);

            if (routeWaypoints.length > 0) {
                for (k in routeWaypoints) {
                    segmentPositions.push(routeWaypoints[k].position);
                }
            }
            segmentPositions.push(destination);

            for (key = 0; key < segmentPositions.length - 1; key++) {
                segment             = new RouteSegment();
                startPosition       = segmentPositions[key];
                endPosition         = segmentPositions[key + 1];
                segment.origin      = startPosition;
                segment.destination = endPosition;
                flat                = startPosition.latitude;
                flon                = startPosition.longitude;
                tlat                = endPosition.latitude;
                tlon                = endPosition.longitude;
                positions           = navigation(searchStr, flat, flon, tlat, tlon, v, fast);
                segment.steps       = optimalWay(positions, v);
                segment.distance    = _data.positionDistance;
                totalDistances     += _data.positionDistance.value;
                segment.duration    = _data.positionDuration;
                totalDurations     += _data.positionDuration.value;
                segments.push(segment);
            }
            result                = new RouteResult();
            summary               = new RouteResultSummary();
            summary.origin        = segmentPositions[0];
            summary.destination   = segmentPositions[segmentPositions.length - 1];
            distance              = new RouteDistance();
            distance.value        = totalDistances;
            distance.unit         = "km";
            summary.totalDistance = distance;
            duration              = new RouteDuration();
            duration.value        = totalDurations;
            summary.totalDuration = duration;
            result.segments       = segments;
            result.summary        = summary;
            successCallback(result);
        }

        tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "find", _find);
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/geoBackend_local', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'), 
    utils = require('ripple/utils'),
    lbs = require('ripple/platform/tizen/2.0/lbs_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    PendingObject = require('ripple/platform/tizen/2.0/pendingObject'),
    PendingOperation = require('ripple/platform/tizen/2.0/pendingoperation'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    GeocodeResult = require('ripple/platform/tizen/2.0/GeocodeResult'),
    _GEO_OBJECTS = "tizen1.0-geocode-objects",
    _get, _save, _geoList_init, GeoEntry,
    _checkAddressType, _transAddressStr,
    _geocodeByString, _findCoordsByString, _geocodeByAddress,
    _reverseGeocodeBySimple, _reverseGeocodeByGeo, _checkCoordsType,
    _self, _geoList = [],
    _PENDING_TIME = 10;

function _get() {
    var geoList = [],
        data = db.retrieveObject(_GEO_OBJECTS);
    
    utils.forEach(data, function (geo) {
        geoList.push(geo);
    });
    return geoList;
}

function _save() {
    db.saveObject(_GEO_OBJECTS, _geoList);
}

function _geoList_init() {
    var entry;
    _geoList = _get();

    /* Put some default data if database is empty */
    if (_geoList.length === 0) {
        entry = new GeoEntry(new lbs.StructuredAddress({
            country : "UK",
            region : "London",
            county : "Lambeth",
            city : "London",
            street : "Westminster Bridge Road",
            streetNumber : "1",
            premises : "Riverside Building",
            additionalInformation : "London Eye",
            postalCode : "SE1 7PB"
        }),
            new lbs.GeoCoordinates({
            latitude : 51.510452,
            longitude : -0.119820,
            altitude : 0,
            accuracy : 0,
            altitudeAccuracy : 0,
            heading : 0,
            speed : 0
        }));
        _geoList.push(entry);
        entry = new GeoEntry(new lbs.StructuredAddress({
            country : "UK",
            city : "London",
            street : "Baker Street",
            streetNumber : "221B",
            postalCode : "NW1 6XE"
        }),
            new lbs.GeoCoordinates({
            latitude : 51.524552,
            longitude : -0.158615,
            altitude : 0,
            accuracy : 0,
            altitudeAccuracy : 0,
            heading : 0,
            speed : 0
        }));
        _geoList.push(entry);
        entry = new GeoEntry(new lbs.StructuredAddress({
            country : "US",
            region : "OR",
            city : "Portland",
            street : "SE Water Ave",
            streetNumber : "1945",
            additionalInformation : "OMSI",
        }),
            new lbs.GeoCoordinates({
            latitude : 45.508490,
            longitude : -122.665953,
            altitude : 0,
            accuracy : 0,
            altitudeAccuracy : 0,
            heading : 0,
            speed : 0
        }));
        _geoList.push(entry);
        entry = new GeoEntry(new lbs.StructuredAddress({
            country : "US",
            region : "OR",
            city : "Portland",
            street : "NW Pittock Drive",
            streetNumber : "3229",
            additionalInformation : "Pittock Mansion",
        }),
            new lbs.GeoCoordinates({
            latitude : 45.531365,
            longitude : -122.716255,
            altitude : 0,
            accuracy : 0,
            altitudeAccuracy : 0,
            heading : 0,
            speed : 0
        }));
        _geoList.push(entry);
        entry = new GeoEntry(new lbs.StructuredAddress({
            region : "OR",
            city : "Hillsboro",
            street : "NE 25th St",
            streetNumber : "2111",
            postalCode : "97124"
        }),
            new lbs.GeoCoordinates({
            latitude : 45.543479,
            longitude : -122.9621601,
            altitude : 0,
            accuracy : 0,
            altitudeAccuracy : 0,
            heading : 0,
            speed : 0
        }));
        _geoList.push(entry);
        _save();
    }
}

function _pendingOperate(operate) {
    var pendingObj, pendingOperation, i, argumentVector = [];

    for (i = 0; i < arguments.length - 1; i++)
        argumentVector[i] = arguments[i + 1];

    pendingObj = new PendingObject();

    pendingObj.pendingID = window.setTimeout(function () {
        pendingObj.setCancelFlag(false);
        operate.apply(this, argumentVector);
    }, _PENDING_TIME);

    pendingOperation = new PendingOperation(pendingObj);

    return pendingOperation;
}

function GeoEntry(addr, coord) {
    var _self;
    _self = {
        address : addr || null,
        coordinate : coord || null
    };
    return _self;
}

function SortMode() {
    var _self;
    _self = {
        attributeName : "",
        order : "ASC"
    };
    return _self;
}

function _transAddressStr(addr) {
    var str = "";
    if (addr.additionalInformation !== null && addr.additionalInformation !== undefined)
        str = str + addr.additionalInformation + ", ";
    if (addr.premises !== null && addr.premises !== undefined)
        str = str + addr.premises + ", ";
    if (addr.streetNumber !== null && addr.streetNumber !== undefined)
        str = str + addr.streetNumber + " ";
    if (addr.street !== null && addr.street !== undefined)
        str = str + addr.street + ", ";
    if (addr.city !== null && addr.city !== undefined)
        str = str + addr.city + ", ";
    if (addr.county !== null && addr.county !== undefined)
        str = str + addr.county + ", ";
    if (addr.region !== null && addr.region !== undefined)
        str = str + addr.region + ", ";
    if (addr.country !== null && addr.country !== undefined)
        str = str + addr.country + ", ";
    if (addr.postalCode !== null && addr.postalCode !== undefined)
        str = str + addr.postalCode;

    if (str.lastIndexOf(", ") === str.length - 2)
        str = str.slice(0, -2);
    return str;
}

function _concatAddress(addr) {
    var str = "";
    if (addr.additionalInformation !== null && addr.additionalInformation !== undefined)
        str = str + addr.additionalInformation + " ";
    if (addr.premises !== null && addr.premises !== undefined)
        str = str + addr.premises + " ";
    if (addr.streetNumber !== null && addr.streetNumber !== undefined)
        str = str + addr.streetNumber + " ";
    if (addr.street !== null && addr.street !== undefined)
        str = str + addr.street + " ";
    if (addr.city !== null && addr.city !== undefined)
        str = str + addr.city + " ";
    if (addr.county !== null && addr.county !== undefined)
        str = str + addr.county + " ";
    if (addr.region !== null && addr.region !== undefined)
        str = str + addr.region + " ";
    if (addr.country !== null && addr.country !== undefined)
        str = str + addr.country + " ";
    if (addr.postalCode !== null && addr.postalCode !== undefined)
        str = str + addr.postalCode;

    return str;
}

function _findCoordsByString(address) {
    var array = [], reg, str, searchAddr, pieces, i;
    if (address.length === 0)
        return array;

    pieces = address.split(",");
    searchAddr = "";
    for (i = 0; i < pieces.length; i++) {
        searchAddr = searchAddr + pieces[i];
    }
    reg = new RegExp(searchAddr, "i");
    
    utils.forEach(_geoList, function (item) {
        str = _concatAddress(item.address);
        if (str.search(reg) !== -1)
            array.push(new GeocodeResult(item.coordinate.latitude, item.coordinate.longitude));
    });

    return array;
}

function _geocodeByString(address, successCB, errorCB, options) {
    var array;
    array = _findCoordsByString(address);
    successCB(array);
}

function _findCoordsByAddress(addr) {
    var array = [], select = false, i;
    for (i = 0; i < _geoList.length; i++) {
        select = false;
        if (addr.country !== null && addr.country !== undefined) {
            if (addr.country === _geoList[i].address.country)
                select = true;
            else
                continue;
        }
        
        if (addr.region !== null && addr.region !== undefined) {
            if (addr.region === _geoList[i].address.region)
                select = true;
            else
                continue;
        }

        if (addr.county !== null && addr.county !== undefined) {
            if (addr.county === _geoList[i].address.county)
                select = true;
            else
                continue;
        }

        if (addr.city !== null && addr.city !== undefined) {
            if (addr.city === _geoList[i].address.city)
                select = true;
            else
                continue;
        }

        if (addr.street !== null && addr.street !== undefined) {
            if (addr.street === _geoList[i].address.street)
                select = true;
            else
                continue;
        }

        if (addr.streetNumber !== null && addr.streetNumber !== undefined) {
            if (addr.streetNumber === _geoList[i].address.streetNumber)
                select = true;
            else
                continue;
        }

        if (addr.premises !== null && addr.premises !== undefined) {
            if (addr.premises === _geoList[i].address.premises)
                select = true;
            else
                continue;
        }

        if (addr.additionalInformation !== null && 
            addr.additionalInformation !== undefined) {
            if (addr.additionalInformation === _geoList[i].address.additionalInformation)
                select = true;
            else
                continue;
        }

        if (addr.postalCode !== null && addr.postalCode !== undefined) {
            if (addr.postalCode === _geoList[i].address.postalCode)
                select = true;
            else
                continue;
        }

        if (select === true) {
            array.push(new GeocodeResult(_geoList[i].coordinate.latitude, _geoList[i].coordinate.longitude));
        }
    }

    return array;
}

function _geocodeByAddress(address, successCB, errorCB, options) {
    var array;
    array = _findCoordsByAddress(address);
    successCB(array);
}

function _checkAddressType(address) {
    var str;
    if (typeof address === "string") {
        str = "string";
    } else if (typeof address === "object") {
        str = "StructuredAddress";
    } else {
        str = "typeMismatch";
    }
    return str;
}

function _checkCoordsType(coord) {
    var str;
    /* SimpleCoordinates is a subset of GeoCoordinates.
       SimpleCoordinates includes latitude, longitude as mandatory fields only.
       GeoCoordinates not only includes latitude, longitude as mandatory fields 
       but also at least includes one more other optional fields */
    if (typeof coord !== "object") {
        str = "typeMismatch";
    } else if (typeof coord.latitude === "number" &&
                typeof coord.longitude === "number") {
        str = "simpleCoordinates";
        if (typeof coord.altitude === "number" ||
            typeof coord.accuracy === "number" ||
            typeof coord.altitudeAccuracy === "number" ||
            typeof coord.heading === "number" ||
            typeof coord.speed === "number") {
            str = "geoCoordinates";
        }
    } else {
        str = "typeMismatch";
    }

    return str;
}

function _findReverseGeocode(coords, options) {
    var array = [], _isStructured = false, i;
    if (options !== null && options !== undefined) {
        if (options.resultType === "STRUCTURED") {
            _isStructured = true;
        }
    }
    for (i = 0; i < _geoList.length; i++) {
        if (_geoList[i].coordinate.latitude === coords.latitude &&
            _geoList[i].coordinate.longitude === coords.longitude) {
            if (coords.altitude) {
                if (_geoList[i].coordinate.altitude !== coords.altitude)
                    continue;
            }
            if (coords.accuracy) {
                if (_geoList[i].coordinate.accuracy !== coords.accuracy)
                    continue;
            }
            if (coords.altitudeAccuracy) {
                if (_geoList[i].coordinate.altitudeAccuracy !== coords.altitudeAccuracy)
                    continue;
            }
            if (coords.heading) {
                if (_geoList[i].coordinate.heading !== coords.heading)
                    continue;
            }
            if (coords.speed) {
                if (_geoList[i].coordinate.speed !== coords.speed)
                    continue;
            }

            if (_isStructured === true) {
                array.push(new lbs.StructuredAddress(_geoList[i].address));
            } else {
                array.push(_transAddressStr(_geoList[i].address));
            }
        }
    }
    return array;
}

function _reverseGeocodeByGeo(coordinates, successCB, errorCB, options) {
    var array, coord;
    coord = new lbs.GeoCoordinates(coordinates);
    array = _findReverseGeocode(coord, options);
    return successCB(array);
}

function _reverseGeocodeBySimple(coordinates, successCB, errorCB, options) {
    var array, coord;
    coord = new lbs.GeoCoordinates({
            latitude : coordinates.latitude,
            longitude : coordinates.longitude
        });
    array = _findReverseGeocode(coord, options);
    return successCB(array);
}

module.exports = function (prop) {
    var _self = new lbs.LocationServiceProvider(prop);
    _geoList_init();
    
    _self.geocode = function (address, successCB, errorCB, options) {
        function _geocode() {
            var ret;
        
            ret = _pendingOperate(function () {
                /* address: its type is AbstractAddress. 
                   It could be StructuredAddress or String */
                if (_checkAddressType(address) === "string") {
                    _geocodeByString(address, successCB, errorCB, options);
                } else if (_checkAddressType(address) === "StructuredAddress") {
                    _geocodeByAddress(address, successCB, errorCB, options);
                } else {
                    throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
                }
            });
        }

        tizen1_utils.validateTypeMismatch(successCB, errorCB, "geocode", _geocode); 
    };

    _self.reverseGeocode = function (coordinates, successCB, errorCB, options) {
        function _reverseGeocode() {
            var ret;
            
            ret = _pendingOperate(function () {
                /* coordinates: Its type is AbstractCoordinates.
                   It could be SimpleCoordinates or GeoCoordinates */
                if (_checkCoordsType(coordinates) === "simpleCoordinates") {
                    _reverseGeocodeBySimple(coordinates, successCB, errorCB, options);
                } else if (_checkCoordsType(coordinates) === "geoCoordinates") {
                    _reverseGeocodeByGeo(coordinates, successCB, errorCB, options);
                } else {
                    throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
                }
            });
        }

        tizen1_utils.validateTypeMismatch(successCB, errorCB, "reverseGeocode", _reverseGeocode);
    };

    return _self;
};


});
define('ripple/platform/tizen/2.0/ContactAnniversary', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (date, label) {
    var _self, _date,
        _label = null;

    if (tizen1_utils.isValidDate(date)) {
        _date = new Date(date);
    } else {
        throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
    }

    if (label) {
        _label = String(label);
    }

    _self = {
        date : _date,
        label : _label
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/AlarmRelative', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var AlarmBase = require('ripple/platform/tizen/2.0/AlarmBase');

module.exports = function (delay, period) {
    var alarm, date;

    alarm  = new AlarmBase();
    delay  = delay || 0;
    period = period || null;
    date   = new Date(); // Alarm settime

    alarm.getRemainingSeconds = function () {
        var current, diff, triggerDate, MILLI_SECOND = 1000;
        current     = new Date();
        triggerDate = new Date(delay * MILLI_SECOND + date.getTime()); // First triggerDate
        diff        = Math.round((triggerDate - current) / MILLI_SECOND);

        if (diff > 0) // Before first trigger
            return diff;

        if (period === null)
            return null; // Alarm is expired

        while (current - triggerDate >= 0) { // Trigger repeatly
            triggerDate = new Date(period * MILLI_SECOND + triggerDate.getTime());
        }
        diff = Math.round(((triggerDate - current) / MILLI_SECOND));
        return diff;
    };

    alarm.__defineGetter__("delay", function () {
        return delay;
    });
    alarm.__defineGetter__("period", function () {
        return period;
    });
    alarm.__defineGetter__("date", function () {
        return date;
    });
    alarm.__defineSetter__("date", function (_date) {
        date = new Date(_date);
    });

    return alarm;
};

});
define('ripple/platform/tizen/2.0/SortMode', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (_attributeName, _order) {
    var _self;
    if (_attributeName !== null && _attributeName !== undefined) {
        if (typeof _attributeName !== "string") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }
    if (_order !== null && _order !== undefined) {
        if (_order !== "ASC" && _order !== "DESC") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }
    _self = {
        attributeName: _attributeName,
        order: _order,
    };

    return _self;
};


});
define('ripple/platform/tizen/2.0/AccountService', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (serviceName, serviceType, tag, displayName, icon, settings) {
    var _self,
        _id = Math.uuid(null, 16);

    _self = {
        serviceName : serviceName || "",
        serviceType : userName || "",
        displayName : displayName || null,
        icon : icon || null,
        settings : settings || null,
        tag : tag || []
    };

    _self.__defineGetter__("id", function () {
        return _id;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/BluetoothClass', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (prop) {
    var _self,
        _major = prop.major || 0,
        _minor = prop.minor || 0,
        _services = prop.services || [];

    _self = {
        hasService: function (service) {
            if (typeof service !== "string") {
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
            }

			return (_services.join(",").indexOf(service) !== -1);
        }
    };

    _self.__defineGetter__("major", function () {
        return _major;
    });
    _self.__defineGetter__("minor", function () {
        return _minor;
    });
    _self.__defineGetter__("services", function () {
        return _services;
    });
    return _self;
};

});
define('ripple/platform/tizen/2.0/BluetoothClassDeviceService', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function () {
    var _self = {};

    _self.__defineGetter__("LIMITED_DISCOVERABILITY", function () {
        return 0x0001;
    });
    _self.__defineGetter__("POSITIONING", function () {
        return 0x0008;
    });
    _self.__defineGetter__("NETWORKING", function () {
        return 0x0010;
    });
    _self.__defineGetter__("RENDERING", function () {
        return 0x0020;
    });
    _self.__defineGetter__("CAPTURING", function () {
        return 0x0040;
    });
    _self.__defineGetter__("OBJECT_TRANSFER", function () {
        return 0x0080;
    });
    _self.__defineGetter__("AUDIO", function () {
        return 0x0100;
    });
    _self.__defineGetter__("TELEPHONY", function () {
        return 0x0200;
    });
    _self.__defineGetter__("INFORMATION", function () {
        return 0x0400;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/AlarmAbsolute', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    AlarmBase = require('ripple/platform/tizen/2.0/AlarmBase'),
    _byDayValue = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"],
    PERIOD_WEEK = (7 * 24 * 60 * 60), MILLI_SECOND = 1000;

module.exports = function (date, frequency) {
    var alarm, period = null, daysOfTheWeek = [], ascDays = [];

    function checkDayValue(days) {
        var isDayType = false, i;
        for (i in days) {
            isDayType = utils.arrayContains(_byDayValue, days[i]);
            if (!isDayType)
                throw new WebAPIError(errorcode.TYPE_MISMATCH_ERR);
        }
        return days;
    }

    function getScheduleDateByPeriod(current, date, period) {
        var diff = period * MILLI_SECOND,
            triggerDate = new Date(date);

        while (current > (triggerDate - MILLI_SECOND)) { // In advance 1s - MILLI_SECOND
            triggerDate.setTime(triggerDate.getTime() + diff);
        }
        return triggerDate;
    }

    function getSchedulteDateByDay(current, triggerTime, startDay, endDay) {
        startDay = (7 + (endDay - startDay)) % 7;
        current.setHours(triggerTime.getHours());
        current.setMinutes(triggerTime.getMinutes());
        current.setSeconds(triggerTime.getSeconds());
        current.setMilliseconds(triggerTime.getMilliseconds());
        current.setDate(current.getDate() + startDay);
        return current;
    }

    function getAscDays() { // Get asc order array
        for (var i in daysOfTheWeek) {
            ascDays.push(_byDayValue.lastIndexOf(daysOfTheWeek[i]));
        }
        return ascDays.sort();
    }

    /*
     * Return
     *     true:  A is bigger than B
     *     false: otherwise
     */
    function compareTime(current, triggerTime) {
        var diff = current.getHours() - triggerTime.getHours();
        if (diff !== 0)
            return (diff > 0);

        diff = current.getMinutes() - triggerTime.getMinutes();
        if (diff !== 0)
            return (diff > 0);

        diff = current.getSeconds() - triggerTime.getSeconds();
        if (diff < -1) // Delay 1s
            return false;

        return true;
    }

    alarm = new AlarmBase();
    date = new Date(date);
    if (frequency !== undefined) {
        if (tizen1_utils.isValidArray(frequency)) {
            daysOfTheWeek = checkDayValue(frequency);
            if (daysOfTheWeek.length !== 0) {
                period = PERIOD_WEEK;
            }
        } else {
            period = frequency;
        }
    }

    alarm.getNextScheduledDate = function () {
        var current = new Date(),
            diff, isPass, today, total, i, nextDate;

        diff = current - date;
        if (diff < -1000) // Advance 1s
            return date; // Before first trigger, return date

        if (period === null)
            return null;

        if (period !== PERIOD_WEEK)
            return getScheduleDateByPeriod(current, date, period); // Repeat by period

        today = current.getDay(); // 0~6
        ascDays = getAscDays();
        total = ascDays.length;

        if ((ascDays[0] <= today) && (today <= ascDays[total - 1])) { // Today out of ascDays
            for (i in ascDays) { // Today in ascDays
                if (ascDays[i] < today) {
                    continue;
                } else if (ascDays[i] > today) {
                    nextDate = ascDays[i];
                    break;
                } else {
                    isPass = compareTime(current, date); // Is triggerTime pass
                    if (isPass) {
                        nextDate = ascDays[(i < total - 1) ? (parseInt(i, 10) + 1) : 0];
                    } else {
                        nextDate = today;
                    }
                    break;
                }
            }
        } else {
            nextDate = ascDays[0];
        }

        return getSchedulteDateByDay(current, date, today, nextDate);
    };

    alarm.__defineGetter__("date", function () {
        return date;
    });
    alarm.__defineGetter__("period", function () {
        return period;
    });
    alarm.__defineGetter__("daysOfTheWeek", function () {
        return daysOfTheWeek;
    });

    return alarm;
};

});
define('ripple/platform/tizen/2.0/sensors', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    sensors = require('ripple/platform/tizen/2.0/spec/sensor'),
    _sensors = ["Accelerometer", "MagneticField", "Rotation", "Orientation"],
    _permission = true,    
    _isWriteable = false, 
    _self;

function SensorError(code, msg) {
    this.__defineGetter__("message", function () {
        return msg;
    });
    this.__defineGetter__("code", function () {
        return code;
    });

    this.PERMISSION_DENIED = -100;
}

function SensorRequest() {
    var _self = {
        result: [],
        error: null,
        readyState: "processing"        
    };

    this.__defineGetter__("result", function () {
        return _self.result;
    });
    this.__defineSetter__("result", function (resultData) { 
        if (_isWriteable) {
            _self.result = utils.copy(resultData);
            _isWriteable = false;
            return;
        }
    });

    this.__defineGetter__("error", function () {
        return _self.error;
    });
    this.__defineSetter__("error", function (errorData) { 
        if (_isWriteable) {
            _self.error = utils.copy(errorData);
            _isWriteable = false;
            return;
        }
    });

    this.__defineGetter__("readyState", function () {
        return _self.readyState;
    });
    this.__defineSetter__("readyState", function (readyStateData) { 
        if (_isWriteable) {
            _self.readyState = readyStateData;
            _isWriteable = false;
            return;
        }
    });
}

_self = {  
    findSensors: function (type) {
        var sensorRequest = new SensorRequest(), index, sensorName = "";

        setTimeout(function () {
            if (_permission) {
                for (index = 0; index < _sensors.length; index++) {
                    sensorName = _sensors[index]; 
                    if (type === null || type === undefined || type === sensorName) {   
                        _isWriteable = true;                                     
                        sensorRequest.result.push(sensors[sensorName]);
                    }
                }

                _isWriteable = true;    
                sensorRequest.readyState = "done";

                if (sensorRequest.onsuccess) {
                    sensorRequest.onsuccess();
                }
            }
            else {
                // error event on the request with error code PERMISSION_DENIED must be fired.
                sensorRequest.error = new SensorError(-100, "permission denied!");
                if (sensorRequest.onerror) {
                    sensorRequest.onerror();
                }
            }
        }, 1);

        return sensorRequest;
    }
};

module.exports = _self;


});
define('ripple/platform/tizen/2.0/msg_utils', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


var db = require('ripple/db'),
    utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    MessageBody = require('ripple/platform/tizen/2.0/MessageBody'),
    _TIZEN_MESSAGE_DB_KEY = "tizen_db_messages",
    MessageElement = function (_type, _id) {
        return {
            type: _type,
            id: _id,
            msg: {},
            conv: {}
        };
    },

    _conversationCount = function (msg, cid, rst) {
        var old_time = new Date(0), t;

        utils.forEach(msg.msg, function (o) {
            if (o.priv.conversationId === cid &&
                o.priv.messageStatus !== "DRAFT") {
                rst.cnt += 1;
                t = new Date(o.priv.timestamp);
                if (t > old_time) {
                    rst.lastid = o.priv.id;
                    old_time = t;
                }
                if (o.isRead === false) {
                    rst.unread++;
                }
            }
        });
    },

    _updateConversation = function (msg, cid) {
        var privConv = {}, lastm, rst = {};

        rst.cnt = 0;
        rst.unread = 0;
        rst.lastid = "";
        _conversationCount(msg, cid, rst);
        if (rst.cnt === 0) {
            if (msg.conv[cid] !== undefined) {
                delete msg.conv[cid];
            }
            return;
        }
        lastm = msg.msg[rst.lastid];

        privConv.id = cid;
        privConv.type = msg.type;
        privConv.timestamp = new Date(lastm.priv.timestamp);
        privConv.messageCount = rst.cnt;
        privConv.unreadMessages = rst.unread;
        privConv.preview = lastm.body.plainBody;
        privConv.subject = lastm.subject;
        privConv.isRead = lastm.isRead;
        privConv.from = lastm.priv.from;
        privConv.to = lastm.to.slice(0);
        privConv.cc = lastm.cc.slice(0);
        privConv.bcc = lastm.bcc.slice(0);
        privConv.lastMessageId = rst.lastid;
        msg.conv[cid] = privConv;
    };

module.exports = {
    conversationCount: _conversationCount,
    setMsg: function (m, newm) {
        if ((m.to === null) || (m.to === undefined)) {
            newm.to = [];
        } else {
            if (tizen1_utils.isValidArray(m.to)) {
                newm.to = m.to.slice(0);
            } else {
                return false;
            }
        }

        if ((m.cc === null) || (m.cc === undefined)) {
            newm.cc = [];
        } else {
            if (tizen1_utils.isValidArray(m.cc)) {
                newm.cc = m.cc.slice(0);
            } else {
                return false;
            }
        }

        if ((m.bcc === null) || (m.bcc === undefined)) {
            newm.bcc = [];
        } else {
            if (tizen1_utils.isValidArray(m.bcc)) {
                newm.bcc = m.bcc.slice(0);
            } else {
                return false;
            }
        }

        if ((m.body === null) || (m.body === undefined)) {
            if (m.htmlBody === null || m.htmlBody === undefined) {
                m.htmlBody = "";
            }
            if (m.plainBody === null || m.plainBody === undefined) {
                m.plainBody = "";
            }
            if (typeof m.plainBody !== 'string' || typeof m.htmlBody !== 'string') {
                return false;
            }
            m.body = new MessageBody(null, true, m.plainBody, m.htmlBody, []);
        } else {
            if (typeof m.body.plainBody !== 'string' || typeof m.body.htmlBody !== 'string') {
                return false;
            }
            m.body = new MessageBody(null, true, m.body.plainBody, m.body.htmlBody, []);
        }
        newm.body = utils.copy(m.body);

        if (typeof m.isRead === 'boolean') {
            newm.isRead = m.isRead;
        } else {
            newm.isRead = false;
        }

        if (typeof m.isHighPriority === 'boolean') {
            newm.isHighPriority = m.isHighPriority;
        } else {
            newm.isHighPriority = false;
        }

        if ((m.subject === null) || (m.subject === undefined)) {
            newm.subject = "";
        } else {
            newm.subject = String(m.subject);
        }

        if ((m.inResponseTo === null) || (m.inResponseTo === undefined)) {
            newm.inResponseTo = null;
        } else {
            newm.inResponseTo = String(m.inResponseTo);
        }

        if ((m.attachments === null) || (m.attachments === undefined)) {
            newm.attachments = [];
        } else {
            newm.attachments = utils.copy(m.attachments);
        }
        return true;
    },

    loadMsg: function (type, id) {
        var i, ret, msg = db.retrieveObject(_TIZEN_MESSAGE_DB_KEY) || null;
        if (msg === null) {
            ret = new MessageElement(type, id);
        } else {
            for (i = 0; i < msg.length; i++) {
                if (msg[i].type === type && msg[i].id === id) {
                    ret = msg[i];
                    break;
                }
            }
            if (ret === undefined) {
                ret = new MessageElement(type, id);
            } else {
                /* after getting Date out of DB, Date will become
                   a string, so need to recast it back to Date */
                for (i in ret.msg) {
                    ret.msg[i].priv.timestamp = new Date(ret.msg[i].priv.timestamp);
                }
            }
        }
        return ret;
    },

    delMsg: function (m) { // m is a PrivMessage
        var i, _msg = db.retrieveObject(_TIZEN_MESSAGE_DB_KEY) || [];
        if (_msg.length === 0) {
            return;
        } else {
            for (i = 0; i < _msg.length; i++) {
                if (_msg[i].type === m.priv.type && _msg[i].id === m.priv.serviceId) {
                    delete _msg[i].msg[m.priv.id];
                    if (m.priv.messageStatus !== "DRAFT") {
                        _updateConversation(_msg[i], m.priv.conversationId);
                    }
                    db.saveObject(_TIZEN_MESSAGE_DB_KEY, _msg);
                    return;
                }
            }
        }
    },

    saveMsg: function (m) { // m is a PrivMessage
        var i, new_msg, _msg = db.retrieveObject(_TIZEN_MESSAGE_DB_KEY) || [];
        if (_msg.length === 0) {
            _msg = new MessageElement(m.priv.type, m.priv.serviceId);
            _msg.msg[m.priv.id] = m;
            if (m.priv.messageStatus !== "DRAFT") {
                _updateConversation(_msg, m.priv.conversationId);
            }
            db.saveObject(_TIZEN_MESSAGE_DB_KEY, [_msg]);
        } else {
            for (i = 0; i < _msg.length; i++) {
                if (_msg[i].type === m.priv.type && _msg[i].id === m.priv.serviceId) {
                    _msg[i].msg[m.priv.id] = m;
                    if (m.priv.messageStatus !== "DRAFT") {
                        _updateConversation(_msg[i], m.priv.conversationId);
                    }
                    db.saveObject(_TIZEN_MESSAGE_DB_KEY, _msg);
                    break;
                }
            }
            if (i === _msg.length) {
                new_msg = new MessageElement(m.priv.type, m.priv.serviceId);
                new_msg.msg[m.priv.id] = m;
                if (m.priv.messageStatus !== "DRAFT") {
                    _updateConversation(new_msg, m.priv.conversationId);
                }
                _msg.push(new_msg);
                db.saveObject(_TIZEN_MESSAGE_DB_KEY, _msg);
            }
        }
    },

    loadConv: function (type, id) {
        var i, ret;
        ret = this.loadMsg(type, id).conv;
        for (i in ret) {
            ret[i].timestamp = new Date(ret[i].timestamp);
        }
        return ret;
    }
};

});
define('ripple/platform/tizen/2.0/routeBackend_local', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    SimpleCoordinates = require('ripple/platform/tizen/2.0/SimpleCoordinates'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    lbs = require('ripple/platform/tizen/2.0/lbs'),
    LocationServiceProvider = {},
    RouteWaypoint,
    RouteDistance,
    RouteDuration,
    RouteStep,
    RouteSegment,
    RouteRequestOptions,
    RouteResultSummary,
    RouteResult,
    _data = {
        DB_ROUTE_LOCATION_KEY: "tizen1-db-route",
        DB_ROUTE_COLLEAGE_KEY: "tizen2-db-route",
        routeProvider: {},
        routes: [],
        RouteDistanceUnit: ["M", "KM", "MI", "FT"],
        providers: [],
        path: []
    },
    _self;

// The RouteWaypoint object
RouteWaypoint = function () {
    return {
        position: {
            latitude: 0,
            longitude: 0
        },
        isStopover: true
    };
};

// The RouteDistance object
RouteDistance = function () {
    return {
        text: "",
        value: 0,
        unit: "KM"
    };
};

// The RouteDuration object
RouteDuration = function () {
    return {
        text: "",
        value: 0 // The duration in a seconds
    };
};

// The RouteStep object
RouteStep = function () {
    var _self = {
        mode: "",        // The way of the travel, for example: car, bike, foot
        instruction: "", // The instruction of this step
        points: []       // The points of this step
    };

    _self.origin      = new SimpleCoordinates(0, 0);
    _self.destination = new SimpleCoordinates(0, 0);
    _self.distance    = new RouteDistance();
    _self.duration    = new RouteDuration();

    return _self;
};

// The RouteSegment object
RouteSegment = function () {
    var _self = {
        steps: []
    };

    _self.origin      = new SimpleCoordinates(0, 0);
    _self.destination = new SimpleCoordinates(0, 0);
    _self.distance    = new RouteDistance();
    _self.duration    = new RouteDuration();

    return _self;
};

// The RouteRequestOptions object
RouteRequestOptions = function () {
    return {
        mode: "", // CAR, BIKE
        unit: "KM",
        routeGoal: "SHORTEST",
        constraints: ["HIGHWAY", "TOLL", "UNPAVED"],
        wayPoints: [],
        maxResults: 1
    };
};

// The RouteResultSummary object
RouteResultSummary = function () {
    var _self = {};

    _self.origin        = new SimpleCoordinates(0, 0);
    _self.destination   = new SimpleCoordinates(0, 0);
    _self.totalDistance = new RouteDistance();
    _self.totalDuration = new RouteDuration();

    return _self;
};

// The RouteResult object
RouteResult = function () {
    var _self = {
        segments: []
    };

    _self.summary = new RouteResultSummary();

    return _self;
};

// Floyd arithmetic in Mathematics, solving the optimal way
function floyd(e, n, startIndex, endIndex) {
    var MAX = Infinity,
        a = new Array(n), i, j, k, p = new Array(n),
        paths, pathWay = [];

    for (i = 1; i < n + 1; i++) {
        a[i] = new Array(n);
    }
    for (i = 1; i < n + 1; i++) {
        p[i] = new Array(n);
    }
    for (i = 1; i < n + 1; i++) {
        for (j = 1; j < n + 1; j++) {
            if (i === j || e[i][j] === "MIN") {
                a[i][j] = 0;
            } else if (e[i][j] !== 0 && e[i][j] !== "MIN") {
                a[i][j] = e[i][j];
            } else {
                a[i][j] = MAX;
            }
            p[i][j] = 0;
        }
    }
    for (i = 1; i < n + 1; i++) {
        a[i][i] = 0;
    }
    for (k = 1; k < n + 1; k++) {
        for (i = 1; i < n + 1; i++) {
            for (j = 1; j < n + 1; j++) {
                if (parseInt(a[i][k], 10) + parseInt(a[k][j], 10) < a[i][j]) {
                    a[i][j] = parseInt(a[i][k], 10) + parseInt(a[k][j], 10);
                    p[i][j] = k;
                }
            }
        }
    }
    _data.path = [];
    paths = findPath(startIndex, endIndex, p);
    pathWay = [];
    pathWay.push(startIndex);
    for (i = 0; i < paths.length; i++) {
        pathWay.push(paths[i]);
    }
    pathWay.push(endIndex);

    return pathWay;
}

// Find the best way in the locations
function findPath(i, j, p) {
    var k = p[i][j];

    if (k === 0 || i === j) {
        return _data.path;
    }
    findPath(i, k, p);
    _data.path.push(k);

    return findPath(k, j, p);
}

// Find the index in the locations by string
function findIndexByStr(str, locations) {
    for (var i in locations) {
        if (locations[i].name === str) {
            return parseInt(i, 10) + 1;
        }
    }
    return -1;
}

// Find the index in the colleages by name1 and name2
function findValueByStr(start, end, locations, colleages) {
    for (var i in colleages) {
        if (colleages[i].name1 === locations[start - 1].name && colleages[i].name2 === locations[end - 1].name) {
            return parseInt(i, 10);
        } else if (colleages[i].name2 === locations[start - 1].name && colleages[i].name1 === locations[end - 1].name) {
            return parseInt(i, 10);
        }
    }
    return -1;
}

// Find the index in the locations by latitude and longitude
function searchIndexBycoodinates(latitude, longitude, locations) {
    if (latitude !== null && longitude !== null) {
        for (var i in locations) {
            if (locations[i].latitude === latitude && locations[i].longitude === longitude) {
                return parseInt(i, 10) + 1;
            }
        }
    }
    return -1;
}

// Get the relation among the locations
function getRelation(n, colleages, locations, goal) {
    var i, j, start, end, relation = new Array(n + 1);
    for (i = 1; i < n + 2; i++) {
        relation[i] = new Array(n + 1);
    }
    for (i = 1; i < n + 1; i++) {
        for (j = 1; j < n + 1; j++) {
            relation[i][j] = 0;
        }
    }
    for (i in colleages) {
        start = findIndexByStr(colleages[i].name1, locations);
        end = findIndexByStr(colleages[i].name2, locations);
        if (start !== -1 && end !== -1 && start !== end) {
            switch (goal) {
            case "distance":
                relation[start][end] = colleages[i].distance;
                relation[end][start] = colleages[i].distance;
                break;

            case "duration":
                relation[start][end] = colleages[i].duration;
                relation[end][start] = colleages[i].duration;
                break;

            case "simple":
                relation[start][end] = 1;
                relation[end][start] = 1;
                break;

            case "scenic":
                if (colleages[i].addition.scenic === "SCENIC") {
                    relation[start][end] = 1;
                    relation[start][end] = 1;
                } else if (colleages[i].addition.scenic === "") {
                    relation[start][end] = "MIN";
                    relation[start][end] = "MIN";
                }
                break;

            case "cheap":
                if (colleages[i].addition.toll === "TOLL") {
                    relation[start][end] = 1;
                    relation[end][start] = 1;
                } else if (colleages[i].addition.toll === "") {
                    relation[start][end] = "MIN";
                    relation[start][end] = "MIN";
                }
                break;

            case "safe":
                if (colleages[i].addition.hazardous === "HAZARDOUS") {
                    relation[start][end] = 1;
                    relation[end][start] = 1;
                } else if (colleages[i].addition.hazardous === "") {
                    relation[start][end] = "MIN";
                    relation[end][start] = "MIN";
                }
                break;

            default:
                return null;
            }
        }
    }

    return relation;
}

// Get the distance relationship among the locations
function distanceRelation(n, colleages, locations) {
    return getRelation(n, colleages, locations, "distance");
}

// Get the duration relationship among the locations
function durationRelation(n, colleages, locations) {
    return getRelation(n, colleages, locations, "duration");
}

// Get the simple relationship among the locations
function simpleRelation(n, colleages, locations) {
    return getRelation(n, colleages, locations, "simple");
}

// Get the cheap relationship among the locations
function cheapRelation(n, colleages, locations) {
    return getRelation(n, colleages, locations, "cheap");
}

// Get the safe relationship among the locations
function safeRelation(n, colleages, locations) {
    return getRelation(n, colleages, locations, "safe");
}

// Get the scenic relationship among the locations
function scenicRelation(n, colleages, locations) {
    return getRelation(n, colleages, locations, "scenic");
}

// Get the shortest way by origin, destination, locations and colleages
function optimalWay(origin, destination, locations, colleages, relation) {
    var n = locations.length, i, steps = [], step, relations, routeLocations,
        originIndex, destinationIndex, startIndex, endIndex, colleageIndex,
        originLatitude, originLongitude, destinationLatitude, destinationLongitude,
        startLatitude, startLongitude, endLatitude, endLongitude,
        originLocation, destinationLocation, segment, result;

    originLatitude = origin.latitude;
    originLongitude = origin.longitude;
    originIndex = searchIndexBycoodinates(originLatitude, originLongitude, locations);

    destinationLatitude = destination.latitude;
    destinationLongitude = destination.longitude;
    destinationIndex = searchIndexBycoodinates(destinationLatitude, destinationLongitude, locations);

    relations = relation(n, colleages, locations);

    if (originIndex !== -1 && destinationIndex !== -1) {
        routeLocations = floyd(relations, n, parseInt(originIndex, 10), parseInt(destinationIndex, 10));

        for (i = 0; i < routeLocations.length - 1; i++) {
            colleageIndex = findValueByStr(routeLocations[i], routeLocations[i + 1], locations, colleages);

            if (colleageIndex !== -1) {
                step = new RouteStep();
                startIndex = parseInt(routeLocations[i], 10) - 1;
                endIndex = parseInt(routeLocations[i + 1], 10) - 1;

                startLatitude = locations[startIndex].latitude;
                startLongitude = locations[startIndex].longitude;
                originLocation = new SimpleCoordinates(startLatitude, startLongitude);

                endLatitude = locations[endIndex].latitude;
                endLongitude = locations[endIndex].longitude;
                destinationLocation = new SimpleCoordinates(endLatitude, endLongitude);

                step.origin = originLocation;
                step.destination = destinationLocation;
                step.distance = colleages[colleageIndex].distance;
                step.duration = colleages[colleageIndex].duration;
                step.mode = colleages[colleageIndex].mode;
                step.addition = colleages[colleageIndex].addition;

                steps.push(step);
            } else if (colleageIndex === -1) {
                return null;
            }
        }

        segment = new RouteSegment();
        segment.steps = steps;
        result = new RouteResult();
        result.segments[0] = segment;

        return result;
    }
    return null;
}

// Get the shortest way by origin, destination, locations and colleages
function shortestWay(origin, destination, locations, colleages) {
    return optimalWay(origin, destination, locations, colleages, distanceRelation);
}

// Get the fastest way by origin, destination, locations and colleages
function fastestWay(origin, destination, locations, colleages) {
    return optimalWay(origin, destination, locations, colleages, durationRelation);
}

// Get the simplest way by origin, destination, locations and colleages
function simplestWay(origin, destination, locations, colleages) {
    return optimalWay(origin, destination, locations, colleages, simpleRelation);
}

// Get the most scenic way by origin, destination, locations and colleages
function mostScenicWay(origin, destination, locations, colleages) {
    return optimalWay(origin, destination, locations, colleages, scenicRelation);
}

// Get the cheapest way by origin, destination, locations and colleages
function cheapestWay(origin, destination, locations, colleages) {
    return optimalWay(origin, destination, locations, colleages, cheapRelation);
}

// Get the safest way by origin, destination, locations and colleages
function safestWay(origin, destination, locations, colleages) {
    return optimalWay(origin, destination, locations, colleages, safeRelation);
}

// Uniquelize the array
function uniquelize(array) {
    var temp = {}, result = [], i;
    for (i = array.length; i--;) {
        temp[array[i]] = array[i];
    }
    for (i in temp) {
        result.push(temp[i]);
    }
    return result;
}

// Is it intersect between the Array a and b
function intersect(a, b) {
    var i, j;

    a = uniquelize(a);
    if (a.length === 0 && b.length === 0) {
        return true;
    }
    for (i in a) {
        for (j in b) {
            if (a[i] === b[j])
                return true;
        }
    }
    return false;
}

function getConstrains(result) {
    var steps = result.segments[0].steps, constrains = [];

    utils.forEach(steps, function (item, index) {
        if (item.addition.highway === "HIGHWAY") {
            constrains.push("HIGHWAY");
        }
        if (item.addition.toll === "TOLL") {
            constrains.push("TOLL");
        }
        if (item.addition.bridge === "BRIDGE") {
            constrains.push("BRIDGE");
        }
        if (item.addition.hazardous === "HAZARDOUS") {
            constrains.push("HAZARDOUS");
        }
        if (item.addition.scenic === "SCENIC") {
            constrains.push("SCENIC");
        }
    });
    if (constrains.length > 0) {
        return uniquelize(constrains);
    }
    return constrains;
}

module.exports = function (prop) {
    var _self = new lbs.LocationServiceProvider(prop);
    _self.find = function (origin, destination, successCallback, errorCallback, options) {
        function _find() {
            var locations, colleages, i, result = {}, emptyResult = [], modes = [], resultModes = [], constrains = [], resultconstrains = [];

            locations = db.retrieveObject(_data.DB_ROUTE_LOCATION_KEY);
            colleages = db.retrieveObject(_data.DB_ROUTE_COLLEAGE_KEY);

            modes = options.modes;
            constrains = options.constrains;
            if (locations.length > 0 && colleages.length > 0) {
                switch (options.routeGoal) {
                case "SHORTEST":
                    result = shortestWay(origin, destination, locations, colleages);
                    break;

                case "FASTEST":
                    result = fastestWay(origin, destination, locations, colleages);
                    break;

                case "SIMPLEST":
                    result = simplestWay(origin, destination, locations, colleages);
                    break;

                case "MOST_SCENIC":
                    result = mostScenicWay(origin, destination, locations, colleages);
                    break;

                case "CHEAPEST":
                    result = cheapestWay(origin, destination, locations, colleages);
                    break;

                case "SAFEST":
                    result = safestWay(origin, destination, locations, colleages);
                    break;

                default:
                    result = shortestWay(origin, destination, locations, colleages);
                    break;
                }
                if (result !== null) {
                    for (i in result.segments[0].steps) {
                        resultModes.push(result.segments[0].steps[i].mode);
                    }
                    resultconstrains = getConstrains(result);
                    if (intersect(resultModes, modes) && intersect(resultconstrains, constrains)) {
                        successCallback(result);
                    } else {
                        successCallback(null);
                    }
                }
            } else {
                successCallback(emptyResult);
            }
        }
        tizen1_utils.validateTypeMismatch(successCallback, errorCallback, "find", _find);
    };
    return _self;
};

});
define('ripple/platform/tizen/2.0/dbfs', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    _console = require('ripple/console'),
    _cache = {},
    _self;

function _get(path) {
    return path.replace(/^\//, '').split("/").reduce(function (obj, token) {
        return token === "" ? obj : (obj.children ? obj.children[token] || null : null);
    }, _cache);
}

function _getInfo(path) {
    var parent = ("/" + path.replace(/^\//, '').replace(/\/$/, '')).split("/"),
        name = parent.splice(parent.length - 1, 1).join("");

    return {
        name: name,
        parent: parent.join("/") || "/"
    };
}

function _set(path, obj) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    parent.children = parent.children || {};
    parent.children[child] = obj;
}

function _delete(path) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    delete parent.children[child];
}

function _save() {
    db.saveObject("tizen1-db-filesystem", _cache);
}

function _walk(path, parent) {
    _self.ls(path, function (entries) {
        parent.children = parent.children || {};

        entries.forEach(function (entry) {
            parent.children[entry.name] = entry;

            if (entry.isDirectory) {
                _walk(entry.fullPath, entry);
            } else {
                /* after getting Date out of DB, Date will become
                   a string, so need to recast it back to Date */
                if (entry.lastModifiedDate !== null && entry.lastModifiedDate !== undefined)
                    entry.lastModifiedDate = new Date(entry.lastModifiedDate);

                _self.read(entry.fullPath, function (data) {
                    parent.children[entry.name].data = data;
                }, function (e) {
                    _console.error(e);
                });
            }
        });
    }, function (e) {
        _console.error(e);
    });
}

function _createPath(path) {
    var parts = path.replace(/^\//, '').split("/"),
        workflow = jWorkflow.order();

    parts.forEach(function (part, index) {
        var dir = "/" + utils.copy(parts).splice(0, index + 1).join("/");

        workflow.andThen(function (prev, baton) {
            baton.take();
            _self.mkdir(dir, baton.pass, baton.pass);
        });
    });

    workflow.start();
}

_self = {
    // The order is consistent with _virtualRoots in filesystem.js
    roots: ["/opt/documents", "/opt/images", "/opt/music", "/opt/videos", "/opt/downloads", "/home/user/appdata/simulatedapp/wgt-package", "/home/user/appdata/simulatedapp/wgt-private", "/home/user/appdata/simulatedapp/wgt-private-tmp", "/SDCard", "/opt/attachments"],
    initialize: function () {
        // TODO: Initialize at bootstrap and emulatorBridge.link
        _cache = db.retrieveObject("tizen1-db-filesystem") || {};
        // create real root paths if empty
        _self.roots.every(function (root) {
            _createPath(root);
            return true;
        });
       // build the file system cache so that we could access information synchronously
        _walk("/", _cache);
    },
    ls: function (path, success, error) {
        try {
            var dir = _get(path),
                items = [];

            if (dir) {
                utils.forEach(dir.children, function (item) {
                    items.push(item);
                });
            }
            else {
                items = {};
            }

            success(items);
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },
    rm: function (path, success, error, options) {
        _delete(path);
        _save();
        success();
    },
    rmdir: function (path, success, error, options) {
        _delete(path);
        _save();
        success();
    },
    mkdir: function (path, success, error) {
        var entry = _get(path),
            info = _getInfo(path);

        if (!entry) {
            _set(path, {
                name: info.name,
                isDirectory: true,
                fullPath: path
            });
            entry = _get(path);
            _save();
        }

        if (entry) {
            success(entry);
        }
        else {
            error({code: 1});
        }
    },
    mv: function (from, to, success, error) {
        try {
            var fromEntry = _get(from),
                toInfo = _getInfo(to);

            fromEntry.fullPath = to;
            fromEntry.name = toInfo.name;

            _set(to, fromEntry);
            _delete(from);
            _save();
            success();
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },
    touch: function (path, success, error) {
        var entry = _get(path),
            info  = _getInfo(path);

        if (!entry) {
            _set(path, {
                lastModifiedDate: new Date(),
                name: info.name,
                isDirectory: false,
                fullPath: path,
                data: ""
            });
            entry = _get(path);
        }
        _save();
        success(entry);
    },
    cp: function (from, to, success, error) {
        try {
            var fromEntry = _get(from),
                copied = utils.copy(fromEntry);

            copied.name  = _getInfo(to).name;
            copied.fullPath = to;
            _set(to, copied);
            _save();
            success();
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },
    stat: function (path, success, error) {
        var entry = _get(path);

        if (entry) {
            success(entry);
        } else {
            error({code: 1});
        }
    },
    write: function (path, contents, success, error, options) {
        var entry = _get(path);

        if (entry) {
            entry.lastModifiedDate = new Date();
            entry.data = contents;
            _save();
            success();
        } else {
            error({code: 1});
        }

    },
    read: function (path, success, error) {
        var entry = _get(path);

        if (entry) {
            success(utils.copy(entry.data));
        }
        else {
            error({code: 1});
        }
    }
};

module.exports = _self;


});
define('ripple/platform/tizen/2.0/DeviceMotionEvent', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    Event = require('ripple/platform/tizen/2.0/EventBase');

module.exports = function () {
    var _self = {
            acceleration: {
                x: null,
                y: null,
                z: null
            },
            accelerationIncludingGravity: {
                x: null,
                y: null,
                z: null
            },
            rotationRate: {
                alpha: null,
                beta: null,
                gamma: null
            },
            interval: 0
        };

    Event.call(this);

    this.__defineGetter__("acceleration", function () {
        return _self.acceleration;
    });

    this.__defineGetter__("accelerationIncludingGravity", function () {
        return _self.accelerationIncludingGravity;
    });

    this.__defineGetter__("rotationRate", function () {
        return _self.rotationRate;
    });

    this.__defineGetter__("interval", function () {
        return _self.interval;
    });

    this.initAccelerometerEvent = function (accelerometerType, accelerometerBubbles, accelerometerCancelable,
                                            accelerationData, accelerationGData, rotationRateData, intervalValue) {
        this.initEvent(accelerometerType, accelerometerBubbles, accelerometerCancelable);

        _self.acceleration = utils.copy(accelerationData);
        _self.accelerationIncludingGravity = utils.copy(accelerationGData);
        _self.rotationRate = utils.copy(rotationRateData);
        _self.interval = intervalValue;
    };
};


});
define('ripple/platform/tizen/2.0/BluetoothServiceHandler', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use _self file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    event = require('ripple/event'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError');

module.exports = function (prop) {
    var _self,
        _uuid = prop.uuid || "",
        _name = prop.name || "",
        _isConnected = prop.isConnected || false,
        _security = prop.metaData || {};

    _self = {
        onconnect : null,
        unregister : function (successCallback, errorCallback) {
            if (!_security.all && !_security.unregister) {
                throw new WebAPIError(errorcode.SECURITY_ERR);
            }

            tizen1_utils.validateCallbackType(successCallback, errorCallback);
            event.trigger("bt-unregister-service", [_uuid, successCallback, errorCallback]);
        }
    };

    _self.__defineGetter__("uuid", function () {
        return _uuid;
    });
    _self.__defineGetter__("name", function () {
        return _name;
    });
    _self.__defineGetter__("isConnected", function () {
        return _isConnected;
    });

    return _self;
};

});
define('ripple/platform/tizen/2.0/GeocodeOptions', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    SortMode = require('ripple/platform/tizen/2.0/SortMode');

module.exports = function (_sortMode, _maxResults) {
    var _self;
    if (_sortMode !== null && _sortMode !== undefined) {
        if (typeof _sortMode !== "object") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
        try {
            new SortMode(_sortMode.attributeName, _sortMode.order);
        } catch (e) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }
    if (_maxResults !== null && _maxResults !== undefined) {
        if (typeof _maxResults !== "number") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }
    }

    _self = {
        sortMode : _sortMode,
        maxResults : _maxResults || 0
    };

    return _self;
};


});
define('ripple/platform/tizen/2.0/spec/sensor', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

function sensorStatusEventTrigger(setting) {
    event.trigger("SensorStatusChanged", [setting]);
}

module.exports = {
    "Accelerometer": {
        "resolution": 0.039239998906850815,
        "minDelay": 20,
        "range": 20.051639556884766,
        "name": "Accelerometer",
        "type": "Accelerometer"
    },
    "MagneticField": {
        "x": {
            "name": "X",
            "control": {
                "type": "range",
                "value": 100.0000000000000000,
                "min": 0.0000000000000000,
                "max": 200.0000000000000000,
                "step": 0.0000000000000001
            },
            "callback": function (setting) {
                event.trigger("MagneticField-xChanged", [setting]);
            }
        },

        "y": {
            "name": "Y",
            "control": {
                "type": "range",
                "value": 100.0000000000000000,
                "min": 0.0000000000000000,
                "max": 200.0000000000000000,
                "step": 0.0000000000000001
            },
            "callback": function (setting) {
                event.trigger("MagneticField-yChanged", [setting]);
            }
        },

        "z": {
            "name": "Z",
            "control": {
                "type": "range",
                "value": 100.0000000000000000,
                "min": 0.0000000000000000,
                "max": 200.0000000000000000,
                "step": 0.0000000000000001
            },
            "callback": function (setting) {
                event.trigger("MagneticField-zChanged", [setting]);
            }
        },

        "resolution": 1,
        "minDelay": 20,
        "range": 359,
        "name": "MagneticField",
        "type": "MagneticField"
    },
    "Rotation": {
        "resolution": 1,
        "minDelay": 20,
        "range": 359,
        "name": "Rotation",
        "type": "Rotation"
    },
    "Orientation": {
        "resolution": 1,
        "minDelay": 20,
        "range": 359,
        "name": "Orientation",
        "type": "Orientation"
    }
};

});
define('ripple/platform/tizen/2.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    utils = require('ripple/utils'),
    NetworkTypeTable = {
        "NONE": "None",
        "2G": "2G",
        "2.5G": "2.5G",
        "3G": "3G",
        "4G": "4G",
        "WIFI": "Wi-Fi",
        "ETHERNET": "Ethernet",
        "UNKNOWN": "Unknown"
    };

function deviceStatusEventTrigger(setting) {
    event.trigger("DeviceStatusChanged", [setting]);
}

module.exports = {
    "Config": {
        "vibratingMode": {
            "name": "Vibrator",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("VibratingModeChanged", [setting]);
            }
        },
        "lockScreen": {
            "name": "Lock Screen",
            "control": {
                "type": "checkbox",
                "value": false
            },
            "callback": function (setting) {
                event.trigger("LockScreenChanged", [setting]);
            }
        }
    },    
    "Cpu": {
        "load": {
            "name": "Load",
            "control": {
                "type": "text",
                "value": 0.1
            },
            "event": "CpuLoadChanged",
            "callback": function (setting) {
                event.trigger("CpuLoadChanged", [setting]);
            }
        }
    },
    "Storage": {
        "units": {
            "name": "Units",
            "control": {
                "type": "label",
                "innertext": "INTERNAL",
                "value": "INTERNAL"
            },
        }
    },
    "Display": {
        "resolutionWidth": {
            "name": "Resolution Width",
            "control": {
                "type": "label",
                "innertext": 0,
                "value": 0
            }
        }, 
        "resolutionHeight": {
            "name": "Resolution Height",
            "control": {
                "type": "label",
                "value": 0
            }
        },     
        "dotsPerInchWidth": {
            "name": "DPI-X",
            "control": {
                "type": "label",
                "value": 0
            }
        },     
        "dotsPerInchHeight": {
            "name": "DPI-Y",
            "control": {
                "type": "label",
                "value": 0
            }
        },
        "physicalWidth": {
            "name": "Physical Width",
            "control": {
                "type": "label",
                "value": 0
            }
        },
        "physicalHeight": {
            "name": "Physical Height",
            "control": {
                "type": "label",
                "value": 0
            }
        },
        "brightness": {
            "name": "Brightness",
            "control": {
                "type": "number",
                "value": 0.8,
            },
            "event": "DisplayBrightnessChanged",
            "callback": function (setting) {
                event.trigger("DisplayBrightnessChanged", [setting]);
            }
        }
    },    
    "Device": {
        "imei": {
            "name": "IMEI",
            "control": {
                "type": "label",
                "value": "352099001761482"
            }
        }, 
        "model": {
            "name": "GT-TIZEN",
            "control": {
                "type": "label",
                "value": ""
            }
        }, 
        "version": {
            "name": "Version",
            "control": {
                "type": "label",
                "value": "TIZEN_1.0"
            }
        }, 
        "vendor": {
            "name": "Vendor",
            "control": {
                "type": "label",
                "value": ""
            }
        }
    },
    "Network": {
        "networkType": {
            "name": "Network Type",
            "control" : {
                "type": "select",
                "value": 0
            },
            "options": (function () {
                var i,
                    optionList = {};
                utils.forEach(NetworkTypeTable, function(key, value) {
                    optionList[key] = NetworkTypeTable[value];
                });

                return optionList;
            }()),
            "event": "NetworkTypeChanged",
            "callback": function (setting) {
                event.trigger("NetworkTypeChanged", [setting]);
            }
        }
    },
    "WifiNetwork": {
        "status": {
            "name": "Status",
            "control": {
                "type": "checkbox",
                "value": false
            },
            "event": "WiFiNetworkStatusChanged",
            "callback": function (setting) {
                event.trigger("WiFiNetworkStatusChanged", [setting]);
            }
        },
        "ssid": {
            "name": "SSID",
            "control": {
                "type": "text",
                "value": "Tizen WiFi"
            },
            "event": "WiFiNetworkSSIDChanged",
            "callback": function (setting) {
                event.trigger("WiFiNetworkSSIDChanged", [setting]);
            }
        }, 
        "ipAddress": {
            "name": "IP Address",
            "control": {
                "type": "text",
                "value": "192.168.0.1"
            },
            "event": "WiFiNetworkIpAddressChanged",
            "callback": function (setting) {
                event.trigger("WiFiNetworkIpAddressChanged", [setting]);
            }
        }, 
        "signalStrength": {
            "name": "Signal Strength",
            "control": {
                "type": "select",
                "value": 0
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 10; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "event": "WiFiNetworkSignalStrengthChanged",
            "callback": function (setting) {
                event.trigger("WiFiNetworkSignalStrengthChanged", [setting]);
            }
        }
    },
    "CellularNetwork": {
        "status": {
            "name": "Status",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "CellularNetworkStatusChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkStatusChanged", [setting]);
            }
        },
        "apn": {
            "name": "APN",
            "control": {
                "type": "text",
                "value": "Tizen"
            },
            "event": "CellularNetworkapnChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkapnChanged", [setting]);
            }
        },
        "ipAddress": {
            "name": "IP Address",
            "control": {
                "type": "text",
                "value": "10.0.2.16"
            },
            "event": "CellularNetworkipAddressChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkipAddressChanged", [setting]);
            }
        },         
        "mcc": {
            "name": "MCC",
            "control": {
                "type": "text",
                "value": "460"
            },
            "event": "CellularNetworkmccChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkmccChanged", [setting]);
            }
        }, 
        "mnc": {
            "name": "MNC",
            "control": {
                "type": "text",
                "value": "0"
            },
            "event": "CellularNetworkmncChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkmncChanged", [setting]);
            }
        }, 
        "cellId": {
            "name": "Cell ID",
            "control": {
                "type": "text",
                "value": "0"
            },
            "event": "CellularNetworkcellIdChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkcellIdChanged", [setting]);
            }
        }, 
        "lac": {
            "name": "LAC",
            "control": {
                "type": "text",
                "value": "0"
            },
            "event": "CellularNetworklacChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworklacChanged", [setting]);
            }
        }, 
        "serviceType": {
            "name": "Service Type",
            "control": {
                "type": "text",
                "value": "INTERNET"
            },
            "event": "CellularNetworkserviceTypeChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkserviceTypeChanged", [setting]);
            }
        }, 
        "isRoaming": {
            "name": "Roaming",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "CellularNetworkIsInRoamingChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkIsInRoamingChanged", [setting]);
            }
        }
    },
    "EthernetNetwork": {
        "status": {
            "name": "Status",
            "control": {
                "type": "checkbox",
                "value": false
            },
            "event": "EthernetStatusChanged",
            "callback": function (setting) {
                event.trigger("EthernetStatusChanged", [setting]);
            }
        },
        "ipAddress": {
            "name": "IP Address",
            "control": {
                "type": "text",
                "value": "192.168.0.1"
            },
            "event": "EthernetIpAddressChanged",
            "callback": function (setting) {
                event.trigger("EthernetIpAddressChanged", [setting]);
            }
        },
        "ipv6Address": {
            "name": "IPv6 Address",
            "control": {
                "type": "text",
                "value": "192.168.0.1"
            },
            "event": "EthernetIpv6AddressChanged",
            "callback": function (setting) {
                event.trigger("EthernetIpv6AddressChanged", [setting]);
            }
        },
        "proxyAddress": {
            "name": "Proxy Address",
            "control": {
                "type": "text",
                "value": "192.168.0.30"
            },
            "event": "EthernetProxyAddressChanged",
            "callback": function (setting) {
                event.trigger("EthernetProxyAddressChanged", [setting]);
            }
        },
        "macAddress": {
            "name": "MAC Address",
            "control": {
                "type": "text",
                "value": "11:22:33:44:55:66"
            },
            "event": "EthernetMacAddressChanged",
            "callback": function (setting) {
                event.trigger("EthernetMacAddressChanged", [setting]);
            }
        },
        "gateway": {
            "name": "Gateway",
            "control": {
                "type": "text",
                "value": "192.168.0.254"
            },
            "event": "EthernetGatewayChanged",
            "callback": function (setting) {
                event.trigger("EthernetGatewayChanged", [setting]);
            }
        },
        "dns": {
            "name": "DNS",
            "control": {
                "type": "text",
                "value": "192.168.30.50"
            },
            "event": "EthernetDnsChanged",
            "callback": function (setting) {
                event.trigger("EthernetDnsChanged", [setting]);
            }
        },
        "subnetMask": {
            "name": "Subnet Mask",
            "control": {
                "type": "text",
                "value": "192.168.0.0"
            },
            "event": "EthernetSubnetMaskChanged",
            "callback": function (setting) {
                event.trigger("EthernetSubnetMaskChanged", [setting]);
            }
        }
    },
    "SIM": {
        "operatorName": {
            "name": "Operator Name",
            "control": {
                "type": "text",
                "value": "Tizen"
            },
            "event": "SimOperatorNameChanged",
            "callback": function (setting) {
                event.trigger("SimOperatorNameChanged", [setting]);
            }
        },
        "msisdn": {
            "name": "MSISDN",
            "control": {
                "type": "text",
                "value": "088123456789"
            },
            "event": "SimMsisdnChanged",
            "callback": function (setting) {
                event.trigger("SimMsisdnChanged", [setting]);
            }
        },
        "iccid": {
            "name": "ICCID",
            "control": {
                "type": "text",
                "value": "123000MFSSYYGXXXXXXP"
            },
            "event": "SimIccidChanged",
            "callback": function (setting) {
                event.trigger("SimIccidChanged", [setting]);
            }
        },
        "mcc": {
            "name": "MCC",
            "control": {
                "type": "text",
                "value": "460"
            },
            "event": "SimMccChanged",
            "callback": function (setting) {
                event.trigger("SimMccChanged", [setting]);
            }
        },
        "mnc": {
            "name": "MNC",
            "control": {
                "type": "text",
                "value": "0"
            },
            "event": "SimMncChanged",
            "callback": function (setting) {
                event.trigger("SimMncChanged", [setting]);
            }
        },
        "msin": {
            "name": "MSIN",
            "control": {
                "type": "text",
                "value": "H1 H2 H3 S 12345"
            },
            "event": "SimMsinChanged",
            "callback": function (setting) {
                event.trigger("SimMsinChanged", [setting]);
            }
        },
        "spn": {
            "name": "SPN",
            "control": {
                "type": "text",
                "value": "TizenSPN"
            },
            "event": "SimSpnChanged",
            "callback": function (setting) {
                event.trigger("SimSpnChanged", [setting]);
            }
        }
    }

};


});
define('ripple/platform/tizen/2.0/spec/btdevices', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {
    "22:33:44:12:34:56": {
        "name": "Tizen Phone",
        "address": "22:33:44:12:34:56",
        "deviceClass": {
            "major": 0x02,
            "majorName": "PHONE",
            "minor": 0x03,
            "minorName": "PHONE_SMARTPHONE",
            "services": [0x0080],
            "servicesName": ["OBJECT_TRANSFER"]
        },
        "isTrusted": false,
        "services": {
            "5bce9431-6c75-32ab-afe0-2ec108a30860" : {
                "name": "Data Exchange",
                "uuid": "5bce9431-6c75-32ab-afe0-2ec108a30860",
                "protocol": "RFCOMM"
            },
            "3537d485-0c1e-445a-a066-43fafcfb61d1" : {
                "name": "Data Transfer",
                "uuid": "3537d485-0c1e-445a-a066-43fafcfb61d1",
                "protocol": "RFCOMM"
            }
        }
    },
    "22:33:44:12:34:88": {
        "name": "Keyboard",
        "address": "22:33:44:12:34:88",
        "deviceClass": {
            "major": 0x05,
            "majorName": "PERIPHERAL",
            "minor": 0x10,
            "minorName": "PERIPHERAL_KEYBOARD",
            "services": [0x0080],
            "servicesName": ["OBJECT_TRANSFER"]
        },
        "isTrusted": true,
        "services": {
            "3537d485-0c1e-445a-a066-43fafcfb61d1" : {
                "name": "Data Exchange",
                "uuid": "3537d485-0c1e-445a-a066-43fafcfb61d1",
                "protocol": "RFCOMM"
            }
        }
    },
    "22:33:44:88:34:58": {
        "name": "Tizen Laptop",
        "address": "22:33:44:88:34:58",
        "deviceClass": {
            "major": 0x01,
            "majorName": "COMPUTER",
            "minor": 0x03,
            "minorName": "COMPUTER_LAPTOP",
            "services": [0x0080],
            "servicesName": ["OBJECT_TRANSFER"]
        },
        "isTrusted": true,
        "services": {
            "3537d485-0c1e-445a-a066-43fafcfb61d1" : {
                "name": "Data Exchange",
                "uuid": "3537d485-0c1e-445a-a066-43fafcfb61d1",
                "protocol": "RFCOMM"
            }
        }
    }
};

});
define('ripple/platform/tizen/2.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "sensors",
        "communication",
        "geoView",
        "widgetConfig",
        "deviceSettings",
        "application",
        "network",
        "power",
        "download"
    ]
};

});
define('ripple/platform/tizen/2.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var platform = require('ripple/platform'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    constants = require('ripple/constants');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (configValidationObject) {
        var valid = true;
        // no xmlns:JIL in wac 2.0 spec
        valid = !!configValidationObject.widget.validationResult[0].attributes.xmlns.valid;

        return valid;
    },
    extractInfo: function (configValidationObject) {
        if (!configValidationObject) {
            return null;
        }

        var widgetInfo = {},
            configFeatures,
            configPreferences,
            preferenceName,
            platform;

        widgetInfo.id = configValidationObject.widget.validationResult[0].attributes.id.value || "";
        widgetInfo.name = configValidationObject.widget.children.name.validationResult[0].value;
        widgetInfo.icon = configValidationObject.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = configValidationObject.widget.validationResult[0].attributes.version.value;

        widgetInfo.features = {};

        configFeatures = configValidationObject.widget.children.feature.validationResult;
        utils.forEach(configFeatures, function (f) {
            if (f.valid === true) {
                var feature = {id: f.attributes.name.value,
                         required: f.attributes.required.valid};
                widgetInfo.features[feature.id] = feature;
            }
        });

        widgetInfo.preferences = {};

        configPreferences = configValidationObject.widget.children.preference.validationResult;

        platform = require('ripple/platform');
        utils.forEach(configPreferences, function (preference) {
            preferenceName = preference.attributes.name.value;
            if (preferenceName) {
                widgetInfo.preferences[preferenceName] = {
                    "key": preferenceName,
                    "value": preference.attributes.value.value || "",
                    "readonly": preference.attributes.readonly.value === "true"
                };

                db.save(preferenceName,
                        widgetInfo.preferences[preferenceName].value,
                        platform.getPersistencePrefix(widgetInfo.id));
            }
        });

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            helpText: "\"widget\" element describes widget information in configuration documents and serves as a container for other elements. It must be used in the configuration document and may have the following child elments: name,description,icon,author,license,content,feature and preference.The \"widget\" element MAY have following attributes: id,version,height,width, defaultlocale, xml:lang and dir",
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xmlns:tizen": {
                    attributeName: "xmlns:tizen",
                    required: false,
                    type: "list",
                    listValues: ["http://tizen.org/ns/widgets"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                },
                dir: {
                    attributeName: "dir",
                    required: false,
                    type: "list",
                    listValues: ["ltr", "rtl", "lro", "rlo"]
                },
                id: {
                    attributeName: "id",
                    required: false,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    required: false,
                    type: "string"
                },
                height: {
                    attributeName: "height",
                    required: false,
                    type: "integer"
                },
                width: {
                    attributeName: "width",
                    required: false,
                    type: "integer"
                },
                viewmodes: {
                    attributeName: "viewmodes",
                    required: false,
                    type: "list",
                    listValues: ["windowed", "floating", "fullscreen", "maximized", "minimized"]
                },
                defaultlocale: {
                    attributeName: "defaultlocale",
                    required: false,
                    type: "iso-language"
                },
            },
            children: {
                name: {
                    nodeName: "name",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                            unique: true
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        "short": {
                            attributeName: "short",
                            required: false,
                            type: "string"
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                            unique: true
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        href: {
                            attributeName: "href",
                            required: false,
                            type: "regex",
                            regex: constants.REGEX.URL
                        },
                        email: {
                            attributeName: "email",
                            required: false,
                            type: "regex",
                            regex: constants.REGEX.EMAIL
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        src: {
                            attributeName: "src",
                            required: true,
                            type: "string"
                        },
                        width: {
                            attributeName: "width",
                            required: false,
                            type: "integer"
                        },
                        height: {
                            attributeName: "height",
                            required: false,
                            type: "integer"
                        }
                    }
                },
                content: {
                    nodeName: "content",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                            unique: true
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        src: {
                            attributeName: "src",
                            required: true,
                            type: "string"
                        },
                        encoding: {
                            attributeName: "encoding",
                            required: false,
                            type: "string"
                        },
                        type: {
                            attributeName: "type",
                            required: false,
                            type: "string"
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        name: {
                            attributeName: "name",
                            required: true,
                            type: "list",
                            listValues: ["http://www.w3.org/TR/geolocation-API/",
                                         "http://www.w3.org/TR/battery-status/",
                                         "http://www.w3.org/TR/vibration/",
                                         "http://www.w3.org/TR/touch-events/",
                                         "http://wacapps.net/api/deviceapis", "http://wacapps.net/api/accelerometer",
                                         "http://wacapps.net/api/orientation", "http://wacapps.net/api/camera",
                                         "http://wacapps.net/api/camera.show", "http://wacapps.net/api/camera.capture",
                                         "http://wacapps.net/api/devicestatus", "http://wacapps.net/api/devicestatus.deviceinfo",
                                         "http://wacapps.net/api/devicestatus.networkinfo", "http://wacapps.net/api/filesystem",
                                         "http://wacapps.net/api/filesystem.read", "http://wacapps.net/api/filesystem.write",
                                         "http://wacapps.net/api/messaging", "http://wacapps.net/api/messaging.send",
                                         "http://wacapps.net/api/messaging.find", "http://wacapps.net/api/messaging.subscribe",
                                         "http://wacapps.net/api/messaging.write", "http://wacapps.net/api/pim.contact",
                                         "http://wacapps.net/api/pim.contact.read", "http://wacapps.net/api/pim.contact.write",
                                         "http://wacapps.net/api/pim.calendar", "http://wacapps.net/api/pim.calendar.read",
                                         "http://wacapps.net/api/pim.calendar.write", "http://wacapps.net/api/pim.task",
                                         "http://wacapps.net/api/pim.task.read", "http://wacapps.net/api/pim.task.write",
                                         "http://wacapps.net/api/deviceinteraction",
                                         "http://tizen.org/api/tizen", "http://tizen.org/api/application",
                                         "http://tizen.org/api/application.launch", "http://tizen.org/api/application.kill",
                                         "http://tizen.org/api/application.read",
                                         "http://tizen.org/api/time", "http://tizen.org/api/time.read",
                                         "http://tizen.org/api/time.write", "http://tizen.org/api/alarm",
                                         "http://tizen.org/api/alarm.read", "http://tizen.org/api/alarm.write",
                                         "http://tizen.org/api/contact", "http://tizen.org/api/contact.read",
                                         "http://tizen.org/api/contact.write", "http://tizen.org/api/filesystem",
                                         "http://tizen.org/api/filesystem.write", "http://tizen.org/api/filesystem.read",
                                         "http://tizen.org/api/calendar", "http://tizen.org/api/calendar.read",
                                         "http://tizen.org/api/calendar.write", "http://tizen.org/api/call",
                                         "http://tizen.org/api/call.state", "http://tizen.org/api/lbs",
                                         "http://tizen.org/api/call.history", "http://tizen.org/api/call.history.read",
                                         "http://tizen.org/api/call.history.write", "http://tizen.org/api/messaging",
                                         "http://tizen.org/api/messaging.send", "http://tizen.org/api/messaging.read",
                                         "http://tizen.org/api/messaging.write",
                                         "http://tizen.org/api/bluetooth", "http://tizen.org/api/bluetooth.admin",
                                         "http://tizen.org/api/bluetooth.gap", "http://tizen.org/api/bluetooth.spp",
                                         "http://tizen.org/api/nfc", "http://tizen.org/api/nfc.tag",
                                         "http://tizen.org/api/nfc.p2p",
                                         "http://tizen.org/api/geocoder",
                                         "http://tizen.org/api/mediacontent", "http://tizen.org/api/systeminfo",
                                         "http://tizen.org/api/sensors", "http://tizen.org/api/power", "http://tizen.org/api/download",
                                         "http://tizen.org/api/notification"]
                        },
                        required: {
                            attributeName: "required",
                            type: "boolean",
                            required: false
                        }
                    },
                    children: {
                        param: {
                            nodeName: "param",
                            required: false,
                            occurrence: 0,
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                },
                                name: {
                                    attributeName: "name",
                                    required: true,
                                    type: "string",
                                },
                                value: {
                                    attributeName: "value",
                                    required: true,
                                    type: "string",
                                }
                            }
                        }
                    }
                },
                preference: {
                    nodeName: "preference",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        name: {
                            attributeName: "name",
                            required: true,
                            type: "string"
                        },
                        value: {
                            type: "string",
                            required: false,
                            attributeName: "value"
                        },
                        readonly: {
                            attributeName: "readonly",
                            type: "boolean",
                            required: false
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/tizen/2.0/ApplicationService', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    ApplicationServiceData = require('ripple/platform/tizen/2.0/ApplicationServiceData');

module.exports = function (operation, uri, mime, data) {
    var _self, i;

    _self = {
        operation: "",
        url: "",
        mime: "",
        data: [],
        replyResult: function (data) {
            event.trigger("appServiceReplied", "Result: " + data);
        },
        replyFailure: function () {
            event.trigger("appServiceReplied", "Failure");
        }
    };

    _self.operation = String(operation);
    if (uri) {
        _self.uri = String(uri);
    }
    if (mime) {
        _self.mime = String(mime);
    }
    if (tizen1_utils.isValidArray(data)) {
        for (i in data) {
            _self.data.push(new ApplicationServiceData(data[i].key, data[i].value));
        }
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/ContactOrganization', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

module.exports = function (prop) {
    var _self;
    _self = {
        name : null,
        department : null,
        office : null,
        title : null,
        role : null,
        logoURI : null,
    };

    if (prop) {
        if (prop.name !== null && prop.name !== undefined) {
            _self.name = String(prop.name);
        }
        if (prop.department !== null && prop.department !== undefined) {
            _self.department = String(prop.department);
        }
        if (prop.office !== null && prop.office !== undefined) {
            _self.office = String(prop.office);
        }
        if (prop.title !== null && prop.title !== undefined) {
            _self.title = String(prop.title);
        }
        if (prop.role !== null && prop.role !== undefined) {
            _self.role = String(prop.role);
        }
        if (prop.logoURI !== null && prop.logoURI !== undefined) {
            _self.logoURI = String(prop.logoURI);
        }
    }

    return _self;
};

});
define('ripple/platform/tizen/2.0/spec', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {

    id: "tizen",
    version: "2.0",
    name: "TIZEN",

    persistencePrefix: "tizen1-",

    config: require('ripple/platform/tizen/2.0/spec/config'),
    ui: require('ripple/platform/tizen/2.0/spec/ui'),
    device: require('ripple/platform/tizen/2.0/spec/device'),
    sensor: require('ripple/platform/tizen/2.0/spec/sensor'),
    DeviceMotionEvent: require('ripple/platform/tizen/2.0/DeviceMotionEvent'),
    DeviceOrientationEvent: require('ripple/platform/tizen/2.0/DeviceOrientationEvent'),

    objects: {
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        SensorConnection: {
            path: "w3c/1.0/SensorConnection"
        },
        navigator: {
            path: "tizen/2.0/navigator",
            children: {
                geolocation: {
                    path: "wac/2.0/geolocation",
                    feature: "http://www.w3.org/TR/geolocation-API/"
                },
                battery: {
                    path: "tizen/2.0/battery",
                    feature: "http://www.w3.org/TR/battery-status/"
                }
            }
        },
        tizen: {
            feature: "http://tizen.org/api/tizen",
            children: {
                CompositeFilter: {
                    path: "tizen/2.0/CompositeFilter"
                },
                AttributeFilter: {
                    path: "tizen/2.0/AttributeFilter"
                },
                AttributeRangeFilter: {
                    path: "tizen/2.0/AttributeRangeFilter"
                },
                SortMode: {
                    path: "tizen/2.0/SortMode"
                },
                alarm: {
                    path: "tizen/2.0/alarm",
                    feature: "http://tizen.org/api/alarm|http://tizen.org/api/alarm.read|http://tizen.org/api/alarm.write",
                    handleSubfeatures: true
                },
                AlarmRelative: {
                    path: "tizen/2.0/AlarmRelative"
                },
                AlarmAbsolute: {
                    path: "tizen/2.0/AlarmAbsolute"
                },
                download: {
                    path: "tizen/2.0/download",
                    feature: "http://tizen.org/api/download"
                },
                URLDownload: {
                    path: "tizen/2.0/URLDownload",
                },
                notification: {
                    path: "tizen/2.0/notification",
                    feature: "http://tizen.org/api/notification",
                },
                StatusNotification: {
                    path: "tizen/2.0/StatusNotification"
                },
                Account: {
                    path: "tizen/2.0/AccountBase"
                },
                AccountService: {
                    path: "tizen/2.0/AccountService"
                },
                account: {
                    path: "tizen/2.0/account",
                    feature: "http://tizen.org/api/account"
                },
                application: {
                    path: "tizen/2.0/application",
                    feature: "http://tizen.org/api/application|http://tizen.org/api/application.launch|http://tizen.org/api/application.kill|http://tizen.org/api/application.read",
                    handleSubfeatures: true
                },
                ApplicationService: {
                    path: "tizen/2.0/ApplicationService"
                },
                ApplicationServiceData: {
                    path: "tizen/2.0/ApplicationServiceData"
                },
                bluetooth: {
                    path: "tizen/2.0/bluetooth",
                    feature: "http://tizen.org/api/bluetooth|http://tizen.org/api/bluetooth.admin|http://tizen.org/api/bluetooth.gap|http://tizen.org/api/bluetooth.spp",
                    handleSubfeatures: true
                },
                ContactName: {
                    path: "tizen/2.0/ContactName"
                },
                ContactOrganization: {
                    path: "tizen/2.0/ContactOrganization"
                },
                ContactWebSite: {
                    path: "tizen/2.0/ContactWebSite"
                },
                ContactAnniversary: {
                    path: "tizen/2.0/ContactAnniversary"
                },
                ContactAccount: {
                    path: "tizen/2.0/ContactAccount"
                },
                ContactAddress: {
                    path: "tizen/2.0/ContactAddress"
                },
                ContactPhoneNumber: {
                    path: "tizen/2.0/ContactPhoneNumber"
                },
                ContactEmailAddress: {
                    path: "tizen/2.0/ContactEmailAddress"
                },
                ContactRef: {
                    path: "tizen/2.0/ContactRef"
                },
                Contact: {
                    path: "tizen/2.0/ContactBase"
                },
                call: {
                    path: "tizen/2.0/call",
                    feature: "http://tizen.org/api/call|http://tizen.org/api/call.history|http://tizen.org/api/call.history.read|http://tizen.org/api/call.history.write",
                    handleSubfeatures: true
                },
                SimpleCoordinates: {
                    path: "tizen/2.0/SimpleCoordinates"
                },
                TZDate: {
                    path: "tizen/2.0/TZDate"
                },
                TimeDuration: {
                    path: "tizen/2.0/TimeDuration"
                },
                Message: {
                    path: "tizen/2.0/Message"
                },
                time: {
                    path: "tizen/2.0/time",
                    feature: "http://tizen.org/api/time|http://tizen.org/api/time.read|http://tizen.org/api/time.write",
                    handleSubfeatures: true
                },
                contact: {
                    path: "tizen/2.0/contact",
                    feature: "http://tizen.org/api/contact|http://tizen.org/api/contact.read|http://tizen.org/api/contact.write",
                    handleSubfeatures: true
                },
                calendar: {
                    path: "tizen/2.0/calendar",
                    feature: "http://tizen.org/api/calendar|http://tizen.org/api/calendar.read|http://tizen.org/api/calendar.write",
                    handleSubfeatures: true
                },
                CalendarTask: {
                    path: "tizen/2.0/CalendarTask"
                },
                CalendarEvent: {
                    path: "tizen/2.0/CalendarEvent"
                },
                CalendarAttendee: {
                    path: "tizen/2.0/CalendarAttendee"
                },
                CalendarRecurrenceRule: {
                    path: "tizen/2.0/CalendarRecurrenceRule"
                },
                CalendarEventId: {
                    path: "tizen/2.0/CalendarEventId"
                },
                CalendarAlarm: {
                    path: "tizen/2.0/CalendarAlarm"
                },
                messaging: {
                    path: "tizen/2.0/messaging",
                    feature: "http://tizen.org/api/messaging|http://tizen.org/api/messaging.send|http://tizen.org/api/messaging.read|http://tizen.org/api/messaging.write",
                    handleSubfeatures: true
                },
                nfc: {
                    path: "tizen/2.0/nfc",
                    feature: "http://tizen.org/api/nfc|http://tizen.org/api/nfc.tag|http://tizen.org/api/nfc.p2p",
                    handleSubfeatures: true
                },
                lbs: {
                    children: {
                        geocoder: {
                            path: "tizen/2.0/geocoder",
                            feature: "http://tizen.org/api/geocoder"
                        },
                        GeoRectBounds: {
                            path: "tizen/2.0/GeoRectBounds"
                        },
                        GeoCircleBounds: {
                            path: "tizen/2.0/GeoCircleBounds"
                        },
                        GeoPolyBounds: {
                            path: "tizen/2.0/GeoPolyBounds"
                        },
                        GeometryFilter: {
                            path: "tizen/2.0/GeometryFilter"
                        }
                    }
                },
                mediacontent: {
                    path: "tizen/2.0/mediacontent",
                    feature: "http://tizen.org/api/mediacontent"
                },
                sensors: {
                    path: "tizen/2.0/sensors",
                    feature: "http://tizen.org/api/sensors"
                },
                systeminfo: {
                    path: "tizen/2.0/systeminfo",
                    feature: "http://tizen.org/api/systeminfo"
                },
                filesystem: {
                    path: "tizen/2.0/filesystem",
                    feature: "http://tizen.org/api/filesystem|http://tizen.org/api/filesystem.read|http://tizen.org/api/filesystem.write"
                },
                power: {
                    path: "tizen/2.0/power",
                    feature: "http://tizen.org/api/power"
                },
                PowerStateRequest: {
                    path: "tizen/2.0/PowerStateRequest",
                    feature: "http://tizen.org/api/power"
                }
            }
        }
    }
};

});
define('ripple/platform/tizen/2.0/ContactWebSite', function (require, exports, module) {
/*      
 *  Copyright 2012 Intel Corporation.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

module.exports = function (url, type) {
    var _self, _url, _type;

    if (url) {
        _url = String(url);
    }

    if (type) {
        _type = String(type).toUpperCase();
    }

    _self = {
        url : _url,
        type: _type
    };

    return _self;
};

});
define('ripple/platform/tizen/2.0/GeoPolyBounds', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (_points) {
    var points = _points || [];

    this.__defineGetter__("points", function () {
        return points;
    });
};

});
define('ripple/platform/tizen/2.0/MessageFolder', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (opt) {
    var folder = {}, _id = opt.id, _parentId = null, _serviceId = opt.serviceId,
        _contentType = opt.contentType, _name = opt.id, _path = opt.path,
        _type = opt.type, _synchronizable = opt.synchronizable;

    folder.name = _name;
    folder.synchronizable = _synchronizable;
    
    folder.__defineGetter__("id", function () {
        return _id;
    });
    folder.__defineGetter__("parentId", function () {
        return _parentId;
    });
    folder.__defineGetter__("serviceId", function () {
        return _serviceId;
    });
    folder.__defineGetter__("contentType", function () {
        return _contentType;
    });
    folder.__defineGetter__("path", function () {
        return _path;
    });
    folder.__defineGetter__("type", function () {
        return _type;
    });
    return folder;
};

});
define('ripple/platform/tizen/2.0/pendingoperation', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (pendingObj) {
    var pending = true;
    this.cancel = function () {
        if (pending === true) {
            if (typeof (pendingObj.getCancelFlag) === "function" && pendingObj.getCancelFlag() === false) {
                pending = false;
                // this clearTimeout is for the case when a 3rd party is invoked to do the task, and it's finished sooner than the intended timeout. therefore, the 3rd party set CancelFlag false, and this cancel is called before timeout
                clearTimeout(pendingObj.pendingID);
                return false;
            }
            if (typeof (pendingObj.userCancel) === "function") {
                pendingObj.userCancel();
            }
            clearTimeout(pendingObj.pendingID);
            pending = false;
            return true;
        } else {
            return false;
        }
    };
};


});
define('ripple/platform/tizen/2.0/WebAPIError', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/tizen/2.0/errorcode');

var msg = {
    0: "Generic Error",
    1: "Index or size is negative, or greater than the allowed value.",
    2: "Specified range of text does not fit into a DOMString.",
    3: "Node is inserted somewhere it doesn't belong.",
    4: "Node is used in a different document than the one that created it (that doesn't support it).",
    5: "An invalid or illegal character is specified.",
    6: "Data is specified for a Node which does not support data.",
    7: "An attempt is made to modify an object where modifications are not allowed.",
    8: "An attempt is made to reference a Node in a context where it does not exist.",
    9: "The implementation does not support the requested type of object or operation.",
    10: "An attempt is made to add an attribute that is already in use elsewhere.",
    11: "An attempt is made to use an object that is not, or is no longer, usable.",
    12: "An invalid or illegal string is specified.",
    13: "An attempt is made to modify the type of the underlying object.",
    14: "An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.",
    15: "A parameter or an operation is not supported by the underlying object.",
    16: "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to \"partial validity\", this exception would be raised and the operation would not be done.",
    17: "The type of an object is incompatible with the expected type of the parameter associated to the object.",
    18: "An attempt is made to perform an operation or access some data in a way that would be a security risk or a violation of the user agent's security policy.",
    19: "A network error occurs in synchronous requests.",
    20: "The abort error occurs in asynchronous requests by user prompt.",
    21: "The operation could not be completed because the URL does not match.",
    22: "The quota has been exceeded.",
    23: "The operation timed out.",
    24: "The supplied node is incorrect or has an incorrect ancestor for this operation.",
    25: "The object can not be cloned.",
    99: "The content of an object does not include valid values.",
    100: "Error occurred in communication with the underlying implementation that meant the requested method could not complete.",
    111: "Requested service is not available."
},
    errType = {
    0: "UnknownError",
    1: "IndexSizeError",
    2: "DOMStringSizeError",
    3: "HierarchyRequestError",
    4: "WrongDocumentError",
    5: "InvalidCharacterError",
    6: "NoDataAllowedError",
    7: "NoModificationAllowedError",
    8: "NotFoundError",
    9: "NotSupportedError",
    10: "InuseAttributeError",
    11: "InvalidStateError",
    12: "SyntaxError",
    13: "InvalidModificationError",
    14: "NamespaceError",
    15: "InvalidAccessError",
    16: "ValidationError",
    17: "TypeMismatchError",
    18: "SecurityError",
    19: "NetworkError",
    20: "AbortError",
    21: "URLMismatchError",
    22: "QuotaExceededError",
    23: "TimeoutError",
    24: "InvalidNodeTypeError",
    25: "DataCloneError",
    99: "InvalidValueError",
    100: "IOError",
    111: "ServiceNotAvailableError"
};

/*
  support 3 types of error:
  - WebAPIError()
      code = errorcode.UNKNOWN_ERR
      message = errorcode.message[UNKNOWN_ERR]
  - WebAPIError(errorcode."TYPE_MISMATCH_ERR")
      code = 17
      message = errorcode.message[17]
  - WebAPIError(my_own_error_code, "This is my error message.")
      code = my_own_error_code(number)
      message = "This is my error message."
*/

module.exports = function (code, message, name) {
    var g, c, _code, _message, _name;

    for (c in errorcode) {
        g = errorcode.__lookupGetter__(c);
        if (g) {
            this.__defineGetter__(c, g);
        }
    }

    if (typeof code !== 'number') {
        _code = errorcode.UNKNOWN_ERR;
        _message = msg[_code];
        _name = errType[_code];
    } else {
        _code = code;
        if (typeof message === 'string') {
            _message = message;
        } else {
            _message = msg[_code];
        }
        if (typeof name === 'string') {
            _name = name;
        } else {
            _name = errType[_code];
        }
    }

    this.__defineGetter__("code", function () {
        return _code;
    });
    this.__defineGetter__("message", function () {
        return _message;
    });
    this.__defineGetter__("name", function () {
        return _name;
    });
};

});
define('ripple/platform/tizen/2.0/notification', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    tizen1_utils = require('ripple/platform/tizen/2.0/tizen1_utils'),
    event = require('ripple/event'),
    errorcode = require('ripple/platform/tizen/2.0/errorcode'),
    WebAPIError = require('ripple/platform/tizen/2.0/WebAPIError'),
    _notificationStack,
    _self;

function _checkServiceProperties(service) {
    if (typeof service !== "object") {
        return false;
    }

    if (typeof service.operation !== "string") {
        return false;
    }

    if (service.uri && typeof service.uri !== "string") {
        return false;
    }

    if (service.mime && typeof service.mime !== "string") {
        return false;
    }

    if (service.data && !tizen1_utils.isValidArray(service.data)) {
        return false;
    }

    if (typeof service.replyResult !== "function") {
        return false;
    }

    if (typeof service.replyFailure !== "function") {
        return false;
    }

    return true;
}

function _validateNotification(notification) {
    if (typeof notification !== "object") {
        return false;
    }

    if (typeof notification.id !== "string") {
        return false;
    }

    if (typeof notification.type !== "string" || notification.type !== "STATUS") {
        return false;
    }

    if (typeof notification.statusType !== "string" ||
        !(notification.statusType === "SIMPLE" || notification.statusType === "ONGOING" || notification.statusType === "PROGRESS")) {
        return false;
    }

    if (typeof notification.title !== "string") {
        return false;
    }

    if (notification.content && typeof notification.content !== "string") {
        return false;
    }

    if (notification.iconPath && typeof notification.iconPath !== "string") {
        return false;
    }

    if (notification.soundPath && typeof notification.soundPath !== "string") {
        return false;
    }

    if (notification.vibration && typeof notification.vibration !== "boolean") {
        return false;
    }

    if (notification.service && !_checkServiceProperties(notification.service)) {
        return false;
    }

    if (notification.statusType === "PROGRESS" && notification.progressValue && typeof notification.progressValue !== "number") {
        return false;
    }

    return true;
}

_self = {
    post : function (notification) {
        if (!_validateNotification(notification)) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (notification.statusType === "PROGRESS" && notification.progressValue &&
            (notification.progressValue < 1 || notification.progressValue > 100)) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }

        if (!_notificationStack[notification.id]) {
            Object.defineProperty(notification, "postedTime", {value: new Date().toString(), writable: false});
            _notificationStack[notification.id] = utils.copy(notification);
            db.saveObject("posted-notifications", _notificationStack);
            event.trigger("refreshNotificationUI", [], true);
        }
    },
    update : function (notification) {
        if (!_validateNotification(notification)) {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (notification.statusType === "PROGRESS" && notification.progressValue &&
            (notification.progressValue < 1 || notification.progressValue > 100)) {
            throw new WebAPIError(errorcode.INVALID_VALUES_ERR);
        }

        if (_notificationStack[notification.id]) {
            _notificationStack[notification.id] = utils.copy(notification);
            db.saveObject("posted-notifications", _notificationStack);
            event.trigger("refreshNotificationUI", [], true);
        }

    },
    remove : function (id) {
        if (typeof id !== "string") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (!_notificationStack[id]) {
            throw (new WebAPIError(errorcode.NOT_FOUND_ERR));
        }

        delete _notificationStack[id];
        db.saveObject("posted-notifications", _notificationStack);
        event.trigger('refreshNotificationUI', [], true);
    },
    removeAll : function () {
        _notificationStack = {};
        db.saveObject("posted-notifications", _notificationStack);
        event.trigger('refreshNotificationUI', [], true);
    },
    get : function (id) {
        if (typeof id !== "string") {
            throw (new WebAPIError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (!_notificationStack[id]) {
            throw (new WebAPIError(errorcode.NOT_FOUND_ERR));
        }

        return utils.copy(_notificationStack[id]);
    },
    getAll : function () {
        var notifications = [];
        utils.forEach(_notificationStack, function (item) {
            notifications.push(utils.copy(item));
        });
        return notifications;
    }
};

function _initilize() {
    _notificationStack = db.retrieveObject("posted-notifications") || {};
    event.on("refreshNotificationStack", function () {
        _notificationStack = db.retrieveObject("posted-notifications");
    });
}

_initilize();

module.exports = _self;
});
define('ripple/platform/webworks.core/2.0.0/fsCache', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var fs = require('ripple/dbfs'),
    utils = require('ripple/utils'),
    _console = require('ripple/console'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    bbUtils = require('ripple/platform/webworks.core/2.0.0/client/utils'),
    FileProperties = require('ripple/platform/webworks.core/2.0.0/client/FileProperties'),
    _cache = {},
    _self;

function _createPath(path) {
    var parts = path.replace(/^\//, '').replace(/\/$/, '').split("/"),
        workflow = jWorkflow.order();

    parts.forEach(function (part, index) {
        var dir = "/" + utils.copy(parts).splice(0, index + 1).join("/");

        workflow.andThen(function (prev, baton) {
            baton.take();
            fs.mkdir(dir, baton.pass, baton.pass);
        });
    });

    workflow.start(_self.refresh);
}
event.on("FileSystemInitialized", function () {
    _createPath("/SDCard");
    _createPath("/store/home/user/music");
    _createPath("/store/home/user/pictures");
    _createPath("/store/home/user/videos");
    _createPath("/store/home/user/videos");
    _createPath("/accounts/1000/appdata/emulatedapp/data");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/bookmarks");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/books");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/camera");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/documents");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/downloads");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/misc");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/music");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/photos");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/print");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/videos");
    _createPath("/accounts/1000/appdata/emulatedapp/shared/voice");
});

function _fsError(e) {
    _self.refresh();
    if (e.code !== 1) { // suppress file not found error
        _console.error("FileSystem error (code " + e.code + ")");
    }
}

function _walk(path, parent) {
    fs.ls(path, function (entries) {
        parent.children = parent.children || {};

        entries.forEach(function (entry) {
            parent.children[entry.name] = entry;
            parent.children[entry.name].properties = {};

            if (entry.isDirectory) {
                _walk(entry.fullPath, entry);
            } else {
                entry.file(function (file) {
                    utils.mixin(file, parent.children[entry.name].properties);
                });
                fs.read(entry.fullPath, function (data) {
                    parent.children[entry.name].data = data;
                }, function (e) {
                    console.error(e);
                });
            }
        });
    }, function (e) {
        console.error(e);
    });
}

function _get(path) {
    return path.replace(/^\//, '').split("/").reduce(function (obj, token) {
        return token === "" ? obj : (obj && obj.children ? obj.children[token] || null : null);
    }, _cache);
}

function _getInfo(path) {
    var parent = ("/" + path.replace(/^\//, '').replace(/\/$/, '')).split("/"),
        name = parent.splice(parent.length - 1, 1).join(""),
        ext = name.split(".");

    return {
        name: name,
        extension: ext.length > 1 ? ext[ext.length - 1] : "",
        hidden: (name.length > 0 && name[0] === ".") || false,
        parent: parent.join("/") || "/"
    };
}

function _set(path, obj) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').replace(/\/$/, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    parent.children = parent.children || {};
    obj.properties = obj.properties || {};
    parent.children[child] = obj;
}

function _delete(path) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').replace(/\/$/, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    delete parent.children[child];
}

// TODO: handle exceptions so that any respective fs command can error out
// TODO: dateCreated is always dateModified

_self = {
    refresh: function () {
        _cache = {};
        _walk("/", _cache);
    },
    file: {
        exists: function (path) {
            var entry = _get(path);
            return !!(entry && !entry.isDirectory);
        },

        deleteFile: function (path) {
            _delete(path);
            fs.rm(path, function () {}, _fsError);
        },

        copy: function (from, to) {
            var fromEntry = _get(from);

            _set(to, {
                fullPath: to,
                properties: fromEntry.properties,
                data: fromEntry.data
            });

            fs.cp(from, to, function (entry) {
                entry.file(function (file) {
                    entry.properties = entry.properties || {};
                    utils.mixin(file, entry.properties);
                    _set(to, entry);
                });
            }, _fsError);
        },

        getFileProperties: function (path) {
            var entry = _get(path),
                info = _getInfo(path);

            fs.stat(path, function () {}, _fsError);

            return new FileProperties({
                //HACK: not sure where these should come from so check both for now.
                dateCreated: entry.properties.lastModifiedDate || entry.lastModifiedDate,
                dateModified: entry.properties.lastModifiedDate || entry.lastModifiedDate,
                directory: info.parent,
                fileExtension: info.extension,
                isHidden: info.hidden,
                isReadonly: false,
                mimeType: entry.properties.type,
                size: entry.properties.size
            });
        },

        rename: function (path, newName) {
            _self.dir.rename(path, newName);
        },

        readFile: function (path, success, async) {
            var entry = _get(path);

            async = async === false ? async : true;

            if (!async) {
                success(bbUtils.stringToBlob(entry.data));
            }
            else {
                fs.read(path, function (data) {
                    var blob = bbUtils.stringToBlob(data);
                    if (async) {
                        success(blob);
                    }
                    entry.data = data;
                    _set(path, entry);
                }, _fsError);
            }
        },

        saveFile: function (path, blob) {
            var data = bbUtils.blobToString(blob);

            _set(path, {
                lastModifiedDate: new Date(),
                fullPath: path,
                isDirectory: false,
                properties: {
                    type: "",
                    size: blob.size
                },
                data: data
            });

            fs.write(path, data, function (entry) {
                entry.data = data;
                entry.file(function (file) {
                    entry.properties = entry.properties || {};
                    utils.mixin(file, entry.properties);
                    _set(path, entry);
                });
            }, _fsError);
        }
    },
    dir: {
        createNewDir: function (path) {
            var entry = _get(path),
                info = _getInfo(path);

            if (!entry) {
                _set(path, {
                    name: info.name,
                    isDirectory: true,
                    fullPath: path
                });
            }

            fs.mkdir(path, function (entry) {
                _set(path, entry);
            }, _fsError);
        },

        deleteDirectory: function (path, recursive) {
            _delete(path);
            if (recursive) {
                fs.rm(path, function () {}, _fsError, {recursive: recursive});
            } else {
                fs.rmdir(path, function () {}, _fsError);
            }
        },

        exists: function (path) {
            var entry = _get(path);
            return !!(entry && entry.isDirectory);
        },

        getFreeSpaceForRoot: function (path) {
            function _du(obj, size) {
                utils.forEach(obj, function (child, key) {
                    if (child.isDirectory && child.children) {
                        size += _du(child.children, size);
                    } else if (child.properties && child.properties.size) {
                        size += child.properties.size;
                    }
                });
                return size;
            }

            return constants.FS_SIZE - _du(_cache.children, 0);
        },

        getParentDirectory: function (path) {
            path = "/" + path.replace(/^\//, '').replace(/\/$/, '');

            var entry = _get(path),
                array = path.split("/");

            return entry ? array.splice(0, array.length - 1).join("/") || "/" : null;
        },

        listDirectories: function (path) {
            var dir = _get(path),
                directories = [];

            utils.forEach(dir.children, function (item) {
                if (item.isDirectory) {
                    directories.push(item.name);
                }
            });

            fs.ls(path, function () {}, _fsError);

            return directories;
        },

        listFiles: function (path) {
            var dir = _get(path),
                files = [];

            if (dir) {
                utils.forEach(dir.children, function (item) {
                    if (!item.isDirectory) {
                        files.push(item.name);
                    }
                });
            }

            fs.ls(path, function () {}, _fsError);

            return files;
        },

        rename: function (path, newName) {
            var info = _getInfo(path),
                parent = info.parent,
                oldName = info.name,
                from = (parent === "/" ? "" : parent) + "/" + oldName,
                to =  (parent === "/" ? "" : parent) + "/" + newName;

            _delete(from);
            _set(to, {
                name: info.name,
                fullPath: path
            });

            fs.mv(from, to, function (entry) {
                _set(to, entry);
            }, _fsError);
        },

        getRootDirs: function () {
            return _self.dir.listDirectories("/");
        }
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/server/dialog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    devices = require('ripple/devices'),
    ui = require('ripple/ui'),
    utils = require('ripple/utils'),
    isDialogVisible = false,
    visibleDialogArgs,
    _self;

function closeDialog() {
    var buttonsDiv = document.getElementById("dialog-buttons"),
        messageDiv = document.getElementById("dialog-message");

    ui.hideOverlay("dialog-window", function (dialog) {
        buttonsDiv.innerHTML = "";
        messageDiv.innerHTML = "";
        isDialogVisible = false;
    });
}

event.on("LayoutChanged", function () {
    if (isDialogVisible) {
        closeDialog();
        //Used to resize dialog on orientation change
        _self.ask(visibleDialogArgs);
    }
});

_self = {

    ask: function (args, post, baton) {
        if (!args) {
            throw ("No arguments provided");
        } else if (!args.buttons || !args.message) {
            throw ("Invalid arguments");
        }
        baton.take();
        visibleDialogArgs = args;

        ui.showOverlay("dialog-window", function (dialog) {
            var container = document.getElementById("viewport-container"),
                height = window.getComputedStyle(container, null).getPropertyValue("height"),
                width = window.getComputedStyle(container, null).getPropertyValue("width"),
                sizeDiv = document.getElementById("dialog-wrapper"),
                positionDiv = document.getElementById("dialog-window"),
                titleDiv = document.getElementById("dialog-title"),
                buttonsDiv = document.getElementById("dialog-buttons"),
                messageDiv = document.getElementById("dialog-message"),
                position, size;

            if (!messageDiv || !buttonsDiv) {
                return;
            }

            dialog.setAttribute("style", "display:-webkit-box;height:" + height + "; width:" + width + ";");

            position = "overlay-dialog";
            size = "overlay-dialog-wrapper";

            if (args.settings && args.settings.position) {
                position += " overlay-dialog-" + args.settings.position;
            }

            if (args.settings && args.settings.size) {
                size += " overlay-dialog-wrapper-" + args.settings.size;
            }

            positionDiv.setAttribute("class", position);
            sizeDiv.setAttribute("class", size);

            titleDiv.innerHTML = args.settings && args.settings.title ? args.settings.title : "";
            messageDiv.innerHTML = args.message;
            isDialogVisible = true;

            args.buttons.forEach(function (button) {
                var buttonElement = utils.createElement("input", {
                    "type": "button",
                    "value": button
                });
                buttonElement.addEventListener("click", function () {
                    var buttonIndex = args.buttons.indexOf(button);
                    closeDialog();
                    baton.pass({code: 1, data: buttonIndex});
                });
                buttonsDiv.appendChild(buttonElement);
            });
        }, true);
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/server/io/dir', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var cache = require('ripple/platform/webworks.core/2.0.0/fsCache');

function _packet(data) {
    return {
        code: 1,
        data: data
    };
}

module.exports = {
    createNewDir: function (get, post, baton) {
        cache.dir.createNewDir(post.path);
        return _packet();
    },
    deleteDirectory: function (get, post, baton) {
        cache.dir.deleteDirectory(post.path, post.recursive);
        return _packet();
    },
    exists: function (get, post, baton) {
        return _packet(cache.dir.exists(post.path));
    },
    getParentDirectory: function (get, post, baton) {
        return _packet(cache.dir.getParentDirectory(post.path));
    },
    listDirectories: function (get, post, baton) {
        return _packet(cache.dir.listDirectories(post.path));
    },
    listFiles: function (get, post, baton) {
        return _packet(cache.dir.listFiles(post.path));
    },
    rename: function (get, post, baton) {
        cache.dir.rename(post.path, post.newName);
        return _packet();
    }
};

});
define('ripple/platform/webworks.core/2.0.0/server/io/file', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var cache = require('ripple/platform/webworks.core/2.0.0/fsCache'),
    constants = require('ripple/constants'),
    notifications = require('ripple/notifications');

function _packet(data) {
    return {
        code: 1,
        data: data
    };
}

module.exports = {
    copy: function (get, post, baton) {
        cache.file.copy(post.from, post.to);
        return _packet();
    },
    deleteFile: function (get, post, baton) {
        cache.file.deleteFile(post.path);
        return _packet();
    },
    exists: function (get, post, baton) {
        return _packet(cache.file.exists(post.path));
    },
    getFileProperties: function (get, post, baton) {
        return _packet(cache.file.getFileProperties(post.path));
    },
    open: function (get, post, baton) {
        var msg = "Attempting to open file: " + post.path;
        notifications.openNotification("normal", msg);
        return _packet(cache.file.exists(post.path));
    },
    readFile: function (get, post, baton) {
        var val;

        if (post.async) {
            baton.take();
        }

        cache.file.readFile(post.path, function (data) {
            if (post.async) {
                baton.pass(_packet({
                    fullPath: post.path,
                    blobData: data
                }));
            } else {
                val = data;
            }
        }, post.async);

        if (!post.async) {
            return _packet({
                fullPath: post.path,
                blobData: val
            });
        }
    },
    rename: function (get, post, baton) {
        cache.file.rename(post.path, post.newName);
        return _packet();
    },
    saveFile: function (get, post, baton) {
        cache.file.saveFile(post.path, post.blob);
        return _packet();
    }
};

});
define('ripple/platform/webworks.core/2.0.0/server/system', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    devices = require('ripple/devices'),
    app = require('ripple/app'),
    client = require('ripple/platform/webworks.core/2.0.0/client/system'),
    utils = require('ripple/utils'),
    notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    platform = require('ripple/platform'),
    _self;

function _is(feature) {
    return {
        allowedFor: function (location) {
            return feature && feature.URIs.some(function (uri) {
                return uri.value === location ||
                      (location.indexOf(uri.value) >= 0 && uri.subdomains);
            });
        }
    };
}

_self = {
    hasCapability: function (args) {
        var capabilities = devices.getCurrentDevice().capabilities;
        return {
            code: 1,
            data: capabilities ? capabilities.some(function (type) {
                return type === args.capability;
            }) : false
        };
    },
    isMassStorageActive: function () {
        return {code: 1, data: deviceSettings.retrieveAsBoolean("system.isMassStorageActive")};
    },
    hasDataCoverage: function () {
        return {code: 1, data: deviceSettings.retrieveAsBoolean("system.hasDataCoverage")};
    },
    softwareVersion: function () {
        return {code: 1, data: devices.getCurrentDevice().osVersion};
    },
    model: function () {
        return {code: 1, data: devices.getCurrentDevice().model};
    },
    scriptApiVersion: function () {
        return {code: 1, data: platform.current().version};
    },
    setHomeScreenBackground: function (args) {
        var path = args.filePath,
            msg = "Set home screen background to " + path + ".";
        notifications.openNotification("normal", msg);
        return {code: 1};
    },
    hasPermission: function (args) {
        var info = app.getInfo(),
            feature = info.features ? info.features[args.desiredModule] : null;

        return {code: 1, data: feature === null || _is(feature).allowedFor(utils.location().href) ? client.ALLOW : client.DENY};
    },
    network: function () {
        return {code: 1, data: deviceSettings.retrieve("system.network")};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/select', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    _select,
    _predicates = {
        "==": function (left, right) {
            return left === right;
        },
        "!=": function (left, right) {
            return left !== right;
        },
        "<": function (left, right) {
            return left < right;
        },
        ">": function (left, right) {
            return left > right;
        },
        "<=": function (left, right) {
            return left <= right;
        },
        ">=": function (left, right) {
            return left >= right;
        },
        "REGEX": function (left, right) {
            return left && left.match(new RegExp(right));
        },
        "CONTAINS": function (left, right) {
            return left.indexOf(right) >= 0;
        }
    };

function isFilter(field) {
    return field && field.operator !== undefined && field.operator !== null;
}

function extractValue(item, field) {
    return field.split(".").reduce(function (value, prop) {
        return value[prop];
    }, item);
}

function copy(items) {
    //use a reduce to ensure that we always just return an array
    //not the most performant but will whitewash the result
    return utils.reduce(items, function (array, item) {
        array.push(item);
        return array;
    }, []);
}

_select = {
    ops: {
        find: {
            0: "!=",
            1: "==",
            2: "<",
            3: "<=",
            4: ">",
            5: ">=",
            8: "REGEX",
            16: "AND",
            32: "OR",
            64: "CONTAINS"
        },
        phone: {
            0: "!=",
            1: "==",
            2: "<",
            3: "<=",
            4: ">",
            5: ">=",
            8: "AND",
            16: "OR",
            32: "CONTAINS"
        }
    },
    from: function (items) {
        var _getPredicate = function (filter, operators) {

                var noOp = function () {
                        return false;
                    },
                    operator = (function () {
                        var result = operators[filter.operator] || filter.operator,
                            exists = function (op) {
                                return result === op;
                            };

                        return utils.some(operators, exists) ? result : "";
                    }());

                return function (item) {
                    var left = extractValue(item, filter.leftField),
                        right = filter.rightField,
                        predicate = _predicates[operator] || noOp;

                    return filter.negate ? !predicate(left, right) : predicate(left, right);
                };

            },
            _applyFilter = function (filter, operators) {
                var result = [],
                    left,
                    right,
                    op;

                if (isFilter(filter.leftField) && isFilter(filter.rightField)) {

                    left = _select.from(items).where(filter.leftField);
                    right = _select.from(items).where(filter.rightField);
                    op = operators[filter.operator] || filter.operator;

                    switch (op) {
                    case "AND":
                        result = left.filter(function (item) {
                            return right.indexOf(item) >= 0;
                        });
                        break;
                    case "OR":
                        result = left.concat(right.filter(function (item) {
                            return left.indexOf(item) < 0;
                        }));
                        break;
                    }

                    if (filter.negate) {
                        //reverse the result set.
                        result = utils.filter(items, function (item) {
                            return result.indexOf(item) < 0;
                        });
                    }
                }
                else {
                    result = utils.filter(items, _getPredicate(filter, operators));
                }

                return result;
            },
            _orderBy,
            _max,
            _direction,
            _self = {
                orderBy: function (prop, dir) {
                    _orderBy = prop;
                    _direction = dir || "asc";
                    return _self;
                },
                max: function (max) {
                    _max = max;
                    return _self;
                },
                where: function (filter, ops) {
                    var result = isFilter(filter) ? _applyFilter(filter, ops || _select.ops.find) : copy(items);

                    result.sort(function (a, b) {
                        if (a[_orderBy] < b[_orderBy]) {
                            return _direction === "asc" ? -1 : 1;
                        }
                        else if (a[_orderBy] > b[_orderBy]) {
                            return _direction === "asc" ? 1: -1;
                        }
                        return 0;
                    });

                    return result.slice(0, _max === null || _max === -1 ? undefined : _max); // slice in V8 returns empty array if null
                }
            };

        return _self;
    }
};

module.exports = _select;

});
define('ripple/platform/webworks.core/2.0.0/XMLHttpRequest', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    create: function (server) {
        var XHR = window.XMLHttpRequest,
            webworks = require(server);

        return function () {
            var _url,
                _async,
                xhr = new XHR(),
                origMethods = {
                    open: xhr.open,
                    send: xhr.send,
                    setRequestHeader: xhr.setRequestHeader
                };

            function onreadystatechange() {
                if (typeof xhr.onreadystatechange === "function") {
                    xhr.onreadystatechange();
                }
            }

            function statemachine(getResult) {
                var state = 0,
                    incState = function (prev, baton) {
                        state++;
                        if (_async) {
                            baton.take();
                            window.setTimeout(baton.pass, 1);
                        }
                    },
                    setResponse = function (result) {
                        xhr.__defineGetter__("status", function () {
                            return 200;
                        });

                        xhr.__defineGetter__("responseText", function () {
                            return result !== null && result !== undefined ?
                                JSON.stringify(result) : null;
                        });
                    };

                xhr.__defineGetter__("readyState", function () {
                    return state;
                });

                jWorkflow.order(incState)
                         .andThen(onreadystatechange)
                         .andThen(incState)
                         .andThen(onreadystatechange)
                         .andThen(incState)
                         .andThen(onreadystatechange)
                         .andThen(getResult)
                         .andThen(setResponse)
                         .andThen(incState)
                         .andThen(onreadystatechange)
                         .start();
            }

            xhr.setRequestHeader = function (header, value) {
                if (!_url.match(/^webworks:\/\//)) {
                    origMethods.setRequestHeader.apply(xhr, Array.prototype.slice.call(arguments));
                }
            };

            xhr.open = function (method, url, async, user, password) {
                _url = url;
                _async = async;

                if (!_url.match(/^webworks:\/\//)) {
                    origMethods.open.apply(xhr, Array.prototype.slice.call(arguments));
                }
            };

            xhr.send = function (post) {
                if (!_url.match(/^webworks:\/\//)) {
                    origMethods.send.apply(xhr, Array.prototype.slice.call(arguments));
                    return;
                }

                var params = _url.match(/\?(.*)$/),
                    objPath = _url.match(/^webworks:\/\/([^\?]*)/)[1].split("/"),
                    apiMethod = objPath.reduce(function (obj, name) {
                        return obj[name];
                    }, webworks),
                    postParams = {},
                    get = {};

                if (params) {
                    params[1].split("&").forEach(function (param) {
                            var pair = param.split("="),
                                key = decodeURIComponent(pair[0]),
                                value = decodeURIComponent(pair[1]);
                            // parsing undefied with JSON throws exception
                            get[key] = value === "undefined" ? undefined : JSON.parse(value);
                        });
                }

                if (post) {
                    post.split("&").forEach(function (param) {
                            var pair = param.split("="),
                                value;
                            try {
                                value = JSON.parse(decodeURIComponent(pair[1]));
                            } catch (e) {
                                value = pair[1] === "undefined" ? undefined : pair[1];
                            }

                            postParams[pair[0]] = value;
                        });
                }

                statemachine(function (prev, baton) {
                    return apiMethod(get, postParams, baton);
                });
            };

            return xhr;
        };
    }
};

});
define('ripple/platform/webworks.core/2.0.0/client/events', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _handlers = [],
    _self;

_self = {
    eventsMap: {
        getHandlerById: function (handlerId) {
            return _handlers[handlerId];
        },
        addHandler: function (handler) {
            _handlers.push(handler);
            return _handlers.length - 1;
        },
        removeHandler: function (handlerId) {
            if (handlerId > -1 && handlerId < _handlers.length) {
                delete _handlers[handlerId]; //cannot splice because all published IDs would refer to the wrong handler
            }
        }
    },

    registerEventHandler : function (eventName, eventCallback, eventParams) {
        return _self.eventsMap.addHandler(eventCallback);
    },

    getEventHandler : function (handlerId) {
        return _self.eventsMap.getHandlerById(handlerId);
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/client/FileProperties', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function FileProperties(props) {
    props = props || {};

    function _get(val) {
        return function () {
            return props[val];
        };
    }

    this.__defineGetter__("dateCreated", _get("dateCreated")); //tablet only
    this.__defineGetter__("dateModified", _get("dateModified"));
    this.__defineGetter__("directory", _get("directory"));
    this.__defineGetter__("fileExtension", _get("fileExtension"));
    this.__defineGetter__("isHidden", _get("isHidden"));
    this.__defineGetter__("isReadonly", _get("isReadonly")); //handset only
    this.__defineGetter__("mimeType", _get("mimeType")); //handset only
    this.__defineGetter__("size", _get("size"));
}

module.exports = FileProperties;

});
define('ripple/platform/webworks.core/2.0.0/client/dialog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/ui/dialog/",
    _self;

function getButtonsForDialogType(dialogType) {
    switch (dialogType) {
    case _self.D_OK:
        return ["Ok"];
    case _self.D_SAVE:
        return ["Save", "Discard"];
    case _self.D_DELETE:
        return ["Delete", "Cancel"];
    case _self.D_YES_NO:
        return ["Yes", "No"];
    case _self.D_OK_CANCEL:
        return ["Ok", "Cancel"];
    default:
        throw new Error("Invalid dialog type: " + dialogType);
    }
}

_self = {
    customAskAsync: function (message, choices, callback, settings) {
        return transport.call(_uri + "ask", {
            async: true,
            get: {
                message: message,
                buttons: choices,
                settings: settings
            }
        }, function (response) {
            if (callback) {
                callback(response);
            }
        });
    },

    standardAskAsync: function (message, type, callback, settings) {
        var choices = getButtonsForDialogType(type);
        return transport.call(_uri + "ask", {
            async: true,
            get: {
                message: message,
                buttons: choices,
                settings: settings
            }
        }, function (response) {
            if (callback) {
                callback(response);
            }
        });
    }
};

_self.__defineGetter__("D_OK", function () {
    return 0;
});

_self.__defineGetter__("D_SAVE", function () {
    return 1;
});

_self.__defineGetter__("D_DELETE", function () {
    return 2;
});

_self.__defineGetter__("D_YES_NO", function () {
    return 3;
});

_self.__defineGetter__("D_OK_CANCEL", function () {
    return 4;
});

_self.__defineGetter__("BOTTOM", function () {
    return "bottomCenter";
});

_self.__defineGetter__("CENTER", function () {
    return "middleCenter";
});

_self.__defineGetter__("TOP", function () {
    return "topCenter";
});

_self.__defineGetter__("SIZE_FULL", function () {
    return "full";
});

_self.__defineGetter__("SIZE_LARGE", function () {
    return "large";
});

_self.__defineGetter__("SIZE_MEDIUM", function () {
    return "medium";
});

_self.__defineGetter__("SIZE_SMALL", function () {
    return "small";
});

_self.__defineGetter__("SIZE_TALL", function () {
    return "tall";
});

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/client/transport', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self;

function RemoteFunctionCall(functionUri) {
    var params = {},
        postString = "",
        postParams = {};

    function composeUri() {
        var uri = "webworks://" + functionUri,
            paramCount = 1,
            param;

        for (param in params) {
            if (params.hasOwnProperty(param)) {
                if (paramCount === 1) {
                    uri += "?";
                } else {
                    uri += "&";
                }
                uri += param + "=" + params[param];
                paramCount++;
            }

            uri = uri.replace(/\&$/, "");
        }

        return uri;
    }

    function createXhrRequest(uri, isAsync) {
        var request = new XMLHttpRequest(),
            paramCount = 1,
            param;

        for (param in postParams) {
            if (postParams.hasOwnProperty(param)) {
                postString += param + "=" + postParams[param] + "&";
                paramCount++;
            }
        }

        postString = postString.replace(/\&$/, "");

        // TODO: make get/post
        request.open("POST", uri, isAsync);
        request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        return request;
    }

    this.addParam = function (name, value) {
        params[name] = encodeURIComponent(JSON.stringify(value));
    };

    this.addPostParam = function (name, value) {
        postParams[name] = encodeURIComponent(JSON.stringify(value));
    };

    this.makeSyncCall = function (success, error) {
        var requestUri = composeUri(),
            request = createXhrRequest(requestUri, false),
            response, errored, cb, data;

        request.send(postString);

        response = JSON.parse(request.responseText || "null");
        errored = response.code < 0;
        cb = errored ? error : success;
        data = errored ? response.msg : response.data;

        if (cb) {
            cb(data, response);
        }
        else if (errored) {
            throw data;
        }

        return data;
    };

    this.makeAsyncCall = function (success, error) {
        var requestUri = composeUri(),
            request = createXhrRequest(requestUri, true);

        request.onreadystatechange = function () {
            if (request.readyState === 4 && request.status === 200) {
                var response = JSON.parse(request.responseText || "null"),
                    cb = response.code < 0 ? error : success,
                    data = response.code < 0 ? response.msg : response.data;

                return cb && cb(data, response);
            }
        };

        request.send(postString);
    };
}

_self = {
    call: function (url, opts, success, error) {
        var request = new RemoteFunctionCall(url),
            name;

        opts = opts || {};

        if (opts.get) {
            for (name in opts.get) {
                if (Object.hasOwnProperty.call(opts.get, name)) {
                    request.addParam(name, opts.get[name]);
                }
            }
        }

        if (opts.post) {
            for (name in opts.post) {
                if (Object.hasOwnProperty.call(opts.post, name)) {
                    request.addPostParam(name, opts.post[name]);
                }
            }
        }

        return opts.async ? request.makeAsyncCall(success, error) : request.makeSyncCall(success, error);
    },

    poll: function (url, opts, callback) {
        opts = opts || {};
        opts.async = true;

        _self.call(url, opts, function (data, response) {
            if (callback(data, response)) {
                _self.poll(url, opts, callback);
            }
        });
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/client/io/dir', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/io/dir/",
    FILE = "file://";

function _prunePrefix(path) {
    return path.replace(new RegExp("^" + FILE), '');
}

function _addPrefix(path) {
    return FILE + path;
}

module.exports = {
    createNewDir: function (path) {
        transport.call(_uri + "createNewDir", {
            post: {path: _prunePrefix(path)}
        });
    },
    deleteDirectory: function (path, recursive) {
        transport.call(_uri + "deleteDirectory", {
            post: {path: _prunePrefix(path), recursive: recursive}
        });
    },
    exists: function (path) {
        return transport.call(_uri + "exists", {
            post: {path: _prunePrefix(path)}
        });
    },
    getParentDirectory: function (path) {
        return _addPrefix(transport.call(_uri + "getParentDirectory", {
            post: {path: _prunePrefix(path)}
        }));
    },
    listDirectories: function (path) {
        return transport.call(_uri + "listDirectories", {
            post: {path: _prunePrefix(path)}
        });
    },
    listFiles: function (path) {
        return transport.call(_uri + "listFiles", {
            post: {path: _prunePrefix(path)}
        });
    },
    rename: function (path, newName) {
        transport.call(_uri + "rename", {
            post: {path: _prunePrefix(path), newName: newName}
        });
    }
};

});
define('ripple/platform/webworks.core/2.0.0/client/io/file', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/io/file/",
    FILE = "file://",
    _onFileOpened;

function _prunePrefix(path) {
    return path.replace(new RegExp("^" + FILE), '');
}

module.exports = {
    copy: function (from, to) {
        transport.call(_uri + "copy", {
            post: {from: _prunePrefix(from), to: _prunePrefix(to)}
        });
    },
    deleteFile: function (path) {
        transport.call(_uri + "deleteFile", {
            post: {path: _prunePrefix(path)}
        });
    },
    exists: function (path) {
        return transport.call(_uri + "exists", {
            post: {path: _prunePrefix(path)}
        });
    },
    getFileProperties: function (path) {
        var properties = transport.call(_uri + "getFileProperties", {
            post: {path: _prunePrefix(path)}
        });
        properties.directory = FILE + properties.directory;
        return properties;
    },
    open: function (path, newName) {
        transport.call(_uri + "open", {
            post: {path: _prunePrefix(path)}
        });
    },
    readFile: function (path, onFileOpened, async) {
        async = async === false ? false : true;

        var uri = _uri + "readFile",
            args = {
                post: {path: _prunePrefix(path), async: async}
            },
            callResult;

        _onFileOpened = onFileOpened;

        if (async) {
            transport.poll(uri, args, function (data, res) {
                if (_onFileOpened) {
                    _onFileOpened(FILE + data.fullPath, data.blobData);
                }
                return false;
            });
        } else {
            callResult = transport.call(uri, args);
            _onFileOpened(FILE + callResult.fullPath, callResult.blobData);
        }
    },
    rename: function (path, newName) {
        transport.call(_uri + "rename", {
            post: {path: _prunePrefix(path), newName: newName}
        });
    },
    saveFile: function (path, blob) {
        transport.call(_uri + "saveFile", {
            post: {path: _prunePrefix(path), blob: blob}
        });
    }
};

});
define('ripple/platform/webworks.core/2.0.0/client/system', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/system/",
    _self;

_self = {
    hasCapability: function (capability) {
        return transport.call(_uri + "hasCapability", {
            get: {capability: capability}
        });
    },

    hasDataCoverage: function () {
        return transport.call(_uri + "hasDataCoverage");
    },

    hasPermission: function (desiredModule) {
        return transport.call(_uri + "hasPermission", {
            get: {desiredModule: desiredModule}
        });
    },

    isMassStorageActive: function () {
        return transport.call(_uri + "isMassStorageActive");
    }
};

_self.__defineGetter__("model", function () {
    return transport.call(_uri + "model");
});
_self.__defineGetter__("scriptApiVersion", function () {
    return transport.call(_uri + "scriptApiVersion");
});
_self.__defineGetter__("softwareVersion", function () {
    return transport.call(_uri + "softwareVersion");
});

_self.__defineGetter__("ALLOW", function () {
    return 0;
});
_self.__defineGetter__("DENY", function () {
    return 1;
});
_self.__defineGetter__("PROMPT", function () {
    return 2;
});
_self.__defineGetter__("NOT_SET", function () {
    return 3;
});

module.exports = _self;

});
define('ripple/platform/webworks.core/2.0.0/client/utils', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _blobs = {};

function _blobBuilder() {
    var BlobBuilder = BlobBuilder || WebKitBlobBuilder;
    return new BlobBuilder();
}

module.exports = {
    parseURL: function (theUrl) {
        /********START IDEA BORROWING*******/
        // parseUri 1.2.2
        // (c) Steven Levithan <stevenlevithan.com>
        // MIT License

        function parseUri(str) {
            var	o   = parseUri.options,
                m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
                uri = {},
                i   = 14;

            while (i--) {
                uri[o.key[i]] = m[i] || "";
            }

            uri[o.q.name] = {};
            uri[o.q.arrayName] = [];
            uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
                if ($1) {
                    uri[o.q.name][$1] = $2;
                    uri[o.q.arrayName].push($2);
                }
            });

            return uri;
        }

        parseUri.options = {
                strictMode: false,
                key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
                q:   {
                    name:   "queryKey",
                    arrayName:   "queryArray",
                    parser: /(?:^|&)([^&=]*)=?([^&]*)/g
                },
                parser: {
                    strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
                    loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
                }
            };
        /********END IDEA BORROWING*******/

        parseUri.strictMode = "strict";
        var uri = parseUri(theUrl),
            retVal = {
                getURLParameter : function (key) {
                    return uri.queryKey[key];
                },

                getURLParameterByIndex : function (index) {
                    return uri.queryArray[index];
                }
            };

        //Add default values for the http/https port if they weren't specified in the URL. The above parser returns undefined. We need the values
        //to be compatible with the BB version of API.
        if (uri["port"] === "") {
            if (uri["protocol"] === "http") {
                uri["port"] = "80";
            }
            else if (uri["protocol"] === "https") {
                uri["port"] = "443";
            }
            else {
                uri["port"] = "0";
            }
        }

        retVal.__defineGetter__("host", function () {
            return uri["host"];
        });
        retVal.__defineGetter__("port", function () {
            return parseInt(uri["port"], 10);
        });

        return retVal;
    },

    generateUniqueId: function () {
        return Math.floor(Math.random() * Number.MAX_VALUE);
    },

    blobToString: function (blob, encoding) {
        return _blobs[blob.id];
    },

    stringToBlob: function (string, encoding) {
        var id = Math.uuid(undefined, 16),
            blob = _blobBuilder(),
            finalBlob;

        _blobs[id] = string;
        blob.append(string);

        finalBlob = blob.getBlob();
        finalBlob.id = id;
        finalBlob.length = finalBlob.size;

        return finalBlob;
    }
};

});
define('ripple/platform/webworks.core/2.0.0/spec/events', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

module.exports = {
    "app.event.onBackground": {
        callback: function () {
            event.trigger("AppRequestBackground");
        }
    },
    "app.event.onForeground": {
        callback: function () {
            event.trigger("AppRequestForeground");
        }
    }
};

});
define('ripple/platform/webworks.core/2.0.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (config) {
        return true;
    },
    extractInfo: function (config) {
        if (!config) {
            return null;
        }

        var widgetInfo = {},
            widgetFeatures = config.widget.children.feature.validationResult,
            accessUrls = config.widget.children.access.validationResult,
            accessFeatures = config.widget.children.access.children.feature.validationResult,
            toFeature = function (validationResult) {
                return {
                    id: validationResult.attributes.id.value,
                    required: !validationResult.attributes.required || validationResult.attributes.required.value,
                    URIs: []
                };
            };

        widgetInfo.id = config.widget.validationResult[0].attributes.id.value;
        widgetInfo.name = config.widget.children.name.validationResult[0].value;
        widgetInfo.icon = config.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = config.widget.validationResult[0].attributes.version.value;
        widgetInfo.author = config.widget.children.author.validationResult[0].value;
        widgetInfo.authorEmail = config.widget.children.author.validationResult[0].attributes.email.value;
        widgetInfo.authorURL = config.widget.children.author.validationResult[0].attributes.href.value;
        widgetInfo.copyright = config.widget.children.author.validationResult[0].attributes["rim:copyright"].value;
        widgetInfo.description = config.widget.children.description.validationResult[0].value;
        if (config.widget.children.license.validationResult[0]) {
            widgetInfo.license = config.widget.children.license.validationResult[0].value;
            widgetInfo.licenseURL = config.widget.children.license.validationResult[0].attributes.href.value;
        }

        widgetInfo.features = widgetFeatures.reduce(function (features, validationResult) {
            if (validationResult.valid) {
                var feature = toFeature(validationResult);
                feature.URIs.push({
                    value: utils.location().href,
                    subdomains: true
                });
                features = features || {};
                features[feature.id] = feature;
            }
            return features;
        }, {});

        widgetInfo.features = accessUrls.map(function (access) {
            return {
                uri: access.attributes.uri.value,
                subdomains: access.attributes.subdomains.value,
                features: accessFeatures ? accessFeatures.filter(function (f) {
                    return f.node && f.node.parentNode && f.node.parentNode.attributes.uri.value === access.attributes.uri.value;
                }) : null
            };
        }).reduce(function (result, access) {
            return access.features ? access.features.reduce(function (features, validationResult) {
                var feature = features[validationResult.attributes.id.value] || toFeature(validationResult);
                feature.URIs.push({
                    value: access.uri,
                    subdomains: access.subdomains
                });
                features[feature.id] = feature;
                return features;
            }, result) : result;
        }, widgetInfo.features);

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xmlns:rim": {
                    attributeName: "xmlns:rim",
                    required: true,
                    type: "list",
                    listValues: ["http://www.blackberry.com/ns/widgets"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                },
                id: {
                    attributeName: "id",
                    required: false,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    required: false,
                    type: "string"
                },
                "rim:header": {
                    attributeName: "rim:header",
                    required: false,
                    type: "string"
                },
                "rim:backButton": {
                    attributeName: "rim:backButton",
                    required: false,
                    type: "string"
                }
            },
            children: {
                name: {
                    nodeName: "name",
                    required: true,
                    occurrence: 1,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        "rim:hover": {
                            attributeName: "rim:hover",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        href: {
                            attributeName: "href",
                            type: "string",
                            required: false
                        },
                        "rim:copyright": {
                            attributeName: "rim:copyright",
                            type: "string",
                            required: false
                        },
                        email: {
                            attributeName: "email",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 1,
                    attributes : {
                        href: {
                            attributeName: "href",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                "rim:cache": {
                    nodeName: "rim:cache",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        disableAllCache: {
                            attributeName: "disableAllCache",
                            required: false,
                            type: "boolean"
                        },
                        aggressiveCacheAge: {
                            attributeName: "aggressiveCacheAge",
                            required: false,
                            type: "number"
                        },
                        maxCacheSizeTotal: {
                            attributeName: "maxCacheSizeTotal",
                            required: false,
                            type: "number"
                        },
                        maxCacheSizeItem: {
                            attributeName: "maxCacheSizeItem",
                            required: false,
                            type: "number"
                        }
                    }
                },
                access: {
                    nodeName: "access",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        uri: {
                            attributeName: "uri",
                            required: true,
                            type: "string"
                        },
                        subdomains: {
                            attributeName: "subdomains",
                            required: false,
                            type: "boolean"
                        }
                    },
                    children: {
                        feature: {
                            nodeName: "feature",
                            required: false,
                            occurrence: 0,
                            attributes: {
                                id: {
                                    attributeName: "id",
                                    required: true,
                                    //TODO: this should be a list
                                    type: "string"
                                },
                                required: {
                                    attributeName: "required",
                                    required: false,
                                    type: "boolean"
                                },
                                version: {
                                    attributeName: "version",
                                    required: false,
                                    type: "string"
                                }
                            }
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        id: {
                            attributeName: "id",
                            required: true,
                            //TODO: this should be a list
                            type: "string"
                        },
                        required: {
                            attributeName: "required",
                            required: false,
                            type: "boolean"
                        },
                        version: {
                            attributeName: "version",
                            required: false,
                            type: "string"
                        }
                    }
                },
                "rim:loadingScreen": {
                    nodeName: "rim:loadingScreen",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        backgroundColor: {
                            attributeName: "backgroundColor",
                            required: false,
                            type: "string"
                        },
                        backgroundImage: {
                            attributeName: "backgroundImage",
                            required: false,
                            type: "string"
                        },
                        foregroundImage: {
                            attributeName: "foregroundImage",
                            required: false,
                            type: "string"
                        },
                        onRemotePageLoad: {
                            attributeName: "onRemotePageLoad",
                            required: false,
                            type: "boolean"
                        },
                        onLocalPageLoad: {
                            attributeName: "onLocalPageLoad",
                            required : false,
                            type: "boolean"
                        },
                        onFirstLaunch: {
                            attributeName: "onFirstLaunch",
                            required: false,
                            type: "boolean"
                        }
                    },
                    children: {
                        "rim:transitionEffect": {
                            nodeName: "rim:transitionEffect",
                            required: false,
                            occurrence: 1,
                            attributes: {
                                "type": {
                                    attributeName: "type",
                                    required: true,
                                    type: "list",
                                    listValues: ["slidePush", "slideOver", "fadeIn", "fadeOut", "wipeIn", "wipeOut", "zoomIn", "zoomOut"]
                                },
                                duration: {
                                    attributeName: "duration",
                                    required: false,
                                    type: "number"
                                },
                                direction: {
                                    attributeName: "direction",
                                    required: false,
                                    type: "list",
                                    listValues: ["left", "right", "up", "down"]
                                }
                            }
                        }
                    }
                },
                "rim:connection": {
                    nodeName: "rim:connection",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        timeout: {
                            attributeName: "timeout",
                            required: false,
                            type: "number"
                        }
                    },
                    children: {
                        id: {
                            nodeName: "id",
                            required: false,
                            occurrence: 0
                        }
                    }
                },
                "rim:navigation": {
                    nodeName: "rim:navigation",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        mode: {
                            attributeName: "mode",
                            required: false,
                            type: "list",
                            listValues: ["focus"]
                        }
                    }
                },
                "content": {
                    nodeName: "content",
                    required: true,
                    occurrence: 1,
                    attributes: {
                        src: {
                            attributeName: "src",
                            required: true,
                            type: "string"
                        },
                        type: {
                            attributeName: "type",
                            required: false,
                            type: "string"
                        },
                        charset: {
                            attributeName: "charset",
                            required: false,
                            type: "string"
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/webworks.bb10/1.0.0/dialog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    ui = require('ripple/ui'),
    event = require('ripple/event'),
    isDialogVisible = false,
    visibleDialogArgs,
    utils = require('ripple/utils');

function getButtonsForDialogType(dialogType) {
    switch (dialogType) {
    case _self.D_OK:
        return ["Ok"];
    case _self.D_SAVE:
        return ["Save", "Discard"];
    case _self.D_DELETE:
        return ["Delete", "Cancel"];
    case _self.D_YES_NO:
        return ["Yes", "No"];
    case _self.D_OK_CANCEL:
        return ["Ok", "Cancel"];
    default:
        throw new Error("Invalid dialog type: " + dialogType);
    }
}

event.on("LayoutChanged", function () {
    if (isDialogVisible) {
        closeDialog();
        //Used to resize dialog on orientation change
        _self.ask(visibleDialogArgs);
    }
});

function closeDialog() {
    var buttonsDiv = document.getElementById("dialog-buttons"),
        messageDiv = document.getElementById("dialog-message");

    ui.hideOverlay("dialog-window", function (dialog) {
        buttonsDiv.innerHTML = "";
        messageDiv.innerHTML = "";
        isDialogVisible = false;
    });
}

function ask(args, callback) {
    if (!args) {
        throw ("No arguments provided");
    } else if (!args.buttons || !args.message) {
        throw ("Invalid arguments");
    }
    visibleDialogArgs = args;

    ui.showOverlay("dialog-window", function (dialog) {
        var container = document.getElementById("viewport-container"),
            height = window.getComputedStyle(container, null).getPropertyValue("height"),
            width = window.getComputedStyle(container, null).getPropertyValue("width"),
            sizeDiv = document.getElementById("dialog-wrapper"),
            positionDiv = document.getElementById("dialog-window"),
            titleDiv = document.getElementById("dialog-title"),
            buttonsDiv = document.getElementById("dialog-buttons"),
            messageDiv = document.getElementById("dialog-message"),
            position, size;

        if (!messageDiv || !buttonsDiv) {
            return;
        }

        dialog.setAttribute("style", "display:-webkit-box;height:" + height + "; width:" + width + ";");

        position = "overlay-dialog";
        size = "overlay-dialog-wrapper";

        if (args.settings && args.settings.position) {
            position += " overlay-dialog-" + args.settings.position;
        }

        if (args.settings && args.settings.size) {
            size += " overlay-dialog-wrapper-" + args.settings.size;
        }

        positionDiv.setAttribute("class", position);
        sizeDiv.setAttribute("class", size);

        titleDiv.innerHTML = args.settings && args.settings.title ? args.settings.title : "";
        messageDiv.innerHTML = args.message;
        isDialogVisible = true;

        args.buttons.forEach(function (button) {
            var buttonElement = utils.createElement("input", {
                "type": "button",
                "value": button
            });
            buttonElement.addEventListener("click", function () {
                var buttonIndex = args.buttons.indexOf(button);
                closeDialog();
                callback(buttonIndex);
            });
            buttonsDiv.appendChild(buttonElement);
        });
    }, true);
}

_self = {
    customAskAsync: function (message, choices, callback, settings) {
        ask({
            message: message,
            buttons: choices,
            settings: settings
        }, function (response) {
            if (callback) {
                callback(response);
            }
        });
    },

    standardAskAsync: function (message, type, callback, settings) {
        var choices = getButtonsForDialogType(type);
        ask({ 
            message: message, 
            buttons: choices, 
            settings: settings
        }, function (response) {
            if (callback) {
                callback(response);
            }
        });
    }
};

_self.__defineGetter__("D_OK", function () {
    return 0;
});

_self.__defineGetter__("D_SAVE", function () {
    return 1;
});

_self.__defineGetter__("D_DELETE", function () {
    return 2;
});

_self.__defineGetter__("D_YES_NO", function () {
    return 3;
});

_self.__defineGetter__("D_OK_CANCEL", function () {
    return 4;
});

_self.__defineGetter__("BOTTOM", function () {
    return "bottomCenter";
});

_self.__defineGetter__("CENTER", function () {
    return "middleCenter";
});

_self.__defineGetter__("TOP", function () {
    return "topCenter";
});

_self.__defineGetter__("SIZE_FULL", function () {
    return "full";
});

_self.__defineGetter__("SIZE_LARGE", function () {
    return "large";
});

_self.__defineGetter__("SIZE_MEDIUM", function () {
    return "medium";
});

_self.__defineGetter__("SIZE_SMALL", function () {
    return "small";
});

_self.__defineGetter__("SIZE_TALL", function () {
    return "tall";
});

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    app = require('ripple/app'),
    notifications = require('ripple/notifications'),
    _uri = "blackberry/app/",
    _self;

_self = {
    exit: function () {
        notifications.openNotification("normal", "blackberry.app.exit() was called, in the real world your app will exit, here... you get this notification");
    }
};

_self.__defineGetter__("author", function () {
    return app.getInfo().author;
});

_self.__defineGetter__("authorEmail", function () {
    return app.getInfo().authorEmail;
});

_self.__defineGetter__("authorURL", function () {
    return app.getInfo().authorURL;
});

_self.__defineGetter__("copyright", function () {
    return app.getInfo().copyright;
});

_self.__defineGetter__("description", function () {
    return app.getInfo().description;
});

_self.__defineGetter__("id", function () {
    return app.getInfo().id;
});

_self.__defineGetter__("license", function () {
    return app.getInfo().license;
});

_self.__defineGetter__("licenseURL", function () {
    return app.getInfo().licenseURL;
});

_self.__defineGetter__("name", function () {
    return app.getInfo().name;
});

_self.__defineGetter__("version", function () {
    return app.getInfo().version;
});

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var devices = require('ripple/devices'),
    _self = {};

_self.__defineGetter__("softwareVersion", function () {
    return devices.getCurrentDevice().osVersion;
});

_self.__defineGetter__("hardwareId", function () {
    return devices.getCurrentDevice().hardwareId;
});
module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/navigator', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var nav = require('ripple/platform/w3c/1.0/navigator'),
    utils = require('ripple/utils'),
    deviceSettings = require('ripple/deviceSettings'),
    _self = {};

utils.mixin(nav, _self);

_self.__defineGetter__("language", function () {
    return deviceSettings.retrieve("system.language");
});

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/event', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    settings = require('ripple/deviceSettings'),
    app = require('ripple/app'),
    cons = require('ripple/console'),
    utils = require('ripple/utils'),
    events = {
        batterystatus: {
            callbacks: [],
            feature: 'blackberry.system' 
        },
        batterylow: {
            callbacks: [],
            feature: 'blackberry.system'
        },
        batterycritical: {
            callbacks: [],
            feature: 'blackberry.system'
        },
        connectionchange: {
            callbacks: [],
            feature: 'blackberry.connection'
        },
        invoked: {
            callbacks: [],
            feature: 'blackberry.invoked'
        },
        swipedown: {
            callbacks: [],
            feature: 'blackberry.app'
        },
        resume: {
            callbacks: [],
            feature: 'blackberry.app'
        },
        pause: {
            callbacks: [],
            feature: 'blackberry.app'
        },
        languagechange: {
            callbacks: [],
            feature: "blackberry.system"
        },
        regionchange: {
            callbacks: [],
            feature: "blackberry.system"
        }
    };

function _apply(eventName, args) {
    events[eventName].callbacks.forEach(function (cb) {
        cb.apply(null, args);
    });
}

event.on('DeviceBatteryStateChanged', function (charging) {
    var info = {
        isPlugged: charging,
        level: parseInt(settings.retrieve('battery.level'), 10)
    };

    _apply('batterystatus', [info]);
});

event.on('DeviceBatteryLevelChanged', function (level) {
    var info = {
        isPlugged: settings.retrieve('battery.state'),
        level: parseInt(level, 10)
    };

    _apply('batterystatus', [info]);
    
    if (level === '14') {
        _apply('batterylow', [info]);
    }

    if (level === '4') {
        _apply('batterycritical', [info]);
    }
});

event.on('DeviceConnectionChanged', function (info) {
    _apply('connectionchange', [info]);
});

event.on("LanguageChanged", function (lang) {
    _apply("languagechange", [lang]);
});

event.on("RegionChanged", function (lang) {
    _apply("regionchange", [lang]);
});

event.on("AppInvoke", function (invokeInfo) {
    var invokeTargets = app.getInfo().invokeTargets;

    if (!invokeTargets) {
        cons.log("The application cannot be invoked, please add a rim:invoke-target node in config.xml");
        return;
    }

    if (invokeTargets.some(function (target) {
        return target.filter.some(function (filter) {
            return (
                (!filter.property ||
                (filter.property && filter.property[0]["@attributes"].var === "exts" && filter.property[0]["@attributes"].value.split(",").some(function (value) {
                    return invokeInfo.extension.match(value);
                })) ||
                (filter.property && filter.property[0]["@attributes"].var === "uris" && filter.property[0]["@attributes"].value.split(",").some(function (value) {
                    return invokeInfo.uri.match(value);
                }))) &&
                filter.action.some(function (action) {
                    return invokeInfo.action.match(action["#text"][0].replace("*", ""));
                }) &&
                filter["mime-type"].some(function (type) {
                    return invokeInfo.type.match(type["#text"][0].replace("*", ""));
                })
            );
        });
    })) {
        _apply('invoked', [invokeInfo]);
    }
    else {
        cons.log("Cannot invoke application, values enter to not match values in rim:invoke-target in config.xml");
    }
});

event.on('AppSwipeDown', function () {
    _apply('swipedown');
});

event.on('AppResume', function () {
    _apply('resume');
});

event.on('AppPause', function () {
    _apply('pause');
});

module.exports = {
    addEventListener: function (type, func) {
        this.removeEventListener(type, func);

        if (!app.getInfo().features || app.getInfo().features[events[type].feature]) {
            events[type].callbacks.push(func);
        }
        else {
            throw ("Cannot register a hanlder for the " + type + " event. Please add the '" + 
                  events[type].feature + "' to your config.xml.");
        }
    },

    removeEventListener: function (type, func) {
        var idx = events[type].callbacks.indexOf(func);
        if (idx >= 0) {
            delete events[type].callbacks[idx];
        }
    }
};

});
define('ripple/platform/webworks.bb10/1.0.0/connection', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    _self = {};

_self.__defineGetter__("type", function () {
    return deviceSettings.retrieve("NetworkStatus.connectionType");
});

_self.__defineGetter__("UNKNOWN", function () { return "unknown"; });
_self.__defineGetter__("ETHERNET", function () { return "ethernet"; });
_self.__defineGetter__("WIFI", function () { return "wifi"; });
_self.__defineGetter__("BLUETOOTH_DUN", function () { return "bluetooth_dun"; });
_self.__defineGetter__("USB", function () { return "usb"; });
_self.__defineGetter__("VPN", function () { return "vpn"; });
_self.__defineGetter__("BB", function () { return "rim-bb"; });
_self.__defineGetter__("CELL_2G", function () { return "2g"; });
_self.__defineGetter__("CELL_3G", function () { return "3g"; });
_self.__defineGetter__("CELL_4G", function () { return "4g"; });
_self.__defineGetter__("NONE", function () { return "none"; });

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/system', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    devices = require('ripple/devices'),
    app = require('ripple/app'),
    utils = require('ripple/utils'),
    _self;

function _is(feature) {
    return {
        allowedFor: function (location) {
            return feature && feature.URIs.some(function (uri) {
                return uri.value === location ||
                      (location.indexOf(uri.value) >= 0 && uri.subdomains);
            });
        }
    };
}

_self = {
    hasCapability: function (capability) {
        var capabilities = devices.getCurrentDevice().capabilities;
        return capabilities ? capabilities.some(function (type) {
                return type === capability;
            }) : false;
    },
    hasPermission: function (desiredModule) {
        var info = app.getInfo(),
            feature = info.features ? info.features[desiredModule] : null;

        return feature === null || _is(feature).allowedFor(utils.location().href) ? _self.ALLOW : _self.DENY;
    }
};

_self.__defineGetter__("ALLOW", function () {
    return 0;
});

_self.__defineGetter__("DENY", function () {
    return 1;
});

_self.__defineGetter__("softwareVersion", function () {
    return devices.getCurrentDevice().osVersion;
});

_self.__defineGetter__("hardwareId", function () {
    return devices.getCurrentDevice().hardwareId;
});

_self.__defineGetter__("language", function () {
    return deviceSettings.retrieve("system.language");
});

_self.__defineGetter__("region", function () {
    return deviceSettings.retrieve("system.region");
});

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/invoke', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var notifications = require('ripple/notifications'),
    utils = require('ripple/utils'),
    _self = {};

function _fail(onError) {
    if (onError && typeof onError === "function") {
        onError("invalid invocation request");
    }
}

_self.invoke = function (request, onSuccess, onError) {
    var argsString = "";

    if (!request) { // is this check even needed?
        _fail(onError);
        return;
    } else {
        if (request) {
            utils.forEach(request, function (arg, key) {
                argsString += key + " = " + arg + "</br>";
            });

            notifications.openNotification("normal", "Requested to invoke external application with the following arguments:</br> " +
                                           argsString + "</br>");
        }
        else {
            _fail(onError);
            return;
        }
    }
};

_self.__defineGetter__("ACTION_OPEN", function () {
    return "bb.action.OPEN";
});
_self.__defineGetter__("ACTION_VIEW", function () { 
    return "bb.action.VIEW"; 
});
_self.__defineGetter__("ACTION_SHARE", function () {
    return "bb.action.SHARE";
});

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/identity', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    _self = {};

_self.__defineGetter__("uuid", function () {
    return deviceSettings.retrieve("identity.uuid");
});

module.exports = _self;

});
define('ripple/platform/webworks.bb10/1.0.0/spec/events', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    event = require('ripple/event');

module.exports = {
    "blackberry.event.swipedown": {
        callback: function () {
            event.trigger("AppSwipeDown");
        }
    },
    "blackberry.event.resume": {
        callback: function () {
            event.trigger("AppResume");
        }
    },
    "blackberry.event.pause": {
        callback: function () {
            event.trigger("AppPause");
        }
    }
};

});
define('ripple/platform/webworks.bb10/1.0.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

module.exports = {
    "NetworkStatus": {
        "connectionType": {
            "name": "Connection Type",
            "control": {
                "type": "select",
                "value": "ethernet"
            },
            "options": {
                "unknown": "UNKNOWN",
                "ethernet": "ETHERNET",
                "wifi": "WIFI",
                "bluetooth_dun": "BLUETOOTH_DUN",
                "usb": "USB",
                "vpn": "VPN",
                "rim-bb": "BB",
                "2g": "CELL_2G",
                "3g": "CELL_3G",
                "4g": "CELL_4G",
                "none": "NONE"
            },
            "callback": function (setting, oldSetting) {
                event.trigger("DeviceConnectionChanged", [{oldType: oldSetting, newType: setting}]);
            }
        }
    },
    "identity": {
        "uuid": {
            "name": "uuid",
            "control": {
                "type": "text",
                "value": "43A8C489"
            }
        }
    },
    "system": {
        "language": {
            "name": "language",
            "control": {
                "type": "text",
                "value": "en_US"
            },
            "callback": function (setting) {
                event.trigger("LanguageChanged", [setting]);
            }
        },
        "region": {
            "name": "region",
            "control": {
                "type": "text",
                "value": "en_CA"
            },
            "callback": function (setting) {
                event.trigger("RegionChanged", [setting]);
            }
        }
    },
    "battery": {
        "state": {
            "name": "Handset is Charging",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("DeviceBatteryStateChanged", [setting]);
            }
        },
        "level":  {
            "name": "Charge Level (% remaining)",
            "control": {
                "type": "select",
                "value": 100
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "callback": function (setting) {
                event.trigger("DeviceBatteryLevelChanged", [setting]);
            }
        }
    },
    "Perimeters": {
        "perimeter": {
            "name": "Perimeter",
            "control": {
                "type": "select",
                "value": "Consumer"
            },
            "options": {
                "Enterprise": "Enterprise",
                "Consumer": "Consumer"
            }
        }
    }
};

});
define('ripple/platform/webworks.bb10/1.0.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        "deviceSettings",
        "geoView",
        "platformEvents",
        "widgetConfig",
        "build",
        "invoke"
    ]
};

});
define('ripple/platform/webworks.bb10/1.0.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (config) {
        return true;
    },
    extractInfo: function (config) {
        if (!config) {
            return null;
        }

        var widgetInfo = {},
            widgetFeatures = config.widget.children.feature.validationResult,
            accessUrls = config.widget.children.access.validationResult,
            invokeTargets = config.rawJSON.widget[0]["rim:invoke-target"],
            accessFeatures = config.widget.children.access.children.feature.validationResult,
            toFeature = function (validationResult) {
                return {
                    id: validationResult.attributes.id.value,
                    required: !validationResult.attributes.required || validationResult.attributes.required.value,
                    URIs: []
                };
            };

        widgetInfo.id = config.widget.validationResult[0].attributes.id.value;
        widgetInfo.name = config.widget.children.name.validationResult[0].value;
        widgetInfo.icon = config.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = config.widget.validationResult[0].attributes.version.value;
        widgetInfo.author = config.widget.children.author.validationResult[0].value;
        widgetInfo.authorEmail = config.widget.children.author.validationResult[0].attributes.email.value;
        widgetInfo.authorURL = config.widget.children.author.validationResult[0].attributes.href.value;
        widgetInfo.copyright = config.widget.children.author.validationResult[0].attributes["rim:copyright"].value;
        widgetInfo.description = config.widget.children.description.validationResult[0].value;
        widgetInfo.invokeTargets = invokeTargets;
        if (config.widget.children.license.validationResult[0]) {
            widgetInfo.license = config.widget.children.license.validationResult[0].value;
            widgetInfo.licenseURL = config.widget.children.license.validationResult[0].attributes.href.value;
        }

        widgetInfo.features = widgetFeatures.reduce(function (features, validationResult) {
            if (validationResult.valid) {
                var feature = toFeature(validationResult);
                feature.URIs.push({
                    value: utils.location().href,
                    subdomains: true
                });
                features = features || {};
                features[feature.id] = feature;
            }
            return features;
        }, {});

        widgetInfo.features = accessUrls.map(function (access) {
            return {
                uri: access.attributes.uri.value,
                subdomains: access.attributes.subdomains.value,
                features: accessFeatures ? accessFeatures.filter(function (f) {
                    return f.node && f.node.parentNode && f.node.parentNode.attributes.uri.value === access.attributes.uri.value;
                }) : null
            };
        }).reduce(function (result, access) {
            return access.features ? access.features.reduce(function (features, validationResult) {
                var feature = features[validationResult.attributes.id.value] || toFeature(validationResult);
                feature.URIs.push({
                    value: access.uri,
                    subdomains: access.subdomains
                });
                features[feature.id] = feature;
                return features;
            }, result) : result;
        }, widgetInfo.features);

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xmlns:rim": {
                    attributeName: "xmlns:rim",
                    required: true,
                    type: "list",
                    listValues: ["http://www.blackberry.com/ns/widgets"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                },
                id: {
                    attributeName: "id",
                    required: false,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    required: false,
                    type: "string"
                },
                "rim:header": {
                    attributeName: "rim:header",
                    required: false,
                    type: "string"
                },
                "rim:backButton": {
                    attributeName: "rim:backButton",
                    required: false,
                    type: "string"
                }
            },
            children: {
                name: {
                    nodeName: "name",
                    required: true,
                    occurrence: 1,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        "rim:hover": {
                            attributeName: "rim:hover",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        href: {
                            attributeName: "href",
                            type: "string",
                            required: false
                        },
                        "rim:copyright": {
                            attributeName: "rim:copyright",
                            type: "string",
                            required: false
                        },
                        email: {
                            attributeName: "email",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 1,
                    attributes : {
                        href: {
                            attributeName: "href",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language"
                        },
                        "its:dir": {
                            attributeName: "its:dir",
                            required: false,
                            type: "list",
                            listValues: ["rtl", "ltr", "lro", "rlo"]
                        }
                    }
                },
                "rim:cache": {
                    nodeName: "rim:cache",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        disableAllCache: {
                            attributeName: "disableAllCache",
                            required: false,
                            type: "boolean"
                        },
                        aggressiveCacheAge: {
                            attributeName: "aggressiveCacheAge",
                            required: false,
                            type: "number"
                        },
                        maxCacheSizeTotal: {
                            attributeName: "maxCacheSizeTotal",
                            required: false,
                            type: "number"
                        },
                        maxCacheSizeItem: {
                            attributeName: "maxCacheSizeItem",
                            required: false,
                            type: "number"
                        }
                    }
                },
                access: {
                    nodeName: "access",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        uri: {
                            attributeName: "uri",
                            required: true,
                            type: "string"
                        },
                        subdomains: {
                            attributeName: "subdomains",
                            required: false,
                            type: "boolean"
                        }
                    },
                    children: {
                        feature: {
                            nodeName: "feature",
                            required: false,
                            occurrence: 0,
                            attributes: {
                                id: {
                                    attributeName: "id",
                                    required: true,
                                    //TODO: this should be a list
                                    type: "string"
                                },
                                required: {
                                    attributeName: "required",
                                    required: false,
                                    type: "boolean"
                                },
                                version: {
                                    attributeName: "version",
                                    required: false,
                                    type: "string"
                                }
                            }
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        id: {
                            attributeName: "id",
                            required: true,
                            //TODO: this should be a list
                            type: "string"
                        },
                        required: {
                            attributeName: "required",
                            required: false,
                            type: "boolean"
                        },
                        version: {
                            attributeName: "version",
                            required: false,
                            type: "string"
                        }
                    }
                },
                "rim:loadingScreen": {
                    nodeName: "rim:loadingScreen",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        backgroundColor: {
                            attributeName: "backgroundColor",
                            required: false,
                            type: "string"
                        },
                        backgroundImage: {
                            attributeName: "backgroundImage",
                            required: false,
                            type: "string"
                        },
                        foregroundImage: {
                            attributeName: "foregroundImage",
                            required: false,
                            type: "string"
                        },
                        onRemotePageLoad: {
                            attributeName: "onRemotePageLoad",
                            required: false,
                            type: "boolean"
                        },
                        onLocalPageLoad: {
                            attributeName: "onLocalPageLoad",
                            required : false,
                            type: "boolean"
                        },
                        onFirstLaunch: {
                            attributeName: "onFirstLaunch",
                            required: false,
                            type: "boolean"
                        }
                    },
                    children: {
                        "rim:transitionEffect": {
                            nodeName: "rim:transitionEffect",
                            required: false,
                            occurrence: 1,
                            attributes: {
                                "type": {
                                    attributeName: "type",
                                    required: true,
                                    type: "list",
                                    listValues: ["slidePush", "slideOver", "fadeIn", "fadeOut", "wipeIn", "wipeOut", "zoomIn", "zoomOut"]
                                },
                                duration: {
                                    attributeName: "duration",
                                    required: false,
                                    type: "number"
                                },
                                direction: {
                                    attributeName: "direction",
                                    required: false,
                                    type: "list",
                                    listValues: ["left", "right", "up", "down"]
                                }
                            }
                        }
                    }
                },
                "rim:invoke-target": {
                    nodeName: "rim:invoke-target",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        id: {
                            attributeName: "id",
                            required: true,
                            type: "string"
                        }
                    },
                    children: {
                        "type": {
                            nodeName: "type",
                            required: true,
                            occurrence: 1
                        },
                        "require-source-permissions": {
                            nodeName: "require-source-permissions",
                            required: false,
                            occurence: 0
                        },
                        "filter": {
                            nodeName: "filter",
                            required: false,
                            occurence: 0,
                            children: {
                                "action": {
                                    nodeName: "action",
                                    required: true,
                                    occurence: 0
                                },
                                "mime-type": {
                                    nodeName: "mime-type",
                                    required: true,
                                    occurence: 0
                                },
                                "property": {
                                    nodeName: "property",
                                    required: false,
                                    occurenc: 0,
                                    attributes: {
                                        "var": {
                                            attributeName: "var",
                                            required: false,
                                            type: "string"
                                        },
                                        "value": {
                                            attributeName: "value",
                                            required: false,
                                            type: "string"
                                        }
                                    }
                                }
                            },
                        }
                    }
                },
                "rim:connection": {
                    nodeName: "rim:connection",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        timeout: {
                            attributeName: "timeout",
                            required: false,
                            type: "number"
                        }
                    },
                    children: {
                        id: {
                            nodeName: "id",
                            required: false,
                            occurrence: 0
                        }
                    }
                },
                "rim:navigation": {
                    nodeName: "rim:navigation",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        mode: {
                            attributeName: "mode",
                            required: false,
                            type: "list",
                            listValues: ["focus"]
                        }
                    }
                },
                "content": {
                    nodeName: "content",
                    required: true,
                    occurrence: 1,
                    attributes: {
                        src: {
                            attributeName: "src",
                            required: true,
                            type: "string"
                        },
                        type: {
                            attributeName: "type",
                            required: false,
                            type: "string"
                        },
                        charset: {
                            attributeName: "charset",
                            required: false,
                            type: "string"
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/webworks.bb10/1.0.0/spec', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    id: "webworks.bb10",
    version: "1.0.0",
    name: "BlackBerry 10 WebWorks",

    persistencePrefix: "rim-bb10-",

    ui: require('ripple/platform/webworks.bb10/1.0.0/spec/ui'),
    device: require('ripple/platform/webworks.bb10/1.0.0/spec/device'),
    config: require('ripple/platform/webworks.bb10/1.0.0/spec/config'),
    events: require('ripple/platform/webworks.bb10/1.0.0/spec/events'),

    initialize: function () {
        var event = require('ripple/event'),
            _console = require('ripple/console'),
            emulatorBridge = require('ripple/emulatorBridge');

        event.on("TinyHipposLoaded", function () {
            var doc = emulatorBridge.document(),
                evt = doc.createEvent("Events");
            evt.initEvent("webworksready", true, true);
            doc.dispatchEvent(evt);
            _console.log("fired webworksready event!");
        });
    },

    objects: {
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        navigator: {
            path: "webworks.bb10/1.0.0/navigator",
            children: {
                geolocation: {
                    path: "w3c/1.0/geolocation"
                }
            }
        },
        blackberry: {
            children: {
                event: {
                    path: "webworks.bb10/1.0.0/event"
                },
                app: {
                    path: "webworks.bb10/1.0.0/app",
                    feature: "blackberry.app"
                },
                invoke: {
                    path: "webworks.bb10/1.0.0/invoke",
                    feature: "blackberry.invoke"
                },
                identity: {
                    path: "webworks.bb10/1.0.0/identity",
                    feature: "blackberry.identity"
                },
                system: {
                    path: "webworks.bb10/1.0.0/system"
                },
                connection: {
                    path: "webworks.bb10/1.0.0/connection"
                },
                ui: {
                    children: {
                        dialog: {
                            path: "webworks.bb10/1.0.0/dialog",
                            feature: "blackberry.ui.dialog"
                        }
                    }
                },
            }
        }
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/accelerometer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    _success,
    _error,
    _current = {x: 0, y: 0, z: 0, timestamp: (new Date()).getTime()},
    _interval;

event.on("AccelerometerInfoChangedEvent", function (accelerometerInfo) {
    _current.x = accelerometerInfo.accelerationIncludingGravity.x;
    _current.y = accelerometerInfo.accelerationIncludingGravity.y;
    _current.z = accelerometerInfo.accelerationIncludingGravity.z;
    _current.timestamp = (new Date()).getTime();
});

module.exports = {
    start: function (success, error, args) {
        _success = success;
        _error = error;
        // Possible HACK? update the timestamp of the last data to something current
        _interval = window.setInterval(function () {
            _current.timestamp = (new Date()).getTime();
            _success(_current);
        }, 50);
    },

    stop: function () {
        _success = null;
        _error = null;
        window.clearInterval(_interval);
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/geolocation', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    geo = require('ripple/geo'),
    utils = require('ripple/utils'),
    PositionError = require('ripple/platform/w3c/1.0/PositionError'),
    _watches = {},
    _current = {
        "latitude": 43.465187,
        "longitude": -80.522372,
        "altitude": 100,
        "accuracy": 150,
        "altitudeAccuracy": 80,
        "heading": 0,
        "velocity": 0,
    },
    _error;

function _getCurrentPosition(win, fail) {
    if (geo.timeout) {
        if (fail) {
            var positionError = new PositionError();

            positionError.code = PositionError.TIMEOUT;
            positionError.message = "postion timed out";
            fail(positionError);
        }
    }
    else {
        win(geo.getPositionInfo());
    }
}

event.on("PositionInfoUpdatedEvent", function (pi) {
    _current.latitude = pi.latitude;
    _current.longitude = pi.longitude;
    _current.altitude = pi.altitude;
    _current.accuracy = pi.accuracy;
    _current.altitudeAccuracy = pi.altitudeAccuracy;
    _current.heading = pi.heading;
    _current.velocity = pi.speed;

    utils.forEach(_watches, function (watch) {
        try {
            _getCurrentPosition(watch.win, watch.fail);
        } catch (e) {
            console.log(e);
        }
    });
});

module.exports = {
    getLocation: function (success, error, args) {
        _getCurrentPosition(success, error);
    },

    addWatch: function (success, error, args) {
        _watches[args[0]] = {
            win: success,
            fail: error
        };
        _getCurrentPosition(success, error);
    },

    clearWatch: function (id) {
        delete _watches[id];
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var camera = require('ripple/ui/plugins/camera'),
    event = require('ripple/event');

module.exports = {
    show: function (success, error, args) {
        return success && success();
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var devices = require('ripple/devices');

module.exports = {
    getDeviceInfo: function (success, fail, args) {
        var device = devices.getCurrentDevice();

        success({
            available: true,
            platform: device.osName,
            version: device.osVersion,
            name: device.name,
            uuid: device.uuid,
            cordova: "2.0.0"
        });
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/file', function (require, exports, module) {
// HACK: fs keeps a reference to the last-used FileSystem requested via requestFileSystem
// this is a hack because if you keep switching between TEMPORARY vs. PERSISTENT file systems requested,
// and run Cordova File API methods, no parameter is passed into exec specifying the underlying File System.
// This should be fixed in Cordova!
var fs, 
    topCordova = require('ripple/platform/cordova/2.0.0/spec'),
    rlfsu;

function cleanPath(path) {
    while (path[0] && path[0] === '/') {
        path = path.substr(1);
    }
    return path;
}

module.exports = {
    requestFileSystem: function (win, fail, args) {
        // HACK: may not be webkit
        var rfs = window.webkitRequestFileSystem,
            type = args[0],
            size = args[1];

        // HACK: assume any FS requested over a gig in size will throw an error
        if (size > (1024 * 1024 * 1024 /* gigabyte */)) {
            if (fail) fail(FileError.QUOTA_EXCEEDED_ERR);
        } else {
            return rfs(type, size, function (effes) {
                fs = effes;
                win(effes);
            }, fail);
        }
    },
    resolveLocalFileSystemURI: function (win, fail, args) {
        var uri = args[0],
            fulluri = fs.root.toURL();

        // HACK: iOS-specific bs right here. See lib/ios/plugin/ios/Entry.js in cordova.js for details
        // Cordova badly needs a unified File System abstraction.
        if (uri.indexOf("file://localhost") === 0) {
            uri = uri.substr(16);
        }
        uri = cleanPath(uri);

        fulluri += uri;

        return window.webkitResolveLocalFileSystemURL(fulluri, function (entry) {
            if (win) win(entry);
        }, function (error) {
            if (fail) fail(error.code);
        });
    },
    getFile: function (win, fail, args) {
        var path = args[0],
            filename = args[1],
            options = args[2],
            file = '';

        path = cleanPath(path);
        filename = cleanPath(filename);

        if (path) {
            file = path + '/';
        }
        file += filename;

        fs.root.getFile(file, options, function (entry) {
            if (win) win(entry);
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    remove: function (win, fail, args) {
        var file = args[0];
        window.webkitResolveLocalFileSystemURL(fs.root.toURL() + file, function (entry) {
            entry.remove(function () {
                if (win) win();
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, fail);
    },
    readEntries: function (win, fail, args) {
        var root = fs.root.toURL(),
            path = args[0],
            reader;

        path = cleanPath(path);
        path = root + path;

        window.webkitResolveLocalFileSystemURL(path, function (entry) {
            reader = entry.createReader();
            reader.readEntries(function (entries) {
                if (win) win(entries);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    getDirectory: function (win, fail, args) {
        var path = args[0],
            filename = args[1],
            options = args[2],
            file = '';

        path = cleanPath(path);
        filename = cleanPath(filename);

        if (path) {
            file = path + '/';
        }
        file += filename;

        fs.root.getDirectory(file, options, function (entry) {
            if (win) win(entry);
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    removeRecursively: function (win, fail, args) {
        var root = fs.root.toURL(),
            path = args[0];

        path = cleanPath(path);

        window.webkitResolveLocalFileSystemURL(root + path, function (dirEntry) {
            dirEntry.removeRecursively(function () {
                if (win) win();
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    getFileMetadata: function (win, fail, args) {
        var path = args[0],
            root = fs.root.toURL();

        path = cleanPath(path);

        window.webkitResolveLocalFileSystemURL(root + path, function (entry) {
            entry.file(function (file) {
                if (win) win(file);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    getMetadata: function (win, fail, args) {
        var path = args[0],
            root = fs.root.toURL();

        path = cleanPath(path);
        
        window.webkitResolveLocalFileSystemURL(root + path, function (entry) {
            entry.getMetadata(function (data) {
                if (win) win(data);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    getParent: function (win, fail, args) {
        var path = args[0],
            root = fs.root.toURL();

        path = cleanPath(path);

        window.webkitResolveLocalFileSystemURL(root + path, function (entry) {
            entry.getParent(function (dirEntry) {
                if (win) win(dirEntry);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    copyTo: function (win, fail, args) {
        var src = args[0],
            parent = args[1],
            name = args[2],
            root = fs.root.toURL();

        parent = cleanPath(parent);
        src = cleanPath(src);

        rlfsu = window.webkitResolveLocalFileSystemURL;
        // get the directoryentry that we will copy TO
        rlfsu(root + parent, function (parentDirToCopyTo) {
            rlfsu(root + src, function (sourceDir) {
                sourceDir.copyTo(parentDirToCopyTo, name, function (newEntry) {
                    if (win) win(newEntry);
                }, function (err) {
                    if (fail) fail(err.code);
                });
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    moveTo: function (win, fail, args) {
        var src = args[0],
            parent = args[1],
            name = args[2],
            root = fs.root.toURL();

        parent = cleanPath(parent);
        src = cleanPath(src);

        rlfsu = window.webkitResolveLocalFileSystemURL;
        // get the directoryentry that we will move TO
        rlfsu(root + parent, function (parentDirToMoveTo) {
            rlfsu(root + src, function (sourceDir) {
                sourceDir.moveTo(parentDirToMoveTo, name, function (newEntry) {
                    if (win) win(newEntry);
                }, function (err) {
                    if (fail) fail(err.code);
                });
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    write: function (win, fail, args) {
        var file = args[0],
            text = args[1],
            position = args[2],
            sourcepath,
            BB = window.BlobBuilder || window.WebKitBlobBuilder,
            bb = new BB();

        // Format source path
        sourcepath = (file.fullPath ? file.fullPath : '') + file.name;
        sourcepath = cleanPath(sourcepath);

        // Create a blob for the text to be written
        bb.append(text);

        // Get the FileEntry, create if necessary
        fs.root.getFile(sourcepath, {create: true}, function (entry) {
            // Create a FileWriter for this entry
            entry.createWriter(function (writer) {
                writer.onwriteend = function (progressEvt) {
                    if (win) win(progressEvt.total);
                };
                writer.onerror = function (err) {
                    if (fail) fail(err.code);
                };

                if (position && position > 0) {
                    writer.seek(position);
                }
                writer.write(bb.getBlob('text/plain'));
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    readAsText: function (win, fail, args) {
        var path = args[0],
            encoding = args[1],
            FileReader = topCordova.nativeMethods.FileReader,
            fr = new window.FileReader();

        // Set up FileReader events
        fr.onerror = function (err) {
            if (fail) fail(err.code);
        };
        fr.onload = function (evt) {
            if (win) win(evt.target.result);
        };

        path = cleanPath(path);

        fs.root.getFile(path, {create: false}, function (entry) {
            entry.file(function (blob) {
                fr.readAsText(blob, encoding);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    readAsDataURL: function (win, fail, args) {
        var path = args[0],
            FileReader = topCordova.nativeMethods.FileReader,
            fr = new window.FileReader();

        // Set up FileReader events
        fr.onerror = function (err) {
            if (fail) fail(err.code);
        };
        fr.onload = function (evt) {
            if (win) win(evt.target.result);
        };

        path = cleanPath(path);

        fs.root.getFile(path, {create: false}, function (entry) {
            entry.file(function (blob) {
                fr.readAsDataURL(blob);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    },
    truncate: function (win, fail, args) {
        var file = args[0],
            position = args[1],
            sourcepath;

        // Format source path
        sourcepath = (file.fullPath ? file.fullPath : '') + file.name;
        sourcepath = cleanPath(sourcepath);

        // Get the FileEntry, create if necessary
        fs.root.getFile(sourcepath, {create: false}, function (entry) {
            // Create a FileWriter for this entry
            entry.createWriter(function (writer) {
                writer.onwriteend = function (progressEvt) {
                    if (win) win(progressEvt.target.length);
                };
                writer.onerror = function (err) {
                    if (fail) fail(err.code);
                };

                writer.truncate(position);
            }, function (err) {
                if (fail) fail(err.code);
            });
        }, function (err) {
            if (fail) fail(err.code);
        });
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/camera', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var camera = require('ripple/ui/plugins/camera'),
    event = require('ripple/event');

module.exports = {
    takePicture: function (success, error, args) {
        event.once("captured-image", function (uri, file) {
            success(uri);
        });
        camera.show();
    },
    cleanup: function (success, error, args) {
        success();
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/console', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {
    log: function (win, fail, args) {
        console.log(args[0]);
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/compass', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var geo = require('ripple/geo');

module.exports = {
    getHeading: function (success, error, args) {
        // TODO: build facility to trigger onError() from emulator
        // see pivotal item: https://www.pivotaltracker.com/story/show/7040343
        success({
            magneticHeading: geo.getPositionInfo().heading, 
            trueHeading: geo.getPositionInfo().heading, 
            headingAccuracy: 100, 
            timestamp: new Date().getSeconds()
        });
    },

    stopHeading: function () { 
        //do nothing
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/contacts', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    utils = require('ripple/utils'),
    _self;

function _default() {
    return [{
        "name": {formatted: "Brent Lintner"},
        "displayName": "Brent Lintner",
        "emails": [{type: "work", value: "brent@tinyhippos.com", pref: false}]
    }, {
        "name": {formatted: "PJ Lowe"},
        "displayName": "PJ Lowe",
        "emails": [{type: "work", value: "pj@tinyhippos.com", pref: false}]
    }, {
        "name": {formatted: "Dan Silivestru"},
        "displayName": "Dan Silivestru",
        "emails": [{type: "work", value: "dan@tinyhippos.com", pref: false}]
    }, {
        "name": {formatted: "Gord Tanner"},
        "displayName": "Gord Tanner",
        "emails": [{type: "work", value: "gord@tinyhippos.com", pref: true}]
    }, {
        "name": {formatted: "Mark McArdle"},
        "displayName": "Mark McArdle",
        "emails": [{type: "work", value: "mark@tinyhippos.com", pref: false}]
    }].map(function (obj) {
        obj.id = Math.uuid(undefined, 16);
        return navigator.contacts.create(obj);
    });
}

function _get() {
    return db.retrieveObject("cordova-contacts") || _default();
}

function _save(contacts) {
    db.saveObject("cordova-contacts", contacts);
}

function _filtered(compare, options) {
    // this could be done a lot better..
    var found = false;
    if (!options.filter || options.filter === "") {
        found = true;
    } else if (typeof compare === "string" &&
              compare.match(new RegExp(".*" + options.filter + ".*", "i"))) {
        found = true;
    } else if (typeof compare === "object" || compare instanceof Array) {
        utils.forEach(compare, function (value) {
            if (!found) {
                found = _filtered(value, options);
            }
        });
    }
    return found;
}

_self = {
    search: function (success, error, args) {
        var fields = args[0],
            options = args[1],
            foundContacts = [],
            tempContact = navigator.contacts.create(),
            contacts = _get();

        options = options || {};

        // handle special case of ["*"] to return all fields
        if (fields.length === 1 && fields[0] === "*") {
            fields = utils.map(tempContact, function (v, k) {
                return k;
            });
        }

        if (fields.length > 0) {
            contacts.forEach(function (contact, index) {
                var newContact = navigator.contacts.create(contact);

                if (options && (!_filtered(contact, options))) {
                    return;
                }

                utils.forEach(newContact, function (value, prop) {
                    if (typeof newContact[prop] !== "function" && prop !== "id" &&
                        !fields.some(function (field) {
                            return field === prop;
                        })) {
                        delete newContact[prop];
                    }
                });

                foundContacts.push(newContact);
            });
        }

        // TODO: don't loop over entire db just to slice the array
        if (options.multiple === false) {
            foundContacts = foundContacts.splice(0, 1);
        }
        success(foundContacts);
    },

    save: function (success, error, args) {
        var contacts = _get(),
            contact = args[0],
            index;

        if (!contact.id) {
            contact.id = Math.uuid(undefined, 16);
            contacts.push(contact);
        } else {
            index = contacts.reduce(function (result, value, index) {
                return value.id === contact.id ? index : result;
            }, -1);

            if (index >= 0) {
                utils.mixin(contact, contacts[index]);
                contact = contacts[index];
            } else {
                contact = null;
            }
        }

        _save(contacts);
        if (success) {
            success(contact);
        }
    },

    remove: function (success, error, args) {
        var contacts = _get(),
            id = args[0],
            toDelete = contacts.reduce(function (result, current, index) {
                return current.id === id ? index : result;
            }, -1);

        if (toDelete >= 0) {
            contacts.splice(toDelete, 1);
            _save(contacts);
            if (success) {
                success();
            }
        } else {
            error({code: 3, message: "could not find contact with id (" + id + ")"}); // PENDING_OPERATION_ERROR
        }
    }
};

module.exports = _self;

});
define('ripple/platform/cordova/2.0.0/bridge/media', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var audioObjects = {},
    noop = function () {};

function createAudio(id, src, error) {
    var a = new Audio();
    a.addEventListener("error", function (e) {
        error(new window.MediaError(1, e.toString()));
    });
    a.addEventListener("durationchange", function () {
        //HACK: I don't like this but best way for us to update the duration
        cordova.require("cordova/plugin/Media").onStatus(id, 2, this.duration);
    });
    a.src = src;

    return a;
}

module.exports = {
    create: function (success, error, args) {
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            src = args[1];

        error = error || noop;
        success = success || noop;

        audioObjects[id] = createAudio(id, src, error);
        success();
    },
    startPlayingAudio: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (args.length === 1) {
            error("Media source argument not found");
            return;
        }

        if (audio) {
            audio.pause();
            audioObjects[id] = undefined;
        }

        audio = audioObjects[id] = createAudio(id, args[1], error);
        audio.play();

        success();
    },
    stopPlayingAudio: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (!audio) {
            error("Audio Object has not been initialized");
            return;
        }

        audio.pause();
        audioObjects[id] = undefined;

        success();
    },
    seekToAudio: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (!audio) {
            error("Audio Object has not been initialized");
            return;
        } else if (args.length === 1) {
            error("Media seek time argument not found");
            return;
        } else {
            try {
                audio.currentTime = args[1];
            } catch (e) {
                error("Error seeking audio: " + e);
            }
        }

        success();
    },
    pausePlayingAudio: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (!audio) {
            error("Audio Object has not been initialized");
            return;
        }

        audio.pause();
        success();
    },
    getCurrentPositionAudio: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (!audio) {
            error("Audio Object has not been initialized");
            return;
        }

        success(audio.currentTime);
    },
    getDuration: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (!audio) {
            error("Audio Object has not been initialized");
            return;
        }

        success(audio.duration);
    },
    startRecordingAudio: function (success, error, args) {
        error = error || noop;
        error("Not supported");
    },
    stopRecordingAudio: function (success, error, args) {
        error = error || noop;
        error("Not supported");
    },
    release: function (success, error, args) {
        error = error || noop;
        success = success || noop;
        if (!args.length) {
            error("Media Object id was not sent in arguments");
            return;
        }

        var id = args[0],
            audio = audioObjects[id];

        if (audio) {
            audioObjects[id] = undefined;
            audio.src = undefined;
            //delete audio;
        }

        success();
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/capture', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var camera = require('ripple/ui/plugins/camera'),
    event = require('ripple/event');

module.exports = {
    captureImage: function (success, error, args) {
        event.once("captured-image", function (uri, file) {
            file.fullPath = uri;
            success([file]);
        });
        camera.show();
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/notification', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var notifications = require('ripple/notifications'),
    _console = require('ripple/console'),
    goodVibrations = require('ripple/ui/plugins/goodVibrations');

module.exports = {
    alert: function (success, error, args) {
        notifications.openNotification("normal", args[0]);
        return success && success();
    },

    confirm: function (success, error, args) {
        throw "Not Implemented";
    },

    activityStart: function (success, error, args) {
    },

    activityStop: function (success, error, args) { 
    },

    progressStart: function (success, error, args) {
    },

    vibrate: function (success, error, args) {
        var ms = args[0] || 500;
        goodVibrations.vibrateDevice(ms);
    },

    beep: function (success, error, args) {
        for (var i = args[0]; i > 0; i--) {
            _console.log("beep!");
        }
        notifications.openNotification("normal", "BEEP x " + args[0]);
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge/network', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var deviceSettings = require('ripple/deviceSettings'),
    event = require('ripple/event'),
    _success;

event.on("ConnectionChanged", function () {
    return _success && _success(deviceSettings.retrieve("NetworkStatus.connectionType"));
});

module.exports = {
    getConnectionInfo: function (success, fail, args) {
        _success = success;
        success(deviceSettings.retrieve("NetworkStatus.connectionType"));
    }
};

});
define('ripple/platform/cordova/2.0.0/JavaPluginManager', function (require, exports, module) {
module.exports = {
    exec: function () {
        throw "this really shouldn't be called. like ever!";
    },
    resume: function () {
        throw "this shouldn't be called";
    },
    pause: function () {
        throw "this shouldn't be called";
    },
    destroy: function () {
        throw "this shouldn't be called";
    }
};

});
define('ripple/platform/cordova/2.0.0/bridge', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _prompt = require('ripple/ui/plugins/exec-dialog');

module.exports = {
    exec: function (success, fail, service, action, args) {
        var emulator = {
            "App": require('ripple/platform/cordova/2.0.0/bridge/app'),
            "Accelerometer": require('ripple/platform/cordova/2.0.0/bridge/accelerometer'),
            "Compass": require('ripple/platform/cordova/2.0.0/bridge/compass'),
            "Camera": require('ripple/platform/cordova/2.0.0/bridge/camera'),
            "Capture": require('ripple/platform/cordova/2.0.0/bridge/capture'),
            "Contacts": require('ripple/platform/cordova/2.0.0/bridge/contacts'),
            "Debug Console": require('ripple/platform/cordova/2.0.0/bridge/console'),
            "Device": require('ripple/platform/cordova/2.0.0/bridge/device'),
            "File": require('ripple/platform/cordova/2.0.0/bridge/file'),
            "Geolocation": require('ripple/platform/cordova/2.0.0/bridge/geolocation'),
            "Media": require('ripple/platform/cordova/2.0.0/bridge/media'),
            "Network Status": require('ripple/platform/cordova/2.0.0/bridge/network'),
            "NetworkStatus": require('ripple/platform/cordova/2.0.0/bridge/network'),
            "Notification": require('ripple/platform/cordova/2.0.0/bridge/notification')
        };

        try {
            emulator[service][action](success, fail, args);
        }
        catch (e) {
            console.log("missing exec:" + service + "." + action);
            console.log(args);
            console.log(e);
            console.log(e.stack);
            //TODO: this should really not log the above lines, but they are very nice for development right now
            _prompt.show(service, action, success, fail);
        }
    }
};

});
define('ripple/platform/cordova/2.0.0/MediaError', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var MediaError = function (code, msg) {
    this.code = (code !== undefined ? code : null);
    this.message = msg || "";
};

MediaError.MEDIA_ERR_NONE_ACTIVE    = 0;
MediaError.MEDIA_ERR_ABORTED        = 1;
MediaError.MEDIA_ERR_NETWORK        = 2;
MediaError.MEDIA_ERR_DECODE         = 3;
MediaError.MEDIA_ERR_NONE_SUPPORTED = 4;

module.exports = MediaError;

});
define('ripple/platform/cordova/2.0.0/logger', function (require, exports, module) {
module.exports = {
    log: function (msg) {
        console.log(msg);
    }
};

});
define('ripple/platform/cordova/2.0.0/spec/events', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function _fires(name, data) {
    return function () {
        cordova.fireDocumentEvent(name, data);
    };
}

module.exports = {
    "deviceready": {
        callback: _fires("deviceready")
    },
    "backbutton": {
        callback: _fires("backbutton")
    },
    "menubutton": {
        callback: _fires("menubutton")
    },
    "pause": {
        callback: _fires("pause")
    },
    "resume": {
        callback: _fires("resume")
    },
    "searchbutton": {
        callback: _fires("searchbutton")
    },
    "online": {
        callback: _fires("online")
    },
    "offline": {
        callback: _fires("offline")
    }
};

});
define('ripple/platform/cordova/2.0.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

module.exports = {
    "NetworkStatus": {
        "connectionType": {
            "name": "Connection Type",
            "control": {
                "type": "select",
                "value": "ethernet"
            },
            "options": {
                "unknown": "UNKNOWN",
                "ethernet": "ETHERNET",
                "wifi": "WIFI",
                "2g": "CELL_2G",
                "3g": "CELL_3G",
                "4g": "CELL_4G",
                "none": "none"
            },
            "callback": function (setting) {
                var connected = setting !== "none";
                require('ripple/bus').send("network", connected);
            }
        },
        "lag": {
            "name": "Lag the network",
            "control": {
                type: "checkbox",
                value: false
            },
            "callback": function (setting) {
                require('ripple/bus').send("lag", setting);
            }
        },
    }
};

});
define('ripple/platform/cordova/2.0.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        "deviceSettings",
        "geoView",
        "widgetConfig",
        "platformEvents"
    ]
};

});
define('ripple/platform/cordova/2.0.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (configValidationObject) {
        var valid = true;
        valid = !((!configValidationObject.widget.validationResult[0].attributes.xmlns.valid) ||
            (!configValidationObject.widget.validationResult[0].attributes["xmlns:gap"].valid));

        return valid;
    },
    extractInfo: function (configValidationObject) {
        if (!configValidationObject) {
            return null;
        }

        var widgetInfo = {};

        widgetInfo.id = configValidationObject.widget.validationResult[0].attributes.id.value || "";
        widgetInfo.name = configValidationObject.widget.children.name.validationResult[0].value;
        widgetInfo.icon = configValidationObject.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = configValidationObject.widget.validationResult[0].attributes.version.value;

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xmlns:gap": {
                    attributeName: "xmlns:gap",
                    required: true,
                    type: "list",
                    listValues: ["http://phonegap.com/ns/1.0"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                },
                dir: {
                    attributeName: "dir",
                    required: false,
                    type: "list",
                    listValues: ["ltr", "rtl", "lro", "rlo"]
                },
                id: {
                    attributeName: "id",
                    required: false,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    required: false,
                    type: "string"
                },
                height: {
                    attributeName: "height",
                    required: false,
                    type: "integer"
                },
                width: {
                    attributeName: "width",
                    required: false,
                    type: "integer"
                },
                viewmodes: {
                    attributeName: "viewmodes",
                    required: false,
                    type: "list",
                    listValues: ["floating", "fullscreen"]
                }
            },
            children: {
                name: {
                    nodeName: "name",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "short": {
                            attributeName: "short",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 1,
                    type: "string",
                    attributes: {
                        email: {
                            attributeName: "email",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.EMAIL
                        },
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 1,
                    type: "string",
                    attributes: {
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        height: {
                            attributeName: "height",
                            required: false,
                            type: "integer"
                        },
                        width: {
                            attributeName: "width",
                            required: false,
                            type: "integer"
                        }
                    }
                },
                content: {
                    nodeName: "content",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        encoding: {
                            attributeName: "encoding",
                            type: "string",
                            required: false
                        },
                        type: {
                            attributeName: "type",
                            type: "string",
                            required: false
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        name: {
                            attributeName: "name",
                            type: "list",
                            required: true,
                            listValues: ["http://api.phonegap.com/1.0/accelerometer", "http://api.phonegap.com/1.0/camera",
                                "http://api.phonegap.com/1.0/compass", "http://api.phonegap.com/1.0/contacts", "http://api.phonegap.com/1.0/device",
                                "http://api.phonegap.com/1.0/events", "http://api.phonegap.com/1.0/file", "http://api.phonegap.com/1.0/geolocation",
                                "http://api.phonegap.com/1.0/media", "http://api.phonegap.com/1.0/network", "http://api.phonegap.com/1.0/notification",
                                "http://api.phonegap.com/1.0/storage"]
                        },
                        required: {
                            attributeName: "required",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                preference: {
                    nodeName: "preference",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        name: {
                            attributeName: "name",
                            type: "string",
                            required: true
                        },
                        value: {
                            type: "string",
                            attributeName: "value",
                            required: false
                        },
                        readonly: {
                            attributeName: "readonly",
                            type: "boolean",
                            required: false
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/cordova/2.0.0/spec', function (require, exports, module) {
function loadWebworks(win, device) {
    var builder = require('ripple/platform/builder'),
        platform = device.id === "Playbook" || device.id === "Colt" ? "tablet" : "handset",
        webworks = require('ripple/platform/webworks.' + platform + '/2.0.0/spec');

    builder.build(webworks.objects).into(win);
    builder.build(webworks.objects).into(window);
}

module.exports = {
    id: "cordova",
    version: "2.0.0",
    name: "Apache Cordova",
    type: "platform",
    nativeMethods: {},

    config: require('ripple/platform/cordova/2.0.0/spec/config'),
    device: require('ripple/platform/cordova/2.0.0/spec/device'),
    ui: require('ripple/platform/cordova/2.0.0/spec/ui'),
    events: require('ripple/platform/cordova/2.0.0/spec/events'),

    initialize: function (win) {
        var honeypot = require('ripple/honeypot'),
            devices = require('ripple/devices'),
            device = devices.getCurrentDevice(),
            bridge = require('ripple/platform/cordova/2.0.0/bridge'),
            cordova,
            topCordova = window.top.require('ripple/platform/cordova/2.0.0/spec'),
            get = function () {
                return cordova;
            },
            set = function (orig) {
                if (cordova) {
                    return;
                }

                cordova = orig;

                cordova.define.remove("cordova/exec");
                cordova.define("cordova/exec", function (require, exports, module) {
                    module.exports = bridge.exec;
                });

                cordova.UsePolling = true;

                //do nothing here as we will just call the callbacks ourselves
                cordova.define.remove("cordova/plugin/android/polling");
                cordova.define("cordova/plugin/android/polling", function (require, exports, module) {
                    module.exports = function () {};
                });

                var builder = cordova.require('cordova/builder'),
                    allTheThings = window,
                    base = cordova.require('cordova/common'),
                    iosPlugin;

                //HACK: Overwrite all the things, handles when cordova.js executes before we start booting
                builder.build(base.objects).intoAndClobber(allTheThings);
                cordova.require('cordova/channel').onNativeReady.fire();
                //  DIRTY HACK: once cordova is cleaned up, we do not
                //  need this.
                // reference issue: https://issues.apache.org/jira/browse/CB-1013
                try {
                    iosPlugin = cordova.require('cordova/plugin/ios/device');
                    bridge.exec(function (info) {
                        iosPlugin.setInfo(info);
                    }, null, 'Device', 'getDeviceInfo', []);
                } catch (e) {
                    cordova.require('cordova/channel').onCordovaInfoReady.fire();
                }
            };

        if (window.FileReader && !topCordova.nativeMethods.FileReader) {
            topCordova.nativeMethods.FileReader = window.FileReader;
        }

        if (device.manufacturer === "Research In Motion") {
            loadWebworks(win, device);
        }

        honeypot.monitor(win, "cordova").andRun(get, set);
    },

    objects: {
        MediaError: {
            path: "cordova/2.0.0/MediaError"
        },
        org: {
            children: {
                apache: {
                    children: {
                        cordova: {
                            children: {
                                Logger: {
                                    path: "cordova/2.0.0/logger"
                                },
                                JavaPluginManager: {
                                    path: "cordova/2.0.0/JavaPluginManager"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/builder', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    db = require('ripple/db'),
    app = require('ripple/app'),
    constants = require('ripple/constants');

function _objectFactory(context, objects, allowed) {
    utils.forEach(objects, function (obj, key) {
        var result = {}, objFeatures = {}, rst, f, widgetFeatures;

        if (allowed(obj)) {
            result = obj.path ? require('ripple/platform/' + obj.path) : {};
            if (typeof result === "function" && obj.handleSubfeatures && obj.handleSubfeatures === true) {
                rst = new result();
                if (obj.feature) {
                    objFeatures = obj.feature.split('|');
                    if (rst.handleSubFeatures) {
                        widgetFeatures = app.getInfo().features; // features in config.xml
                        f = {};
                        utils.forEach(objFeatures, function (o) {
                            if (widgetFeatures && !!widgetFeatures[o]) {
                                f[widgetFeatures[o].id] = widgetFeatures[o];
                            }
                        });
                        rst.handleSubFeatures(f);
                        delete rst.handleSubFeatures;
                    }
                }
                result = rst;
            }
        }

        if (obj.children) {
            _objectFactory(result, obj.children, allowed);
        }

        // inject into the context if it is allowed or it has children that were allowed
        if (allowed(obj) || utils.count(result)) {
            context[key] = result;
        }
        else {
            delete context[key];
        }
    });
}

module.exports = {
    build: function (objects) {
        return {
            into: function (sandbox) {
                var features = utils.copy(app.getInfo().features),
                    allowed = function (obj) {
                        var contains = function (requirements) {
                            return requirements.split('|').some(function (feature) {
                                return !!features[feature];
                            });
                        };
                        //object is allowed if:
                        // 1. it has no feature requirement
                        // 2. the config file doesn't exist (features collection is null)
                        // 3. the feature exists in the defined features
                        return !obj.feature || !features || (features && contains(obj.feature));
                    };

                _objectFactory(sandbox, objects, allowed);
            }
        };
    }
};

});
define('ripple/platform/wac/2.0/orientation', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    event = require('ripple/event'),
    Rotation = function (alpha, beta, gamma) {
        return {
            alpha: alpha || 0,
            beta:  beta  || 0,
            gamma: gamma || 0
        };
    },
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    _rotationInfo = new Rotation(),
    _defaultInterval = 100,
    _watches = {},
    _self;

module.exports = _self = {
    getCurrentOrientation: function (onSuccess, onError) {
        function _getCurrentOrientation() {
            setTimeout(function () {
                onSuccess(utils.copy(_rotationInfo));
            }, 1);
            return null;
        }

        return wac2_utils.validateTypeMismatch(onSuccess, onError, "getCurrentOrientation", _getCurrentOrientation);
    },

    watchOrientation: function (orientationSuccess, orientationError, options) {
        function _watchOrientation() {
            var watchId = (new Date()).getTime() | 0,
                watchObj = {},
                opt = Object(options),
                minNotificationInterval = opt.minNotificationInterval | 0,
                orientationInterval = _defaultInterval;

            if (minNotificationInterval > 0) {
                orientationInterval = minNotificationInterval;
            }

            watchObj = {
                onSuccess: orientationSuccess,
                onError: orientationError,
                interval: orientationInterval
            };

            _watches[watchId] = watchObj;

            _watches[watchId].intervalId = setInterval(function () {
                _self.getCurrentOrientation(_watches[watchId].onSuccess, _watches[watchId].onError);
            }, _watches[watchId].interval);

            return watchId;
        }

        return wac2_utils.validateTypeMismatch(orientationSuccess, orientationError, "watchOrientation", _watchOrientation);
    },

    clearWatch: function (watchId) {

        var id = watchId | 0;
        if (_watches[id]) {
            clearInterval(_watches[id].intervalId);
            delete(_watches[id]);
            return null;
        }

        return undefined;
    }
};

event.on("AccelerometerInfoChangedEvent", function (orientationInfo) {
    _rotationInfo.alpha = orientationInfo.orientation.alpha;
    _rotationInfo.beta  = orientationInfo.orientation.beta;
    _rotationInfo.gamma = orientationInfo.orientation.gamma;
});


});
define('ripple/platform/wac/2.0/accelerometer', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    event = require('ripple/event'),
    Acceleration = function (x, y, z) {
        return {
            xAxis: x || 0,
            yAxis: y || 0,
            zAxis: z || 0
        };
    },
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    _accelerometerInfo = new Acceleration(),
    _defaultInterval = 100,
    _watches = {},
    _self;

module.exports = _self = {
    getCurrentAcceleration: function (onSuccess, onError) {
        function _getCurrentAcceleration() {
            setTimeout(function () {
                onSuccess(utils.copy(_accelerometerInfo));
            }, 1);
            return null;
        }

        return wac2_utils.validateTypeMismatch(onSuccess, onError, "getCurrentAcceleration", _getCurrentAcceleration); 
    },

    watchAcceleration: function (accelerometerSuccess, accelerometerError, options) {
        function _watchAcceleration() {
            var watchId = (new Date()).getTime() | 0,
                watchObj = {},
                opt = Object(options),
                minNotificationInterval = opt.minNotificationInterval | 0,
                accelerometerInterval = _defaultInterval;

            if (minNotificationInterval > 0) {
                accelerometerInterval = minNotificationInterval;
            }

            watchObj = {
                onSuccess: accelerometerSuccess,
                onError: accelerometerError,
                interval: accelerometerInterval
            };

            _watches[watchId] = watchObj;

            _watches[watchId].intervalId = setInterval(function () {
                _self.getCurrentAcceleration(_watches[watchId].onSuccess, _watches[watchId].onError);
            }, _watches[watchId].interval);

            return watchId;
        }

        return wac2_utils.validateTypeMismatch(accelerometerSuccess, accelerometerError, "watchAcceleration", _watchAcceleration); 
    },

    clearWatch: function (watchId) {

        var id = watchId | 0;

        if (_watches[id]) {
            clearInterval(_watches[id].intervalId);
            delete(_watches[id]);
            return null;
        }

        return undefined;
    }
};

event.on("AccelerometerInfoChangedEvent", function (accelerometerInfo) {
    _accelerometerInfo.xAxis = accelerometerInfo.accelerationIncludingGravity.x;
    _accelerometerInfo.yAxis = accelerometerInfo.accelerationIncludingGravity.y;
    _accelerometerInfo.zAxis = accelerometerInfo.accelerationIncludingGravity.z;
});


});
define('ripple/platform/wac/2.0/geolocation', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var geo = require('ripple/geo'),
    Position = require('ripple/platform/w3c/1.0/Position'),
    PositionError = require('ripple/platform/w3c/1.0/PositionError'),
    _lastPosition = null,
    _watches = {},
    _defaultInterval = 100,
    _defaultDelay = 50,
    _self;

function _createPosition() {
    var position = new Position(),
        positionInfo = geo.getPositionInfo();

    position.coords.latitude = positionInfo.latitude;
    position.coords.longitude = positionInfo.longitude;
    position.coords.altitude = positionInfo.altitude;
    position.coords.altitudeAccuracy = positionInfo.altitudeAccuracy;
    position.coords.accuracy = positionInfo.accuracy;
    position.coords.heading = positionInfo.heading;
    position.coords.speed = positionInfo.speed;
    position.timestamp = positionInfo.timeStamp.getTime();

    return position;
}

function _isValid(onSuccess, onError, options, argLength) {
    if (argLength < 1 || argLength > 3)
        return false;

    if (typeof onSuccess !== "function")   // imply onSuccess == null
        return false;

    if (onError && (typeof onError !== "function"))
        return false;

    if ((options !== undefined) &&
        ((typeof options !== "object") ||
        (options.enableHighAccuracy !== undefined) && (typeof options.enableHighAccuracy !== "boolean") ||
        (options.timeout            !== undefined) && (typeof options.timeout            !== "number") ||
        (options.maximumAge         !== undefined) && (typeof options.maximumAge         !== "number")))
        return false;

    return true;
}

function _processOptions(options) {
    var validOptions = {
        enableHighAccuracy: false,
        timeout: 0,
        maximumAge: 0
    };

    if (options !== undefined &&
        options.maximumAge !== undefined &&
        options.maximumAge === Math.floor(options.maximumAge) &&
        options.maximumAge >= 0) {
        validOptions.maximumAge = options.maximumAge | 0;
    } else {
        validOptions.maximumAge = 0;
    }

    if (options !== undefined &&
        options.timeout !== undefined &&
        options.timeout === Math.floor(options.timeout)) {
        validOptions.timeout = (options.timeout >= 0) ? (options.timeout | 0) : 0;
    } else {
        validOptions.timeout = Infinity;
    }

    if (options !== undefined && options.enableHighAccuracy !== undefined) {
        validOptions.enableHighAccuracy = options.enableHighAccuracy;
    } else {
        validOptions.enableHighAccuracy = false;
    }

    validOptions.delay = geo.delay * 1000 || _defaultDelay;

    return validOptions;
}

function _errorOccur(code, onError) {
    if (!onError)
        return;

    var error = new PositionError();

    error.code = code;
    switch (code) {
    case PositionError.POSITION_UNAVAILABLE:
        error.message = "Position unavailable";
        break;

    case PositionError.TIMEOUT:
        error.message = "Position timed out";
        break;
    }

    onError(error);
}

function _execute(data) {
    return function () {
        if (_lastPosition !== null &&
            ((new Date()).getTime() - _lastPosition.timestamp <= data.maximumAge)) {
            window.setTimeout(function () {
                data.onSuccess(_lastPosition);
            }, 1);
        } else if (data.timeout === 0) {
            _errorOccur(PositionError.TIMEOUT, data.onError);
        } else {
            window.setTimeout(function () {
                if (data.delay <= data.timeout) {
                    _lastPosition = _createPosition();

                    if (_lastPosition !== null) {
                        data.onSuccess(_lastPosition);
                    } else {
                        _errorOccur(PositionError.POSITION_UNAVAILABLE, data.onError);
                    }
                } else {
                    _errorOccur(PositionError.TIMEOUT, data.onError);
                }
            }, Math.min(data.delay, data.timeout));
        }
    };
}

function _interval(k, n) { 
    return k * Math.floor((n + k - 1) / k) || k;
}

_self = {
    getCurrentPosition: function (onSuccess, onError, options) {
        if (!_isValid(onSuccess, onError, options, arguments.length))
            return;

        var validData = _processOptions(options);

        validData.onSuccess = onSuccess;
        validData.onError   = onError;

        _execute(validData)();
    },

    watchPosition: function (geolocationSuccess, geolocationError, geolocationOptions) {
        if (!_isValid(geolocationSuccess, geolocationError, geolocationOptions, arguments.length))
            return undefined;

        var validData = _processOptions(geolocationOptions),
            watchId = (new Date()).getTime() | 0,
            watchObj = {
                onSuccess:          geolocationSuccess,
                onError:            geolocationError,
                enableHighAccuracy: validData.enableHighAccuracy,
                timeout:            validData.timeout,
                maximumAge:         validData.maximumAge,
                delay:              validData.delay,
                interval:           _interval(validData.maximumAge || _defaultInterval,
                                        Math.min(validData.delay, validData.timeout)),
            };

        _watches[watchId] = watchObj;

        _watches[watchId].intervalId = window.setInterval(_execute(_watches[watchId]),
            _watches[watchId].interval);

        return watchId;
    },

    clearWatch: function (watchId) {
        if (arguments.length !== 1)
            return undefined;

        var id = watchId | 0;

        if (_watches[id]) {
            window.clearInterval(_watches[id].intervalId);
            delete _watches[id];

            return null;
        }

        return undefined;
    }
};

module.exports = _self;

});
define('ripple/platform/wac/2.0/errorcode', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"),
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _self = {
    message : []
};

_self.__defineGetter__("UNKNOWN_ERR", function () {
    return 0;
});

_self.__defineGetter__("INDEX_SIZE_ERR", function () {
    return 1;
});

_self.__defineGetter__("DOMSTRING_SIZE_ERR", function () {
    return 2;
});

_self.__defineGetter__("HIERARCHY_REQUEST_ERR", function () {
    return 3;
});

_self.__defineGetter__("WRONG_DOCUMENT_ERR", function () {
    return 4;
});

_self.__defineGetter__("INVALID_CHARACTER_ERR", function () {
    return 5;
});

_self.__defineGetter__("NO_DATA_ALLOWED_ERR", function () {
    return 6;
});

_self.__defineGetter__("NO_MODIFICATION_ALLOWED_ERR", function () {
    return 7;
});

_self.__defineGetter__("NOT_FOUND_ERR", function () {
    return 8;
});

_self.__defineGetter__("NOT_SUPPORTED_ERR", function () {
    return 9;
});

_self.__defineGetter__("INUSE_ATTRIBUTE_ERR", function () {
    return 10;
});

_self.__defineGetter__("INVALID_STATE_ERR", function () {
    return 11;
});

_self.__defineGetter__("SYNTAX_ERR", function () {
    return 12;
});

_self.__defineGetter__("INVALID_MODIFICATION_ERR", function () {
    return 13;
});

_self.__defineGetter__("NAMESPACE_ERR", function () {
    return 14;
});

_self.__defineGetter__("INVALID_ACCESS_ERR", function () {
    return 15;
});

_self.__defineGetter__("VALIDATION_ERR", function () {
    return 16;
});

_self.__defineGetter__("TYPE_MISMATCH_ERR", function () {
    return 17;
});

_self.__defineGetter__("SECURITY_ERR", function () {
    return 18;
});

_self.__defineGetter__("NETWORK_ERR", function () {
    return 19;
});

_self.__defineGetter__("ABORT_ERR", function () {
    return 20;
});

_self.__defineGetter__("TIMEOUT_ERR", function () {
    return 21;
});

_self.__defineGetter__("INVALID_VALUES_ERR", function () {
    return 22;
});

_self.__defineGetter__("IO_ERR", function () {
    return 100;
});

_self.__defineGetter__("NOT_AVAILABLE_ERR", function () {
    return 101;
});

function _setMessage(_self) {
    var c, g;
    for (c in _self) {
        g = _self.__lookupGetter__(c);
        if (g) {
            _self.message[g()] = c;
        }
    }
}

_setMessage(_self);

module.exports = _self;


});
define('ripple/platform/wac/2.0/contactfilter', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    _self;

_self = function (criteria) {
    var pattern,
        contactFilter;

    contactFilter = {
        match: function (target) {
            var result = false, key, value, index;

            switch (Object.prototype.toString.call(target)) {
            case "[object String]":
                result = pattern.test(target);
                break;

            case "[object Object]":
                for (key in criteria) {
                    result = true;
                    value = criteria[key];
                    if ((value !== undefined) && (!_self(value).match(target[key])))
                        return false;
                }
                break;

            case "[object Array]":
                for (index in target) {
                    if (contactFilter.match(target[index]))
                        return true;
                }
                break;
            }

            return result;
        }
    };

    if (typeof criteria === "string")
        pattern = new RegExp(criteria.replace(/(^|[^\\])%+/g, "$1.*").replace(/\\%/g, "%").replace(/.*/, "^$&$"), "i");

    return contactFilter;
};

module.exports = _self;

});
define('ripple/platform/wac/2.0/filesystem', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/wac/2.0/errorcode'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    utils = require('ripple/utils'),
    dbfs  = require('ripple/platform/wac/2.0/dbfs'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    _console = require('ripple/console'),
    _maxPathLength = 256,
    _virtualRoots = ["documents", "images", "music", "videos", "downloads", "wgt-package", "wgt-private", "wgt-private-tmp", "removable", "attachments"],
    _realRoots = dbfs.roots,
    _r2vmap = {},
    _v2rmap = {},
    _initialized = false,
    _readOnly  = false,
    _writeOnly = false,
    _defaultMode = "rw",
    File, 
    FileStream;

function _isValidChar(c) {
    return  (c >= '0' && c <= '9') || 
        (c >= 'a' && c <= 'z') || 
        (c >= 'A' && c <= 'Z') || 
        (c === ' ') || 
        (c === '_') ||
        (c === '-') ||
        (c === '.');
}

function _isValidFileName(name) {
    var _valid = true,
        _c;

    if (name === '' || name === '.' || name === '..' || (name.length > _maxPathLength)) {
        _valid = false;
    } else {
        for (_c = 0; _c < name.length; _c++) {
            if (!_isValidChar(name[_c])) {
                _valid = false;
                break;
            }
        }
    }
    
    return _valid;
}

function _initialize() {
    var _i;

    dbfs.initialize();
    
    // set up the map between real path and virtual path
    for (_i = 0; _i < _virtualRoots.length; _i++) {
        _r2vmap[_realRoots[_i]] = _virtualRoots[_i];
    }

    utils.forEach(_r2vmap, function (value, key) {
        _v2rmap[value] = key;
    });
}

function _resolveSync(srcLocation, onSuccess, onError, accessMode) {
    var _parts = srcLocation.replace(/\/$/, '').split("/"),
        _header, _fullPath,
        _i;

    // TODO: Initialize at bootstrap and emulatorBridge.link 
    if (!_initialized) {
        _initialize();
        _initialized = true;
    }

    for (_i = 0; _i < _parts.length; _i++) {
        if (!_isValidFileName(_parts[_i])) {
            if (onError) {
                onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
            }
            return;
        }
    }

    _header = _v2rmap[_parts[0]];
    if (_header === undefined) {
        if (onError) {
            onError(new DeviceApiError(errorcode.NOT_FOUND_ERR));
        }
        return;
    }

    if (_parts.length === 1) {
        _fullPath = _header;
    } else {
        _fullPath = _header + "/" + _parts.splice(1, _parts.length - 1).join("/");
    }

    dbfs.stat(_fullPath, 
            function (entry) {
                onSuccess(new File(entry, accessMode));
            }, 
            function () {
                if (onError) {
                    onError(new DeviceApiError(errorcode.NOT_FOUND_ERR));
                }    
            });
}

function _resolveAsync(onSuccess, onError, srcLocation, accessMode) {
    _resolveSync(srcLocation,
                function (file) {
                    setTimeout(function () {
                        onSuccess(file);
                    }, 1);
                },
                function (e) {
                    setTimeout(function () {
                        onError(e);
                    }, 1);
                },
                accessMode);
}

File = function (entry, mode) {
    var _entry = entry,
        _mode = mode,
        _parent,
        _self;

    function _r2v(rpath) {
        var i, v, r, regExp;

        for (i = 0; i < _virtualRoots.length; i++) {
            v = _virtualRoots[i];
            r = _v2rmap[v];
            if (rpath.match("^" + r)) {
                regExp = new RegExp("^" + r);
                return rpath.replace(regExp, v);
            }
        }

        return ""; 
    }

    function _v2r(vpath) {
        var i, v, r, regExp;

        for (i = 0; i < _virtualRoots.length; i++) {
            v = _virtualRoots[i];
            r = _v2rmap[v];
            if (vpath.match("^" + v)) {
                regExp = new RegExp("^" + v);
                return vpath.replace(regExp, r);
            }
        }

        return ""; 
    }

    function _copyMoveInternal(onSuccess, onError, src, dst, overwrite, func) {
        var _srcName = String(src),
            _dstName = String(dst),
            _src = null,
            _dst = null,
            _error = false,
            _dstParent = null,
            _dstParts  = _dstName.split("/"),
            _dstParentName = _dstParts.splice(0, _dstParts.length - 1).join("/");

        if (!_entry.isDirectory) {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.IO_ERR));
                }, 1);
            }
            return undefined;
        }

        _resolveSync(_srcName, 
                function (file) {
                    _src = file;
                },
                function (e) {
                    setTimeout(function () {
                        onError(e);
                    }, 1);
                },
                _mode);

        if (_src) {
            if (_src.parent.fullPath === _self.fullPath) {
                if (!_readOnly && _mode !== "r") {
                    _resolveSync(_dstParentName, 
                            function (file) {
                                _dstParent = file;
                            },
                            function (e) {
                                setTimeout(function () {
                                    onError(e);
                                }, 1);
                            },
                            _mode);

                    if (_dstParent === null) {
                        return undefined;
                    }

                    _resolveSync(_dstName, 
                            function (file) {
                                _dst = file;
                            },
                            function (e) {
                                if (e.code !== errorcode.NOT_FOUND_ERR) {
                                    setTimeout(function () {
                                        onError(e);
                                    }, 1);
                                    _error = true;
                                } 
                            },
                            _mode);

                    if (_error) {
                        return undefined;
                    }

                    if (_src.isFile) {
                        if (_dst === null) {
                            func(_v2r(_srcName), _v2r(_dstName),
                                    function () {
                                        setTimeout(function () {
                                            onSuccess();
                                        }, 1);
                                    },
                                    function () {});
                            return null;
                        } else {
                            if (_dst.isFile && Boolean(overwrite) && (_srcName !== _dstName)) {
                                func(_v2r(_srcName), _v2r(_dstName),
                                        function () {
                                            setTimeout(function () {
                                                onSuccess();
                                            }, 1);
                                        },
                                        function () {});
                                return null;
                            } else {
                                setTimeout(function () {
                                    onError(new DeviceApiError(errorcode.IO_ERR));
                                }, 1);
                            }
                        }
                    } else {
                        if (_dst === null) {
                            func(_v2r(_srcName), _v2r(_dstName),
                                function () {
                                    setTimeout(function () {
                                        onSuccess();
                                    }, 1);
                                },
                                function () {});
                            return null;
                        } else {
                            setTimeout(function () {
                                onError(new DeviceApiError(errorcode.IO_ERR));
                            }, 1);
                        } 
                    }
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                }
            } else {
                if (onError) {
                    setTimeout(function () {
                        onError(new DeviceApiError(errorcode.IO_ERR));
                    }, 1);
                }
            }
        }

        return undefined;
    }

    _self = {
        toURI: function () {
            return "file://" + _entry.fullPath;
        },
        listFiles: function (onSuccess, onError, filter) {
            var _filter = Object(filter),
                _filterName = _filter.name,
                _startModified = _filter.startModified,
                _endModified   = _filter.endModified;

            function _matchName(fileName) {
                var _matched = true, 
                    _name1 = String(_filterName).toLowerCase(),
                    _name2 = fileName.toLowerCase(),
                    _pattern;

                if (_filterName !== undefined && _filterName !== null) {
                    if (!_name1.match("\\\\%")) {
                        if (_name1.match("%")) {
                            _pattern = new RegExp("^" + _name1.replace(/%/g, ".*") + "$");
                            _matched = _name2.match(_pattern) ? true : false;
                        } else {
                            _matched = (_name1 === _name2);
                        }
                    } else {
                        // % is not allowed as a part of file name
                        _matched = false;
                    }
                }
                
                return _matched;
            }

            function _matchDate(date) {
                var _matched = true;

                if (_startModified !== undefined && _startModified !== null) {
                    _matched = (date.getTime() >= _startModified.getTime());
                }

                if (_matched && (_endModified !== undefined && _endModified !== null)) {
                    _matched = (date.getTime() <= _endModified.getTime());
                }

                return _matched;
            }

            function _matchFilter(entry) {
                return _matchName(entry.name) && _matchDate(entry.lastModifiedDate);
            } 

            function _listFiles() {
                var _files = [];

                if ((_startModified !== undefined && !wac2_utils.isValidDate(_startModified)) ||
                    (_endModified !== undefined && !wac2_utils.isValidDate(_endModified))) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (!_entry.isDirectory) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.IO_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                utils.forEach(_entry.children, function (child) {
                    if (_matchFilter(child)) {
                        _files.push(new File(child, _mode));
                    }
                });

                setTimeout(function () {
                    onSuccess(_files);
                }, 1);

                return null;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "listFiles", _listFiles);
        },
        openStream: function (onSuccess, onError, mode, encoding) {
            function _openStream() {
                var  _openMode = String(mode),
                    _encoding = encoding ? String(encoding) : "UTF-8";

                if (_openMode !== "r" && _openMode !== "w" && _openMode !== "a") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                if (_encoding !== "UTF-8" && _encoding !== "ISO-8859-1") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                
                if (((_readOnly || _mode === "r") && (_openMode === "w" || _openMode === "a")) ||
                    (_writeOnly && _openMode === "r")) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                 
                setTimeout(function () {
                    onSuccess(new FileStream(_entry, _openMode, _encoding));
                }, 1);

                return null;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "openStream", _openStream);
        },
        readAsText: function (onSuccess, onError, encoding) {
            function _readAsText() {
                var _encoding = encoding ? String(encoding) : "UTF-8";
                if (_encoding !== "UTF-8" && _encoding !== "ISO-8859-1") {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (_writeOnly) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (_self.isFile) {
                    dbfs.read(_entry.fullPath, 
                            function (data) {
                                setTimeout(function () {
                                    onSuccess(data);
                                }, 1);
                            },
                            function () {});
                    return null;
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.IO_ERR));
                        }, 1);
                    }
                }

                return undefined;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "readAsText", _readAsText);
        },
        copyTo: function (onSuccess, onError, src, dst, overwrite) {
            function _copyTo() {
                return _copyMoveInternal(onSuccess, onError, src, dst, overwrite, dbfs.cp);
            }
            
            return wac2_utils.validateTypeMismatch(onSuccess, onError, "copyTo", _copyTo);
        },
        moveTo: function (onSuccess, onError, src, dst, overwrite) {
            function _moveTo() {
                return _copyMoveInternal(onSuccess, onError, src, dst, overwrite, dbfs.mv);
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "moveTo", _moveTo);
        },
        createDirectory: function (dirPath) {
            var _path  = String(dirPath),
                _parts = _path.replace(/\/$/, "").split("/"),
                _dir   = null,
                _exist = null,
                _current = _entry.fullPath,
                _i;

            function onSuccess(entry) {
                _dir = entry;
            }

            for (_i = 0; _i < _parts.length; _i++) {
                if (!_isValidFileName(_parts[_i])) {
                    throw new DeviceApiError(errorcode.INVALID_VALUES_ERR);
                }
            }
      
            if (!entry.isDirectory) {
                throw new DeviceApiError(errorcode.IO_ERR);
            }

            _exist = _parts.reduce(function (obj, token) {
                return token === "" ? obj : (obj.children ? obj.children[token] || null : null);
            }, _entry);

            if (_exist) {
                throw new DeviceApiError(errorcode.IO_ERR);
            }

            if (_readOnly || _mode === "r") {
                throw new DeviceApiError(errorcode.SECURITY_ERR);
            }

            for (_i = 0; _i < _parts.length; _i++) {
                _current = _current + "/" + _parts[_i];
                dbfs.mkdir(_current, onSuccess);
            }
            
            return new File(_dir, _mode);
        },
        createFile: function (filePath) {
            var _name = String(filePath),
                _file = null;

            if (!_isValidFileName(_name)) {
                throw new DeviceApiError(errorcode.INVALID_VALUES_ERR);
            }

            if (!entry.isDirectory || (_entry.children && _entry.children[_name])) {
                throw new DeviceApiError(errorcode.IO_ERR);
            }

            if (_readOnly || _mode === "r") {
                throw new DeviceApiError(errorcode.SECURITY_ERR);
            }

            dbfs.touch(_entry.fullPath + "/" + _name,
                        function (entry) {
                            _file = new File(entry, _mode);
                        },
                        function () {});
            
            return _file;
        },
        resolve: function (filePath) {
            var _fullPath = _self.fullPath + "/" + String(filePath),
                _file = null;
 
            if (!_entry.isDirectory) {
                throw new DeviceApiError(errorcode.IO_ERR); 
            }

            _resolveSync(_fullPath,
                    function (file) {
                        _file = file;
                    },
                    function (e) {
                        throw (e);
                    },
                    _mode);

            return _file;
        }, 
        deleteDirectory: function (onSuccess, onError, directory, recursive) {
            function _deleteDirectory() {
                var _dir = null,
                    _dirName = String(directory);
                _resolveSync(_dirName, 
                        function (file) {
                            _dir = file;
                        },
                        function (e) {
                            setTimeout(function () {
                                onError(e);
                            }, 1);
                        },
                        _mode);

                if (_dir) {
                    if (_dir.isDirectory && 
                        _dir.parent.fullPath === _self.fullPath &&
                        (!recursive && _dir.length === 0)) {
                        if (!_readOnly && _mode !== "r") {
                            dbfs.rmdir(_v2r(_dirName),
                                    function () {
                                        setTimeout(function () {
                                            onSuccess();
                                        }, 1);
                                    },
                                    function () {});
                            return null;
                        } else {
                            if (onError) {
                                setTimeout(function () {
                                    onError(new DeviceApiError(errorcode.SECURITY_ERR));
                                }, 1);
                            }
                        }
                    } else {
                        if (onError) {
                            setTimeout(function () {
                                onError(new DeviceApiError(errorcode.IO_ERR));
                            }, 1);
                        }
                    }
                }

                return undefined; 
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "deleteDirectory", _deleteDirectory);
        },
        deleteFile: function (onSuccess, onError, fileName) {
            function _deleteFile() {
                var _file = null;
                _resolveSync(String(fileName),
                        function (file) {
                            _file = file;
                        },
                        function (e) {
                            if (onError) {
                                setTimeout(function () {
                                    onError(e);
                                }, 1);
                            }
                        },
                        _mode);

                if (_file) {
                    if (_file.isFile && _file.parent.fullPath === _self.fullPath) {
                        if (!_readOnly && _mode !== "r") {
                            dbfs.rm(_v2r(fileName),
                                    function () {
                                        setTimeout(function () {
                                            onSuccess();
                                        }, 1);
                                    },
                                    function () {});
                            return null;
                        } else {
                            if (onError) {
                                setTimeout(function () {
                                    onError(new DeviceApiError(errorcode.SECURITY_ERR));
                                }, 1);
                            }
                        }
                    } else {
                        if (onError) {
                            setTimeout(function () {
                                onError(new DeviceApiError(errorcode.IO_ERR));
                            }, 1);
                        }
                    }
                }

                return undefined; 
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "deleteFile", _deleteFile);
        }
    };

    _self.__defineGetter__("parent", function () {
        var _parts = _self.fullPath.split("/");

        if (_parent === undefined) {
            if (_parts.length === 1) {
                // virtual root's parent is null
                _parent = null;
            } else {
                _resolveSync(_parts.splice(0, _parts.length - 1).join("/"), 
                        function (file) {
                            _parent = file;
                        },
                        function () {},
                        _mode);
            }
            return _parent;
        } else { 
            return _parent;
        }
    });

    _self.__defineGetter__("readOnly", function () {
        return false;
    });

    _self.__defineGetter__("isFile", function () {
        return !_entry.isDirectory;
    });

    _self.__defineGetter__("isDirectory", function () {
        return _entry.isDirectory;
    });

    _self.__defineGetter__("created", function () {
        return undefined;
    });

    _self.__defineGetter__("modified", function () {
        if (_entry.isDirectory) {
            return undefined;
        } else {
            return _entry.lastModifiedDate;
        }
    });

    _self.__defineGetter__("path", function () {
        var _parts = _self.fullPath.split("/");

        if (_parts.length === 1) {
            // virtual root
            return _parts.join("");
        } else {
            return _parts.splice(0, _parts.length - 1).join("/") + "/";
        }
    });

    _self.__defineGetter__("name", function () {
        return _entry.name;
    });

    _self.__defineGetter__("fullPath", function () {
        return _r2v(_entry.fullPath);
    });

    _self.__defineGetter__("fileSize", function () {
        if (_entry.isDirectory) {
            return undefined;
        } else {
            return _entry.data.length;
        }
    });

    _self.__defineGetter__("length", function () {
        var _l = 0;
        if (_entry.isDirectory) {
            utils.forEach(_entry.children, function () {
                _l++;
            });
            return _l;
        } else {
            return undefined;
        }
    });

    return _self;
};

FileStream = function (entry, mode, encoding) {
    var _entry = entry,
        _data = entry.data,
        _mode = mode,
        _position = (_mode === "a" ? _data.length : 0),
        _self;

    _self = {
        close: function () {
            var _element;
            if (mode === "a" || mode === "w") {
                dbfs.write(_entry.fullPath, _data, function () {}, function () {});
            }
            for (_element in _self) {
                delete _self[_element];
            }
        },
        read: function (charCount) {
            var _count  = charCount | 0,
                _substr = _data.substring(_position, _position + _count);

            if (_position + _count > _data.length) {
                _position = _data.length;
            } else {
                _position += _count;
            }

            return _substr; 
        },
        readBytes: function (byteCount) {
            var _substr = _self.read(byteCount),
                _bytes = [],
                _i;

            for (_i = 0; _i < _substr.length; _i++) {
                _bytes.push(_substr.charCodeAt(_i));
            }

            return _bytes;
        },
        readBase64: function (byteCount) {
            var _substr = _self.read(byteCount);

            return window.atob(_substr);
        },
        write: function (stringData) {
            var _stringData = String(stringData),
                _substr = _data.substring(0, _position);

            _data = _substr.concat(_stringData);
            _position = _data.length;
        },
        writeBytes: function (byteData) {
            _self.write(String.fromCharCode.apply(String, byteData));
        },
        writeBase64: function (base64Data) {
            _self.write(window.btoa(String(base64Data)));
        }
    };

    _self.__defineGetter__("eof", function () {
        return _position === _data.length;
    });

    _self.__defineGetter__("position", function () {
        return _position;
    });

    _self.__defineSetter__("position", function (value) {
        var _value = value | 0;

        if (_value >= 0 && _value <= _data.length) {
            _position = _value;
        } else {
            throw new DeviceApiError(errorcode.INVALID_VALUES_ERR);
        }
    });

    _self.__defineGetter__("bytesAvailable", function () {
        return (_data.length - _position) || -1;
    });

    return _self;
};

module.exports = function () {
    return {
        maxPathLength: _maxPathLength,
        resolve: function (onSuccess, onError, srcLocation, accessMode) {
            function _resolve() {
                var _mode = accessMode ? String(accessMode) : _defaultMode;

                if (_mode === "r" || _mode === "rw") {
                    _resolveAsync(onSuccess, onError, String(srcLocation), _mode);
                    return null;
                } else {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                }
                return undefined;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "resolve", _resolve);
        },
        handleSubFeatures: function (subFeatures) {
            if (wac2_utils.isEmptyObject(subFeatures) ||
                subFeatures["http://wacapps.net/api/filesystem"] ||
                (subFeatures["http://wacapps.net/api/filesystem.read"] &&
                subFeatures["http://wacapps.net/api/filesystem.write"])) {
                return;
            }
            if (subFeatures["http://wacapps.net/api/filesystem.read"]) {
                _readOnly = true;
                return;
            }
            if (subFeatures["http://wacapps.net/api/filesystem.write"]) {
                _writeOnly = true;
                return;
            }
            _console.warn("WAC-2.0-Filesystem: something wrong in handleSubFeatures");
        }
    }; 
};


});
define('ripple/platform/wac/2.0/deviceapierror', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var errorcode = require('ripple/platform/wac/2.0/errorcode');

module.exports = function (code) {
    for (var c in errorcode) {
        var g = errorcode.__lookupGetter__(c);
        if (g) {
            this.__defineGetter__(c, g);
        }
    }

    this.code = code;
    this.message = errorcode.message[code];
    this.type =  "";

    this.toString = function () {
        var result = this.type + ': "' + this.message + '"';

        if (this.stack) {
            result += "\n" + this.stack;
        }
        return result;
    };
};


});
define('ripple/platform/wac/2.0/messagefilter', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _self;

_self = function (criteria) {
    var pattern,
        messageFilter;

    messageFilter = {
        match: function (target) {
            var result = false, index;

            if (Object.prototype.toString.call(criteria) === "[object Array]") {
                for (index in criteria) {
                    if (_self(criteria[index]).match(target))
                        return true;
                }
                return false;
            }

            switch (Object.prototype.toString.call(target)) {
            case "[object Number]":
                result = (criteria === target);
                break;

            case "[object String]":
                result = pattern.test(target);
                break;

            case "[object Array]":
                for (index in target) {
                    if (messageFilter.match(target[index]))
                        return true;
                }
                break;
            }

            return result;
        }
    };

    if (typeof criteria === "string")
        pattern = new RegExp(criteria.replace(/(^|[^\\])%+/g, "$1.*").replace(/\\%/g, "%").replace(/.*/, "^$&$"), "i");

    return messageFilter;
};

module.exports = _self;

});
define('ripple/platform/wac/2.0/contact', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    db = require('ripple/db'),
    constants = require('ripple/constants'),
    exception = require('ripple/exception'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    TypeCoerce = require('ripple/platform/wac/2.0/typecoerce'),
    Filter = require('ripple/platform/wac/2.0/contactfilter'),
    AddressBook,
    ContactProperties,
    Contact,
    Address,
    ContactAddress,
    PhoneNumber,
    EmailAddress,
    ContactFilter,
    _KEY = "wac2-pim-contact",
    _PENDING_TIME = 600,
    _addressBooks = [],
    _contacts = {},
    _security = {
        "http://wacapps.net/api/pim.contact": [],
        "http://wacapps.net/api/pim.contact.read": ["findContacts"],
        "http://wacapps.net/api/pim.contact.write": ["addContact", "updateContact", "deleteContact"],
        all: true
    },
    _self;

function _errorOccurred(onError, code) {
    if (!onError)
        return;

    setTimeout(function () {
        onError(new DeviceApiError(code));
    }, 1);
}

function _pendingOperate(operate, scope) {
    var i, argumentVector = [];

    for (i = 0; i < arguments.length - 2; i++)
        argumentVector[i] = arguments[i + 2];

    return function () {
        var pendingObj, pendingOperation;

        pendingObj = new PendingObject();
        pendingObj.pendingID = window.setTimeout(function () {
            pendingObj.setCancelFlag(false);
            operate.apply(scope, argumentVector);
        }, _PENDING_TIME);

        pendingOperation = new PendingOperation(pendingObj);

        return pendingOperation;
    };
}

function _defaultContacts() {
    var id1 = Math.uuid(null, 16),
        id2 = Math.uuid(null, 16),
        id3 = Math.uuid(null, 16),
        id4 = Math.uuid(null, 16),
        contacts = {};

    contacts.PHONE_ADDRESS_BOOK = {
        type: _self().PHONE_ADDRESS_BOOK,
        items: [{
            id: id1,
            firstName: "Leonardo",
            lastName: "Gates",
            nicknames: ["Leo"],
            phoneticName: "",
            addresses: [{streetAddress: "Gran Via, 32", postalCode: "50013", city: "Zaragoza", country: "ES"}],
            photoURI: "",
            phoneNumbers: [],
            emails: ["leo@underground.com"]
        }, {
            id: id2,
            firstName: "Jordan",
            lastName: "",
            nicknames: [""],
            phoneticName: "",
            addresses: [],
            photoURI: "",
            phoneNumbers: [],
            emails: ["jordan@underground.com"]
        }]
    };

    contacts.SIM_ADDRESS_BOOK = {
        type: _self().SIM_ADDRESS_BOOK,
        items: [{
            id: id3,
            firstName: "Raphael",
            lastName: "",
            nicknames: [""],
            phoneticName: "",
            addresses: [],
            photoURI: "",
            phoneNumbers: [],
            emails: ["raph@underground.com"]
        }]
    };

    contacts.DEVICE_ADDRESS_BOOK = {
        type: _self().DEVICE_ADDRESS_BOOK,
        items: [{
            id: id4,
            firstName: "Michelangelo",
            lastName: "",
            nicknames: [""],
            phoneticName: "",
            addresses: [],
            photoURI: "",
            phoneNumbers: [],
            emails: ["mike@underground.com"]
        }]
    };

    return contacts;
}

function _get() {
    _contacts = db.retrieveObject(_KEY) || _defaultContacts();
}

function _save() {
    db.saveObject(_KEY, _contacts);
}

function _initAddressBooks() {
    _get();
    utils.forEach(_contacts, function (contactObj, name) {
        _addressBooks.push(new AddressBook(contactObj.type, name));
    });
}

_self = function () {
    var contact = {
        getAddressBooks: function (successCallback, errorCallback) {
            function _getAddressBooks() {
                if (_addressBooks.length === 0) {
                    _initAddressBooks();
                }
                successCallback(_addressBooks);
            }
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "getAddressBooks", _getAddressBooks);
        },

        handleSubFeatures: function (subFeatures) {
            for (var subFeature in subFeatures) {
                if (_security[subFeature].length === 0) {
                    _security.all = true;
                    return;
                }
                _security.all = false;
                utils.forEach(_security[subFeature], function (method) {
                    _security[method] = true;
                });
            }
        }
    };

    contact.__defineGetter__("SIM_ADDRESS_BOOK", function () {
        return 0x0000;
    });

    contact.__defineGetter__("DEVICE_ADDRESS_BOOK", function () {
        return 0x000F;
    });

    contact.__defineGetter__("PHONE_ADDRESS_BOOK", function () {
        return 0x00FF;
    });

    return contact;
};

AddressBook = function (type, name) {
    var addressBook,
        contactItems = _contacts[name].items;

    addressBook = {
        createContact: function (contactProperties) {
            var cp, contact = new Contact();

            if ((contactProperties !== undefined) &&
                (contactProperties !== null)) {
                cp = TypeCoerce(ContactProperties).cast(contactProperties);
                !cp.firstName    || (contact.firstName    = utils.copy(cp.firstName));
                !cp.lastName     || (contact.lastName     = utils.copy(cp.lastName));
                !cp.nicknames    || (contact.nicknames    = utils.copy(cp.nicknames));
                !cp.phoneticName || (contact.phoneticName = utils.copy(cp.phoneticName));
                !cp.addresses    || (contact.addresses    = utils.copy(cp.addresses));
                !cp.photoURI     || (contact.photoURI     = utils.copy(cp.photoURI));
                !cp.phoneNumbers || (contact.phoneNumbers = utils.copy(cp.phoneNumbers));
                !cp.emails       || (contact.emails       = utils.copy(cp.emails));
            }

            return contact;
        },

        addContact: function (successCallback, errorCallback, contact) {
            function _addContact() {
                var c;

                if (!contact)
                    exception.raise(exception.types.Argument, "addContact invalid message parameter", new DeviceApiError(errorcode.INVALID_VALUES_ERR));

                if (!_security.all && !_security.addContact)
                    return _errorOccurred(errorCallback, errorcode.SECURITY_ERR);

                c = TypeCoerce(new Contact()).cast(contact);
                contactItems.push(c);
                _save();
                successCallback(c);
            }
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "addContact", _pendingOperate(_addContact));
        },

        updateContact: function (successCallback, errorCallback, contact) {
            function _updateContact() {
                var c, isFound = false;

                if (!contact)
                    exception.raise(exception.types.Argument, "updateContact invalid message parameter", new DeviceApiError(errorcode.INVALID_VALUES_ERR));

                if (!_security.all && !_security.updateContact)
                    return _errorOccurred(errorCallback, errorcode.SECURITY_ERR);

                c = TypeCoerce(new Contact()).cast(contact);
                utils.forEach(contactItems, function (contactItem) {
                    if (contactItem.id === c.id) {
                        !c.firstName    || (contactItem.firstName    = utils.copy(c.firstName));
                        !c.lastName     || (contactItem.lastName     = utils.copy(c.lastName));
                        !c.nicknames    || (contactItem.nicknames    = utils.copy(c.nicknames));
                        !c.phoneticName || (contactItem.phoneticName = utils.copy(c.phoneticName));
                        !c.addresses    || (contactItem.addresses    = utils.copy(c.addresses));
                        !c.photoURI     || (contactItem.photoURI     = utils.copy(c.photoURI));
                        !c.phoneNumbers || (contactItem.phoneNumbers = utils.copy(c.phoneNumbers));
                        !c.emails       || (contactItem.emails       = utils.copy(c.emails));

                        _save();
                        isFound = true;
                        successCallback();
                    }
                });

                if (!isFound)
                    _errorOccurred(errorCallback, errorcode.NOT_FOUND_ERR);
            }
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "updateContact", _pendingOperate(_updateContact));
        },

        deleteContact: function (successCallback, errorCallback, id) {
            function _deleteContact() {
                var isFound = false;

                if (!_security.all && !_security.deleteContact)
                    return _errorOccurred(errorCallback, errorcode.SECURITY_ERR);

                utils.forEach(contactItems, function (contactItem, index) {
                    if (contactItem.id === id) {
                        contactItems.splice(index, 1);
                        _save();
                        isFound = true;
                        successCallback();
                    }
                });

                if (!isFound)
                    _errorOccurred(errorCallback, errorcode.NOT_FOUND_ERR);
            }
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "deleteContact", _pendingOperate(_deleteContact));
        },

        findContacts: function (successCallback, errorCallback, filter) {
            function _findContacts() {
                var contact, result = [];

                if (!_security.all && !_security.findContacts)
                    return _errorOccurred(errorCallback, errorcode.SECURITY_ERR);

                utils.forEach(contactItems, function (contactItem) {
                    if ((filter              === undefined || filter === null) ||
                        (filter.id           === undefined || Filter(filter.id).match(contactItem.id)) &&
                        (filter.firstName    === undefined || Filter(filter.firstName).match(contactItem.firstName)) &&
                        (filter.lastName     === undefined || Filter(filter.lastName).match(contactItem.lastName)) &&
                        (filter.phoneticName === undefined || Filter(filter.phoneticName).match(contactItem.phoneticName)) &&
                        (filter.nickname     === undefined || Filter(filter.nickname).match(contactItem.nicknames)) &&
                        (filter.phoneNumber  === undefined || Filter(filter.phoneNumber).match(contactItem.phoneNumbers)) &&
                        (filter.email        === undefined || Filter(filter.email).match(contactItem.emails)) &&
                        (filter.address      === undefined || Filter(filter.address).match(contactItem.addresses))) {
                        contact = new Contact(contactItem.id);

                        contact.firstName    = utils.copy(contactItem.firstName);
                        contact.lastName     = utils.copy(contactItem.lastName);
                        contact.nicknames    = utils.copy(contactItem.nicknames);
                        contact.phoneticName = utils.copy(contactItem.phoneticName);
                        contact.addresses    = utils.copy(contactItem.addresses);
                        contact.photoURI     = utils.copy(contactItem.photoURI);
                        contact.phoneNumbers = utils.copy(contactItem.phoneNumbers);
                        contact.emails       = utils.copy(contactItem.emails);

                        result.push(contact);
                    }
                });
                successCallback(result);
            }
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "findContacts", _pendingOperate(_findContacts));
        }
    };

    addressBook.__defineGetter__("type", function () {
        return type;
    });

    addressBook.__defineGetter__("name", function () {
        return name;
    });

    return addressBook;
};

Address = {
    country: "",
    region: "",
    county: "",
    city: "",
    streetAddress: "",
    additionalInformation: "",
    postalCode: ""
};

ContactAddress = function () {
    this.types = [""]; // "WORK", "PREF", "HOME"
};

ContactAddress.prototype = Address;

PhoneNumber = {
    number: "",
    types: [""] // "WORK", "PREF", "HOME", "VOICE", "FAX", "MSG", "CELL",
                // "PAGER", "BBS", "MODEM", "CAR", "ISDN", "VIDEO", "PCS"
};

EmailAddress = {
    email: "",
    types: [""] // "WORK", "PREF", "HOME"
};

ContactProperties = {
    firstName: "",
    lastName: "",
    nicknames: [""],
    phoneticName: "",
    addresses: [new ContactAddress()],
    photoURI: "",
    phoneNumbers: [PhoneNumber],
    emails: [EmailAddress]
};

Contact = function (id) {
    id = id || Math.uuid(null, 16);

    this.__defineGetter__("id", function () {
        return id;
    });
};

Contact.prototype = ContactProperties;

ContactFilter = {
    id: "",
    firstName: "",
    lastName: "",
    phoneticName: "",
    nickname: "",
    phoneNumber: "",
    email: "",
    address: ""
};

module.exports = _self;

});
define('ripple/platform/wac/2.0/typecoerce', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    _self;

_self = function (pattern) {
    var typeCoerce,
        typeOfPattern = Object.prototype.toString.call(pattern);

    typeCoerce = {
        cast: function (obj) {
            var validObj,
                validValue,
                elementType,
                typeOfObj = Object.prototype.toString.call(obj);

            switch (typeOfPattern) {
            case "[object String]":
                validObj = (typeOfObj !== typeOfPattern) ? String(obj) : obj;
                break;

            case "[object Number]":
                validObj = (typeOfObj !== typeOfPattern) ? (Number(obj) | 0) : obj;
                break;

            case "[object Object]":
                if (typeOfObj !== typeOfPattern) {
                    validObj = {};
                } else {
                    validObj = obj;
                    utils.forEach(validObj, function (value, key) {
                        if (pattern[key] === undefined) {
                            delete validObj[key];
                        } else {
                            validValue = _self(pattern[key]).cast(value);
                            if (validObj[key] !== validValue)
                                validObj[key] = validValue;
                        }
                    });
                }
                break;

            case "[object Array]":
                if (typeOfObj !== typeOfPattern) {
                    validObj = [];
                } else {
                    validObj = obj;
                    elementType = _self(pattern[0]);
                    utils.forEach(validObj, function (element, index) {
                        validObj[index] = elementType.cast(element);
                    });
                }
                break;
            }

            return validObj;
        }
    };

    return typeCoerce;
};

module.exports = _self;

});
define('ripple/platform/wac/2.0/camera', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    _console = require('ripple/console'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils');

module.exports = function () {
    var _cameraArray, Camera, _videoStatus = {},
        _captureImage, _startVideoCapture,
        _doCaptureImage, _doStartVideoCapture,
        _doGetPreview, _doGetCameras,
        _stopVideoCapture, _createPreviewNode,
        _FAKEWAITTIME = 5,
        _defaultHighRes = true,
        _defaultImageFilename = "_capture.jpg",
        _defaultVideoFilename = "_capture.avi",
        _captureImageAllowed = true,
        _startVideoCaptureAllowed = true,
        _stopVideoCaptureAllowed = true,
        _createPreviewNodeAllowed = true;

    _doCaptureImage = function (onSuccess, onError, capFilename, capHighRes, pendingObj) {
        pendingObj.pendingID = setTimeout(function () {
            var dname = "", fname = "";
            //pretend to do sth.
            pendingObj.setCancelFlag(false);  // too late to cancel
            if (capFilename.indexOf("/") !== -1) {
                dname = capFilename.replace(/(.*\/)[^\/]+$/i, "$1");
                fname = capFilename.replace(/.*\/([^\/]*)$/i, "$1");
                //replace extension with jpg
                fname = fname.replace(/\.[^\/\.]+$/i, ".jpg");
            } else {
                dname = "";
                fname = capFilename.replace(/\.[^\/\.]+$/i, ".jpg");
            }
            if (fname === "") {
                fname = _defaultImageFilename;
            }
            if (fname.search(/\.jpg$/) === -1) {
                fname = fname + ".jpg";
            }
            if (capHighRes) {
                onSuccess(dname + "high-" + fname);
            } else {
                onSuccess(dname + "low-" + fname);
            }
        }, _FAKEWAITTIME);
    };

    _captureImage = function (onSuccess, onError, options) {
        var pendingOperation = {}, pendingObj,
            filename = this.id + _defaultImageFilename,
            highRes = _defaultHighRes, opt;

        if (onSuccess) {
            utils.validateArgumentType(onSuccess, "function", null, "captureImage: invalid successCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (onError) {
            utils.validateArgumentType(onError, "function", null, "captureImage: invalid errorCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (options) {
            opt = new Object(options);
            /* NOTE: if desktinationFilename or highRes is not provided by
               user, i.e. undefined or null, a default value is used.
             */
            if (opt.destinationFilename !== null && opt.destinationFilename !== undefined) {
            // TODO: validate filename via Filesystem.resolve()
                filename = String(opt.destinationFilename);
            }
            if (opt.highRes !== null && opt.highRes !== undefined) {
                highRes = Boolean(opt.highRes);
            }
        }
        if (!_captureImageAllowed) {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.SECURITY_ERR));
                }, 1);
            }
            return undefined;
        }

        if (onSuccess) {
            pendingObj = new PendingObject();
            _doCaptureImage(onSuccess, onError, filename, highRes, pendingObj);
            pendingOperation = new PendingOperation(pendingObj);
            return pendingOperation;
        } else {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                }, 1);
            }
        }
        return undefined;
    };

    _stopVideoCapture = function () {
        var dname = "", fname = "", capFilename = _videoStatus[this.id].capFilename;
        if (_videoStatus[this.id]) {
            if (capFilename.indexOf("/") !== -1) {
                dname = capFilename.replace(/(.*\/)[^\/]+$/i, "$1");
                fname = capFilename.replace(/.*\/([^\/]*)$/i, "$1");
                //replace extension with avi
                fname = fname.replace(/\.[^\/\.]+$/i, ".avi");
            } else {
                dname = "";
                fname = capFilename.replace(/\.[^\/\.]+$/i, ".avi");
            }
            if (fname === "") {
                fname = _defaultVideoFilename;
            }
            if (fname.search(/\.avi$/) === -1) {
                fname = fname + ".avi";
            }
            if (_videoStatus[this.id].capHighRes) {
                _videoStatus[this.id].capSuccess(dname + "high-" + fname);
            } else {
                _videoStatus[this.id].capSuccess(dname + "low-" + fname);
            }
            delete _videoStatus[this.id];
        }
    };

    _doStartVideoCapture = function (camID, onSuccess, onError, filename, highRes, pendingObj) {
        var videoStatus = {};
        _videoStatus[camID] = videoStatus;
        pendingObj.userCancel = function () {
            delete _videoStatus[camID];
        };
        pendingObj.getCancelFlag = function () {
            return !!_videoStatus[camID];
        };
        pendingObj.pendingID = setTimeout(function () {
            // waiting to be cancelled
            videoStatus = {
                capSuccess: onSuccess,
                capError: onError,
                capFilename: filename,
                capHighRes: highRes
            };
            _videoStatus[camID] = videoStatus;
        }, _FAKEWAITTIME);
    };

    _startVideoCapture = function (onSuccess, onError, options) {
        var pendingOperation = {}, pendingObj,
            filename = this.id + _defaultVideoFilename,
            highRes = _defaultHighRes, opt;

        if (onSuccess) {
            utils.validateArgumentType(onSuccess, "function", null, "startVideoCapture: invalid successCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (onError) {
            utils.validateArgumentType(onError, "function", null, "startVideoCapture: invalid errorCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (options) {
            opt = new Object(options);
            /* NOTE: if desktinationFilename or highRes is not provided by
               user, i.e. undefined or null, a default value is used.
             */
            if (opt.destinationFilename !== null && opt.destinationFilename !== undefined) {
            // TODO: validate filename via Filesystem.resolve()
                filename = String(opt.destinationFilename);
            }
            if (opt.highRes !== null && opt.highRes !== undefined) {
                highRes = Boolean(opt.highRes);
            }
        }
        if (!_captureImageAllowed) {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.SECURITY_ERR));
                }, 1);
            }
            return undefined;
        }
        if (_videoStatus[this.id]) { 
            // capture already started
            _console.warn("WAC-2.0-startVideoCapture: capture already started");
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.UNKNOWN_ERR));
                }, 1);
            }
            return undefined;
        }

        if (onSuccess) {
            pendingObj = new PendingObject();
            _doStartVideoCapture(this.id, onSuccess, onError, filename, highRes, pendingObj);
            
            pendingOperation = new PendingOperation(pendingObj);
            return pendingOperation;
        } else {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                }, 1);
            }
        }
        return undefined;
    };

    _doGetPreview = function (camID, onSuccess, onError, pendingObj) {
        var container, demoImg, loc, imageSrc;
        container = document.createElement("div");
        container.setAttribute("id", camID + "-wac-2-0-camera-preview-container");
        demoImg = document.createElement("img");
        demoImg.setAttribute("id", camID + "-wac-2-0-camera-demo-image");
        loc = document.location;
        imageSrc = loc.protocol + "//" + loc.hostname + loc.pathname.replace(/index\.html$/, "") + constants.CAMERA.WINDOW_ANIMATION;
        demoImg.setAttribute("src", imageSrc);
        demoImg.setAttribute("width", "100%");
        container.appendChild(demoImg);
        
        pendingObj.pendingID = setTimeout(function () {
            pendingObj.setCancelFlag(false);  // too late to cancel
            onSuccess(container);
        }, _FAKEWAITTIME);
    };

    _createPreviewNode = function (onSuccess, onError) {
        var pendingOperation, pendingObj = {};
        if (onSuccess) {
            utils.validateArgumentType(onSuccess, "function", null, "createPreviewNode: invalid successCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (onError) {
            utils.validateArgumentType(onError, "function", null, "createPreviewNode: invalid errorCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (!_createPreviewNodeAllowed) {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.SECURITY_ERR));
                }, 1);
            }
            return undefined;
        }
        if (onSuccess) {
            pendingObj = new PendingObject();
            _doGetPreview(this.id, onSuccess, onError, pendingObj);
            pendingOperation = new PendingOperation(pendingObj);
            return pendingOperation;
        } else {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                }, 1);
            }
        }
        return undefined;
    };

    Camera = function (cameraID) {
        return {
            id: cameraID,
            captureImage: _captureImage,
            startVideoCapture: _startVideoCapture,
            stopVideoCapture: _stopVideoCapture,
            createPreviewNode: _createPreviewNode
        };
    };

    _cameraArray = [new Camera("rear"), new Camera("front")];

    _doGetCameras = function (onSuccess, onError, pendingObj) {
        pendingObj.pendingID = setTimeout(function () {
            pendingObj.setCancelFlag(false);  // too late to cancel
            if (_cameraArray.length !== 0) {
                onSuccess(utils.copy(_cameraArray));
            } else {
                // no camera
                if (onError) {
                    setTimeout(function () {
                        onError(new DeviceApiError(errorcode.UNKNOWN_ERR));
                    }, 1);
                }
            }
        }, _FAKEWAITTIME);
    };

    this.getCameras = function (onSuccess, onError) {
        var pendingOperation, pendingObj = {};
        if (onSuccess) {
            utils.validateArgumentType(onSuccess, "function", null, "getCameras: invalid successCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (onError) {
            utils.validateArgumentType(onError, "function", null, "getCameras: invalid errorCallback parameter", new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }
        if (onSuccess) {
            pendingObj = new PendingObject();
            _doGetCameras(onSuccess, onError, pendingObj);
            pendingOperation = new PendingOperation(pendingObj);
            return pendingOperation;
        } else {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                }, 1);
            }
        }
        return undefined;
    };

    this.handleSubFeatures = function (subFeatures) {
        if (wac2_utils.isEmptyObject(subFeatures) ||
            subFeatures["http://wacapps.net/api/camera"] ||
            (subFeatures["http://wacapps.net/api/camera.capture"] &&
            subFeatures["http://wacapps.net/api/camera.show"])) {
            return;
        }
        if (subFeatures["http://wacapps.net/api/camera.show"] &&
           !subFeatures["http://wacapps.net/api/camera.capture"]) {
            _captureImageAllowed = false;
            _startVideoCaptureAllowed = false;
            _stopVideoCaptureAllowed = false;
            return;
        }
        if (subFeatures["http://wacapps.net/api/camera.capture"] &&
           !subFeatures["http://wacapps.net/api/camera.show"]) {
            _createPreviewNodeAllowed = false;
            return;
        }
        _console.warn("WAC-2.0-Camera-handleSubFeatures: something wrong");
    };
};

});
define('ripple/platform/wac/2.0/deviceapis', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var platform = require('ripple/platform'),
    app = require('ripple/app'),
    utils = require('ripple/utils'),
    init_done = false,
    _activatedSet = {},
    _activatedFeatures = [],
    _availableSet = {},
    _availableFeatures = [],
    _features = {},
    initFeaturesSet,
    populateFeatures;

populateFeatures = function (objects) {
    utils.forEach(objects, function (obj, key) {
        var objFeatures = {}, rpt, i, j;
        if (obj.feature) {
            objFeatures = obj.feature.split('|');
            utils.forEach(objFeatures, function (feature) {
                var avail = {uri: feature,
                             required: false,
                             param: null};
                _availableSet[feature] = avail;
            });
            if (_features) {
                rpt = objFeatures.length;
                j = 0;
                for (i = 0; i < rpt; i++) {
                    if (!_features[objFeatures[j]]) {
                        objFeatures.splice(j, 1);
                    } else {
                        j++;
                    }
                }
            }
            utils.forEach(objFeatures, function (feature) {
                var avail = {uri: feature,
                             required: true,
                             param: null};
                _activatedSet[feature] = avail;
            });
        }
        if (obj.children) {
            populateFeatures(obj.children);
        }
    });
};

initFeaturesSet = function () {
    _features = utils.copy(app.getInfo().features);
    populateFeatures(platform.current().objects);
    utils.forEach(_activatedSet, function (obj, key) {
            _activatedFeatures.push(obj);
        });
    utils.forEach(_availableSet, function (obj, key) {
            _availableFeatures.push(obj);
        });
    init_done = true;
};

module.exports = {
    listAvailableFeatures: function () {
        if (!init_done)
            initFeaturesSet();
        return _availableFeatures;
    },

    listActivatedFeatures: function () {
        if (!init_done)
            initFeaturesSet();
        return _activatedFeatures;
    }
};


});
define('ripple/platform/wac/2.0/pendingObject', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (pendingObj) {
    var cancelFlag = true;
    this.setCancelFlag = function (flag) {
        cancelFlag = flag;
    };
    this.getCancelFlag = function () {
        return cancelFlag;
    };
    this.userCancel = null;
    this.pendingID = null;
};

});
define('ripple/platform/wac/2.0/devicestatus', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    _console = require('ripple/console'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    deviceSettings = require('ripple/deviceSettings'),    
    event = require('ripple/event'),    
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    _getDeviceInfoAspect = true,
    _getNetworkInfoAspect = true,    
    _deviceInfoAspect = ["Battery", "Device", "Display", "MemoryUnit", "OperatingSystem", "WebRuntime"],    
    _networkInfoAspect = ["CellularHardware", "CellularNetwork", "WiFiHardware", "WiFiNetwork"],
    _aspectArray = [], 
    _propertyMap = {},
    _watches = {},
    _self;

function _asynchErrorCallback(errorCallback, errorCode) {
    if (errorCallback) {        
        setTimeout(function () {
            errorCallback(errorCode);
        }, 1);  
    }
}

function _initialize() {
    var aspectName, index, i;

    _aspectArray = _deviceInfoAspect.concat(_networkInfoAspect);
    for (index = 0; index < _aspectArray.length; index++) {
        aspectName = _aspectArray[index];
        _propertyMap[aspectName] = [];
        for (i in deviceSettings.retrieve(aspectName)) {
            _propertyMap[aspectName].push(i);
        }
    }     
}

function _isPropertyFound(aspect, property) {
    if (_aspectArray.length === 0) {
        _initialize();
    }

    if (_propertyMap[aspect]) {
        if (property) {
            return _propertyMap[aspect].some(function (prop) {
                return prop === property;
            });
        }
        return true;
    }
    return false;
}

function _isPropertyAllowed(aspect) {
    function hasAspect(asp) {
        return asp === aspect;
    }

    if ((_deviceInfoAspect.some(hasAspect) && _getDeviceInfoAspect === false) ||
        (_networkInfoAspect.some(hasAspect) && _getNetworkInfoAspect === false)) {
        return false;
    }

    return true;
}

function _isPropertyValid(prop, errorCallback) {
    var _prop = Object(prop);

    if (_prop && _prop.aspect && _prop.property) {
        if (_isPropertyFound(_prop.aspect, _prop.property) === false) {
            _asynchErrorCallback(errorCallback, new DeviceApiError(errorcode.NOT_FOUND_ERR));
            return false;
        }
        else if (_isPropertyAllowed(_prop.aspect) === false) {
            _asynchErrorCallback(errorCallback, new DeviceApiError(errorcode.SECURITY_ERR));
            return false;
        }
    } 
    else {
        _asynchErrorCallback(errorCallback, new DeviceApiError(errorcode.INVALID_VALUES_ERR));
        return false;
    }
    return true;
}

module.exports = function () {
    return {  
        getComponents: function (aspect) {
            if (_isPropertyFound(aspect))
                return ["_default"];
            return null;              
        },

        isSupported: function (aspect, property) {
            return _isPropertyFound(aspect, property);
        },

        getPropertyValue: function (successCallback, errorCallback, prop) {
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "getPropertyValue", function () {                                  
                if (_isPropertyValid(prop, errorCallback) !== true)
                    return undefined;
                
                var value = deviceSettings.retrieve(prop.aspect + "." + prop.property);
                if (value !== undefined) {
                    successCallback(value, prop);
                }
                else {
                    _asynchErrorCallback(errorCallback, new DeviceApiError(errorcode.NOT_AVAILABLE_ERR)); 
                }
                
                return null;    
            });        
        },
       
        watchPropertyChange: function (successCallback, errorCallback, prop, options) {  
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "watchPropertyChange", function () {
                if (_isPropertyValid(prop, errorCallback) !== true)
                    return undefined;

                var _options = Object(options),
                    eventType = deviceSettings.retrieve(prop.aspect)[prop.property].event,
                    watchObj = {
                        eventType: eventType,
                        onEvent: function (newValue) {
                            if (watchObj.timeStamp && 
                                ((new Date()).getTime() - watchObj.timeStamp < options.minNotificationInterval)) {
                                return undefined;
                            }                       
                            else if (watchObj.value &&
                                     (newValue > watchObj.value * (1 - _options.minChangePercent) && 
                                      newValue < watchObj.value * (1 + _options.minChangePercent))) {
                                return undefined;
                            }

                            if (watchObj.intervalId) {
                                clearInterval(watchObj.intervalId);
                                watchObj.intervalId = setInterval(function () {
                                    successCallback(deviceSettings.retrieve(prop.aspect + "." + prop.property), prop);
                                }, _options.maxNotificationInterval);
                            }
                            successCallback(newValue, prop);
                            if (watchObj.timeStamp) {
                                watchObj.timeStamp = (new Date()).getTime();
                            }
                            if (watchObj.value) {
                                watchObj.value = newValue;
                            }
                        }                              
                    },
                    watchId = (new Date()).getTime() | 0;

                if (options && _options.minNotificationInterval && _options.maxNotificationInterval && 
                    (_options.minNotificationInterval < 0 || _options.maxNotificationInterval < 0 || 
                     _options.minNotificationInterval >= _options.maxNotificationInterval)) {
                    _asynchErrorCallback(errorCallback, new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                    return undefined;
                }

                if (options && _options.maxNotificationInterval) {
                    watchObj.intervalId = setInterval(function () {
                        successCallback(deviceSettings.retrieve(prop.aspect + "." + prop.property), prop);
                    }, _options.maxNotificationInterval);
                }    

                if (options && _options.minNotificationInterval) {
                    watchObj.timeStamp = (new Date()).getTime();
                }                    

                if (options && _options.minChangePercent) {
                    if (_options.minNotificationInterval || _options.maxNotificationInterval) {}
                    else {                
                        watchObj.value = deviceSettings.retrieve(prop.aspect + "." + prop.property);
                    }
                }
               
                _watches[watchId] = watchObj;
                if (watchObj.eventType) {
                    event.on(watchObj.eventType, watchObj.onEvent);
                }

                return watchId;
            });             
        },

        clearPropertyChange: function (watchHandler) {
            var _handler = watchHandler | 0;
            
            if (_watches[_handler]) {
                event.deleteEventHandler(_watches[_handler].eventType, _watches[_handler].onEvent);            
                if (_watches[_handler].intervalId) {
                    clearInterval(_watches[_handler].intervalId);
                }
                delete(_watches[_handler]); 
            }
            return null;
        },

        handleSubFeatures: function (subFeatures) {
            if (wac2_utils.isEmptyObject(subFeatures) ||
                subFeatures["http://wacapps.net/api/devicestatus"] || 
                (subFeatures["http://wacapps.net/api/devicestatus.deviceinfo"] &&
                 subFeatures["http://wacapps.net/api/devicestatus.networkinfo"])) {
                return;
            }
            if (subFeatures["http://wacapps.net/api/devicestatus.deviceinfo"]) {
                _getNetworkInfoAspect = false;
                return;
            }
            if (subFeatures["http://wacapps.net/api/devicestatus.networkinfo"]) {
                _getDeviceInfoAspect = false;
                return;
            }
            _console.warn("WAC-2.0-Devicestatus-handleSubFeatures: something wrong");
        }
    };
};


});
define('ripple/platform/wac/2.0/messaging', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    event = require('ripple/event'),
    db = require('ripple/db'),
    exception = require('ripple/exception'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    TypeCoerce = require('ripple/platform/wac/2.0/typecoerce'),
    Filter = require('ripple/platform/wac/2.0/messagefilter'),
    FileSystem = require('ripple/platform/wac/2.0/filesystem'),
    MessageSendCallback,
    Message,
    MessageFilter,
    Recipients,
    _KEY = "wac2-pim-messaging",
    _PENDING_TIME = 600,
    _messages = {},
    _subscriber = {
        onSMS: {},
        onMMS: {},
        onEmail: {}
    },
    _sentStatus = {},
    _security = {
        "http://wacapps.net/api/messaging": [],
        "http://wacapps.net/api/messaging.send": ["sendMessage"],
        "http://wacapps.net/api/messaging.find": ["findMessages"],
        "http://wacapps.net/api/messaging.subscribe": ["onSMS", "onMMS", "onEmail"],
        "http://wacapps.net/api/messaging.write": ["update"],
        all: true
    },
    _fileSystem,
    _initialized = false,
    _self;

function _initialize() {
    _get();
    if (!_fileSystem) {
        _fileSystem = new FileSystem();
    }
    _initialized = true;
}

function _get() {
    _messages = db.retrieveObject(_KEY) || {1: [], 2: [], 3: [], 4: []};
    utils.forEach(_messages, function (folder) {
        utils.forEach(folder, function (messageItem) {
            if (messageItem.timestamp)
                messageItem.timestamp = new Date(messageItem.timestamp);
        });
    });
}

function _save() {
    db.saveObject(_KEY, _messages);
}

function _updateDB(message, duplicate) {
    _get();
    _messages[message.folder].push(message);
    if (duplicate)
        _messages[duplicate.folder].push(duplicate);
    _save();
}

function _processAttachments(message) {
    var attachmentsFileName = [],
        attachmentsContent = [];

    function _generateAttachmentFileName(attachment) {
        var lastDot = attachment.filename.lastIndexOf(".");
        return attachment.filename.substring(0, lastDot) + "_" + Math.uuid(8, 16) + attachment.filename.substring(lastDot);
    }

    function _onResolveSuccess(file) {
        var fileAttachment = file.createFile(attachmentsFileName[0]);

        fileAttachment.openStream(
            function (fs) {
                fs.write(attachmentsContent[0]);
                fs.close();
            }, null, "w");
    }

    function _onResolveError() {
    }

    if (message.attachments.length === 0)
        return;

    attachmentsFileName.push(_generateAttachmentFileName(message.attachments[0]));
    attachmentsContent.push(message.attachments[0].content);

    _fileSystem.resolve(_onResolveSuccess, _onResolveError, "attachments", "rw");

    message.attachments = utils.copy(attachmentsFileName);
}

function _errorOccurred(onError, code) {
    if (!onError)
        return;

    setTimeout(function () {
        onError(new DeviceApiError(code));
    }, 1);
}

function _pendingOperate(operate, scope) {
    var i, argumentVector = [];

    for (i = 0; i < arguments.length - 2; i++)
        argumentVector[i] = arguments[i + 2];

    return function () {
        var pendingObj, pendingOperation;

        pendingObj = new PendingObject();
        pendingObj.pendingID = window.setTimeout(function () {
            pendingObj.setCancelFlag(false);
            if (operate)
                operate.apply(scope, argumentVector);
        }, _PENDING_TIME);

        pendingOperation = new PendingOperation(pendingObj);

        return pendingOperation;
    };
}

function _onMessage(onMessage, messageHandler) {
    if (!messageHandler)
        exception.raise(exception.types.Argument,
            onMessage + " invalid messageHandler parameter",
            new DeviceApiError(errorcode.INVALID_VALUES_ERR));

    utils.validateArgumentType(messageHandler, "function", null,
        "messageHandler invalid function parameter",
        new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));

    if (!_security.all && !_security[onMessage])
        exception.raise(exception.types.Argument,
            onMessage + " access denied", new DeviceApiError(errorcode.SECURITY_ERR));

    var idSubscribe = (new Date()).getTime() | 0;
    _subscriber[onMessage][idSubscribe] = messageHandler;

    return idSubscribe;
}

function _validateRecipients(message) {
    var i;

    for (i = 0; i < message.to.length;) {
        message.to[i] = message.to[i].replace(/^\s*(\S*)\s*$/, '$1');
        if (message.to[i] === "")
            message.to.splice(i, 1);
        else
            i++;
    }
    for (i = 0; i < message.cc.length;) {
        message.cc[i] = message.cc[i].replace(/^\s*(\S*)\s*$/, '$1');
        if (message.cc[i] === "")
            message.cc.splice(i, 1);
        else
            i++;
    }
    for (i = 0; i < message.bcc.length;) {
        message.bcc[i] = message.bcc[i].replace(/^\s*(\S*)\s*$/, '$1');
        if (message.bcc[i] === "")
            message.bcc.splice(i, 1);
        else
            i++;
    }
    if (message.to.length + message.cc.length + message.bcc.length === 0)
        exception.raise(exception.types.Argument,
            "sendMessage invalid message.to parameter",
            new DeviceApiError(errorcode.INVALID_VALUES_ERR));
}

function _isValid(onSuccess, onError, message) {
    if (onSuccess &&
        typeof onSuccess !== "function" &&
        typeof onSuccess !== "object") {
        exception.raise(exception.types.Argument,
            "sendMessage invalid successCallback parameter",
            new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
    }

    if (onError) {
        utils.validateArgumentType(onError, "function", null,
            "sendMessage invalid errorCallback parameter",
            new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
    }

    if (!onSuccess) {
        _errorOccurred(onError, errorcode.INVALID_VALUES_ERR);
        return false;
    }

    if (message) {
        utils.validateArgumentType(message, "object", null,
            "sendMessage invalid message parameter",
            new DeviceApiError(errorcode.INVALID_VALUES_ERR));
    } else {
        _errorOccurred(onError, errorcode.INVALID_VALUES_ERR);
        return false;
    }

    if (message.type !== _self().TYPE_SMS &&
        message.type !== _self().TYPE_MMS &&
        message.type !== _self().TYPE_EMAIL)
        exception.raise(exception.types.Argument,
            "sendMessage invalid message.type parameter",
            new DeviceApiError(errorcode.INVALID_VALUES_ERR));

    if (!_security.all && !_security.sendMessage) {
        _errorOccurred(onError, errorcode.SECURITY_ERR);
        return false;
    }

    TypeCoerce(Message(0)).cast(message);
    _validateRecipients(message);

    return true;
}

function _getEachSentStatus(onMessageSentSuccess, onMessageSentError, message,
                            sucRecipients, failRecipients, recType) {
    utils.forEach(message[recType], function (recipient) {
        if (_sentStatus[recipient]) {
            sucRecipients[recType].push(recipient);
            if (onMessageSentSuccess) {
                onMessageSentSuccess(recipient);
            }
        } else {
            failRecipients[recType].push(recipient);
            if (onMessageSentError) {
                onMessageSentError(new DeviceApiError(errorcode.UNKNOWN_ERR), recipient);
            }
        }
    });
}

function _getSentStatus(onSuccess, onError, message, onMessageSentSuccess, onMessageSentError) {
    var allSentSuccess,
        sucRecipients = new Recipients(),
        failRecipients = new Recipients(),
        duplicate;

    _getEachSentStatus(onMessageSentSuccess, onMessageSentError,
        message, sucRecipients, failRecipients, "to");

    if (message.type === _self().TYPE_EMAIL) {
        _getEachSentStatus(onMessageSentSuccess, onMessageSentError,
            message, sucRecipients, failRecipients, "cc");
        _getEachSentStatus(onMessageSentSuccess, onMessageSentError,
            message, sucRecipients, failRecipients, "bcc");
    }

    allSentSuccess = (failRecipients.total() === 0);

    if (allSentSuccess) {
        message.folder = _self().FOLDER_SENTBOX;
    } else if (sucRecipients.total() === 0) {
        message.folder = _self().FOLDER_DRAFTS;
    } else {
        duplicate = utils.copy(message);

        message.to = sucRecipients.to;
        message.cc = sucRecipients.cc;
        message.bcc = sucRecipients.bcc;
        message.folder = _self().FOLDER_SENTBOX;

        duplicate.to = failRecipients.to;
        duplicate.cc = failRecipients.cc;
        duplicate.bcc = failRecipients.bcc;
        duplicate.folder = _self().FOLDER_DRAFTS;
    }

    _updateDB(message, duplicate);

    if (allSentSuccess) {
        onSuccess();
    } else if (onError) {
        onError(new DeviceApiError(errorcode.UNKNOWN_ERR));
    }
}

_self = function () {
    var messaging = {
        createMessage: function (type) {
            type = type | 0;

            if (type < _self().TYPE_SMS || type > _self().TYPE_EMAIL)
                exception.raise(exception.types.Argument,
                "type invalid value", new DeviceApiError(errorcode.INVALID_VALUES_ERR));

            var msg = new Message(type);

            return msg;
        },

        sendMessage: function (successCallback, errorCallback, message) {
            var ret;

            function _sendMessage() {
                event.trigger("OutsideMessageReceived", [message]);

                return _pendingOperate(_getSentStatus, undefined,
                    successCallback, errorCallback, message)();
            }

            function _sendEachMessage() {
                utils.forEach(successCallback, function (value, key) {
                    utils.validateArgumentType(value, "function", null,
                        "sendMessage invalid successCallback." + key + " parameter",
                        new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
                });

                event.trigger("OutsideMessageReceived", [message]);

                return _pendingOperate(_getSentStatus, undefined,
                    successCallback.onsuccess, errorCallback, message,
                    successCallback.onmessagesendsuccess, successCallback.onmessagesenderror)();
            }

            if (!_isValid(successCallback, errorCallback, message))
                return null;

            switch (typeof successCallback) {
            case "function":
                ret = _sendMessage();
                break;

            case "object":
                ret = _sendEachMessage();
                break;
            }

            return ret;
        },

        findMessages: function (successCallback, errorCallback, filter) {
            function _findMessages() {
                var message, result = [];

                if (!_security.all && !_security.findMessages)
                    return _errorOccurred(errorCallback, errorcode.SECURITY_ERR);

                utils.forEach(_messages, function (folder) {
                    utils.forEach(folder, function (messageItem) {
                        if ((filter                 === undefined || filter === null) ||
                            (filter.id              === undefined || Filter(filter.id).match(messageItem.id)) &&
                            (filter.type            === undefined || Filter(filter.type).match(messageItem.type)) &&
                            (filter.folder          === undefined || Filter(filter.folder).match(messageItem.folder)) &&
                            (filter.startTimestamp  === undefined || (messageItem.timestamp >= filter.startTimestamp)) &&
                            (filter.endTimestamp    === undefined || (messageItem.timestamp <= filter.endTimestamp)) &&
                            (filter.from            === undefined || Filter(filter.from).match(messageItem.from)) &&
                            (filter.to              === undefined || Filter(filter.to).match(messageItem.to)) &&
                            (filter.cc              === undefined || Filter(filter.cc).match(messageItem.cc)) &&
                            (filter.bcc             === undefined || Filter(filter.bcc).match(messageItem.bcc)) &&
                            (filter.body            === undefined || Filter(filter.body).match(messageItem.body)) &&
                            (filter.isRead          === undefined || (messageItem.isRead === filter.isRead)) &&
                            (filter.messagePriority === undefined || (messageItem.priority === filter.messagePriority)) &&
                            (filter.subject         === undefined || Filter(filter.subject).match(messageItem.subject))) {
                            message = utils.copy(messageItem);
                            result.push(message);
                        }
                    });
                });
                successCallback(result);
            }
            return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "findMessages", _pendingOperate(_findMessages));
        },

        onSMS: function (messageHandler) {
            return _onMessage("onSMS", messageHandler);
        },

        onMMS: function (messageHandler) {
            return _onMessage("onMMS", messageHandler);
        },

        onEmail: function (messageHandler) {
            return _onMessage("onEmail", messageHandler);
        },

        unsubscribe: function (subscriptionHandler) {
            var onMessage, idSubscribe;

            utils.validateArgumentType(subscriptionHandler, "integer",
                null, "subscriptionHandler invalid function parameter",
                new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));

            for (onMessage in _subscriber) {
                for (idSubscribe in _subscriber[onMessage]) {
                    if (idSubscribe == subscriptionHandler) {
                        delete _subscriber[onMessage][idSubscribe];
                        return;
                    }
                }
            }
        },

        handleSubFeatures: function (subFeatures) {
            for (var subFeature in subFeatures) {
                if (_security[subFeature].length === 0) {
                    _security.all = true;
                    return;
                }
                _security.all = false;
                utils.forEach(_security[subFeature], function (method) {
                    _security[method] = true;
                });
            }
        }
    };

    messaging.__defineGetter__("TYPE_SMS", function () {
        return 1;
    });

    messaging.__defineGetter__("TYPE_MMS", function () {
        return 2;
    });

    messaging.__defineGetter__("TYPE_EMAIL", function () {
        return 3;
    });

    messaging.__defineGetter__("FOLDER_INBOX", function () {
        return 1;
    });

    messaging.__defineGetter__("FOLDER_OUTBOX", function () {
        return 2;
    });

    messaging.__defineGetter__("FOLDER_DRAFTS", function () {
        return 3;
    });

    messaging.__defineGetter__("FOLDER_SENTBOX", function () {
        return 4;
    });

    if (!_initialized)
        _initialize();

    return messaging;
};

MessageSendCallback = {
    onsuccess: function () {},
    onmessagesendsuccess: function (recipient) {},
    onmessagesenderror: function (error, recipient) {}
};

Message = function (type) {
    this.id = Math.uuid(null, 16);
    this.type = type;
    this.folder = 0;
    this.timestamp = new Date();
    this.from = "";
    this.to = [""];
    this.cc = [""];
    this.bcc = [""];
    this.body = "";
    this.isRead = false;
    this.priority = false;
    this.subject = "";
    this.attachments = [""];

    this.update = function (successCallback, errorCallback) {
        function _update() {
            var isFound = false;

            if (!_security.all && !_security.update)
                return _errorOccurred(errorCallback, errorcode.SECURITY_ERR);

            TypeCoerce(new Message(0)).cast(this);
            _get();
            utils.forEach(_messages[this.folder], function (messageItem) {
                if (messageItem.id === this.id) {
                    !this.isRead || (messageItem.isRead = this.isRead);
                    if (this.folder === _self().FOLDER_DRAFTS) {
                        !this.type        || (messageItem.type        = this.type);
                        !this.to          || (messageItem.to          = utils.copy(this.to));
                        !this.cc          || (messageItem.cc          = utils.copy(this.cc));
                        !this.bcc         || (messageItem.bcc         = utils.copy(this.bcc));
                        !this.body        || (messageItem.body        = this.body);
                        !this.priority    || (messageItem.priority    = this.priority);
                        !this.subject     || (messageItem.subject     = this.subject);
                        !this.attachments || (messageItem.attachments = utils.copy(this.attachments));
                    }
                    isFound = true;
                }
            });

            if (isFound) {
                _save();
                successCallback();
            } else {
                _errorOccurred(errorCallback, errorcode.NOT_FOUND_ERR);
            }
        }
        return wac2_utils.validateTypeMismatch(successCallback, errorCallback, "update", _pendingOperate(_update, this));
    };
};

MessageFilter = {
    id: "",
    type: [0],
    folder: [0],
    startTimestamp: new Date(),
    endTimestamp: new Date(),
    from: "",
    to: [""],
    cc: [""],
    bcc: [""],
    body: "",
    isRead: false,
    messagePriority: false,
    subject: ""
};

Recipients = function () {
    this.to  = [];
    this.cc  = [];
    this.bcc = [];

    this.total = function () {
        return (this.to.length + this.cc.length + this.bcc.length);
    };
};

event.on("MessageReceived", function (message) {
    var onMessage;

    switch (message.type) {
    case "sms":
        message.type = _self().TYPE_SMS;
        onMessage = "onSMS";
        break;

    case "mms":
        message.type = _self().TYPE_MMS;
        onMessage = "onMMS";
        break;

    case "email":
        message.type = _self().TYPE_EMAIL;
        onMessage = "onEmail";
        break;

    default:
        break;
    }

    message.folder = _self().FOLDER_INBOX;
    _processAttachments(message);
    _updateDB(message);
    utils.forEach(_subscriber[onMessage], function (subscriberCallback) {
        subscriberCallback(message);
    });
});

event.on("MessageSent", function (sentStatus) {
    _sentStatus = sentStatus;
});

module.exports = _self;

});
define('ripple/platform/wac/2.0/calendar', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    constants = require('ripple/constants'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    _console = require('ripple/console'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    _SIM_CALENDAR = 0, _DEVICE_CALENDAR = 1,
    _NO_RECURRENCE = 0, _DAILY_RECURRENCE = 1, _WEEKLY_RECURRENCE = 2,
    _MONTHLY_RECURRENCE = 3, _YEARLY_RECURRENCE = 4,
    _TENTATIVE_STATUS = 0, _CONFIRMED_STATUS = 1, _CANCELLED_STATUS = 2,
    _NO_ALARM = 0, _SILENT_ALARM = 1, _SOUND_ALARM = 2,
    _calendars = [], _DB_CALENDARS_KEY = "wac2-db-calendars",
    _FAKEWAITTIME = 5, _FAKE_LONG_WAITTIME = 10,
    _save_calendars, _eventPropCheck, _eventFilterCheck,
    _addEventAllowed = true, _deleteEventAllowed = true,
    _updateEventAllowed = true, _findEventsAllowed = true,
    CalendarEventProperties, Calendar, CalendarEvent;

_save_calendars = function (_name, _type, _events) {
    var i;
    for (i = 0; i < _calendars.length; i++) {
        if (_calendars[i].name === _name && _calendars[i].type === _type) {
            _calendars[i].events = _events;
            break;
        }
    }
    db.saveObject(_DB_CALENDARS_KEY, _calendars);
};

_eventPropCheck = function (prop, dst) {
    var i;
    if (prop.description !== null && prop.description !== undefined) {
        dst.description = String(prop.description);
    }
    if (prop.summary !== null && prop.summary !== undefined) {
        dst.summary = String(prop.summary);
    } 
    if (prop.startTime !== null && prop.startTime !== undefined) {
        if (!wac2_utils.isValidDate(prop.startTime)) {
            return false;
        }
        dst.startTime = new Date(prop.startTime);
    }
    dst.duration = prop.duration | 0;
    if (prop.location !== null && prop.location !== undefined) {
        dst.location = String(prop.location);
    }
    if (prop.categories !== null && prop.categories !== undefined) {
        if (!wac2_utils.isValidArray(prop.categories))  {
            return false;
        }
        dst.categories = [];
        for (i = 0; i < prop.categories.length; i++) {
            dst.categories.push(String(prop.categories[i]));
        }
    }
    if (prop.recurrence !== null && prop.recurrence !== undefined) {
        if (prop.recurrence === _NO_RECURRENCE ||
            prop.recurrence === _DAILY_RECURRENCE ||
            prop.recurrence === _WEEKLY_RECURRENCE ||
            prop.recurrence === _MONTHLY_RECURRENCE ||
            prop.recurrence === _YEARLY_RECURRENCE) {
            dst.recurrence = prop.recurrence | 0;
        } else {
            return false;
        }
    }
    if (dst.recurrence === _NO_RECURRENCE) {
        dst.expires = null;
        dst.interval = null;
    } else {
        // expires and interval matters when recurrence is not NO_RECURRENCE
        if (prop.expires !== null && prop.expires !== undefined) {
            if (!wac2_utils.isValidDate(prop.expires)) {
                return false;
            }
            dst.expires = new Date(prop.expires);
        }
        // expires === undefined -> to recur indefinitely
        // expires === null -> keep dst.expires unchanged, even it's null
        if (prop.expires === undefined) {
            dst.expires = null;
        }
        if (prop.interval !== null && prop.interval !== undefined) {
            dst.interval = prop.interval | 0;
        }
    }

    if (prop.status !== null && prop.status !== undefined) {
        if (prop.status === _TENTATIVE_STATUS ||
            prop.status === _CONFIRMED_STATUS ||
            prop.status === _CANCELLED_STATUS) {
            dst.status = prop.status | 0;
        } else {
            return false;
        }
    }

    if (prop.alarmType !== null && prop.alarmType !== undefined) {
        if (prop.alarmType === _NO_ALARM ||
            prop.alarmType === _SILENT_ALARM ||
            prop.alarmType === _SOUND_ALARM) {
            dst.alarmType = prop.alarmType;
        } else {
            return false;
        }
    } 
    if (dst.alarmType !== _NO_ALARM && prop.alarmTrigger !== undefined && prop.alarmTrigger !== undefined) {
        dst.alarmTrigger = prop.alarmTrigger | 0;
    }
};

_eventFilterCheck = function (filter) {
    if (filter.id !== undefined && filter.id !== null) {
        filter.id = String(filter.id);
    } else {
        filter.id = undefined;
    }
    if (filter.summary !== undefined && filter.summary !== null) {
        filter.summary = String(filter.summary);
    } else {
        filter.summary = undefined;
    }
    if (filter.description !== undefined && filter.description !== null) {
        filter.description = String(filter.description);
    } else {
        filter.description = undefined;
    }
    if (filter.location !== undefined && filter.location !== null) {
        filter.location = String(filter.location);
    } else {
        filter.location = undefined;
    }
    if (filter.catetory !== undefined && filter.catetory !== null) {
        filter.catetory = String(filter.catetory);
    } else {
        filter.catetory = undefined;
    }
    if (filter.status !== undefined && filter.status !== null) {
        var i;
        if (!wac2_utils.isValidArray(filter.status))  {
            return false;
        }
        for (i = 0; i < filter.status.length; i++) {
            filter.status[i] = filter.status[i] | 0;
            if (filter.status[i] > _CANCELLED_STATUS || filter.status[i] < _TENTATIVE_STATUS)
                return false;
        }
    } else {
        filter.status = undefined;
    }
    if (filter.initialStartDate !== undefined && filter.initialStartDate !== null) {
        if (!wac2_utils.isValidDate(filter.initialStartDate)) {
            return false;
        }
        filter.initialStartDate = new Date(filter.initialStartDate);
    } else {
        filter.initialStartDate = undefined;
    }
    if (filter.endStartDate !== undefined && filter.endStartDate !== null) {
        if (!wac2_utils.isValidDate(filter.endStartDate)) {
            return false;
        }
        filter.endStartDate = new Date(filter.endStartDate);
    } else {
        filter.endStartDate = undefined;
    }
    return true;
};

CalendarEventProperties = function (prop) {
    var _self;
    _self = {
        description : "",
        summary : "",
        startTime : new Date(),
        duration : 0,
        location : "",
        categories : undefined,
        recurrence : _NO_RECURRENCE,
        expires : null,  // ignored if recurrence == NO_RECURRENCE
        interval : null, // ignored if recurrence == NO_RECURRENCE
        status : _CONFIRMED_STATUS,
        alarmTrigger : 0,
        alarmType : _NO_ALARM
    };
    if (prop) {
        if (_eventPropCheck(prop, _self) === false) {
            return undefined;
        }
    }
    return _self;
};

CalendarEvent = function (prop, genNewID) {
    var id, _self = new CalendarEventProperties(prop);

    /* if error occurs during checking, _self is an empty object.
       so i randomly pick description to check if property check fails */
    if (_self.description === undefined) {
        return undefined;
    }

    if (genNewID === true) {
        id = Math.uuid(undefined, 16);
    } else {
        id = prop.id;
    }
    _self.__defineGetter__("id", function () {
        return id;
    });
    return _self;
};

Calendar = function (type, name, events) {
    var _type = type,
        _name = name,
        _events = events, _self;

    _self = {
        createEvent: function (evtProp) {
            var rst = {};
            rst = new CalendarEventProperties(evtProp);
            /* if error occurs during checking, rst is an empty object.
               so i randomly pick description to check if property check fails */
            if (rst.description === undefined) {
                exception.raise(exception.types.Argument, "EventProperties: input parameter contains invalid values", new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                return undefined;
            } else {
                return rst;
            }
        },

        addEvent: function (onSuccess, onError, calEvent) {
            var pendingOperation, pendingObj = {},
                newEvent = {}, _doAddEvent, _calEvent = Object(calEvent);

            _doAddEvent = function () {
                if (!_addEventAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                newEvent = new CalendarEvent(_calEvent, true);
                /* if newEvent.id === undefined,
                   means somthing wrong in calEvent  */
                if (newEvent.id === undefined) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                pendingObj = new PendingObject();
                pendingObj.pendingID = setTimeout(function () {
                    pendingObj.setCancelFlag(false);
                    _events[newEvent.id] = newEvent;
                    _save_calendars(_name, _type, _events);
                    onSuccess(new CalendarEvent(newEvent), false);
                }, _FAKEWAITTIME);
                pendingOperation = new PendingOperation(pendingObj);
                return pendingOperation;
            };

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "Calendar:addEvent", _doAddEvent);
        },

        updateEvent: function (onSuccess, onError, calEvent) {
            var pendingOperation, pendingObj = {},
                chkEvent, _doUpdateEvent, _calEvent = Object(calEvent);

            _doUpdateEvent = function () {
                if (!_updateEventAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                if (!_events[_calEvent.id]) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.NOT_FOUND_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                chkEvent = new CalendarEvent(_events[_calEvent.id], false);
                /* _eventPropCheck will also update chkEvent btw */
                if (_eventPropCheck(_calEvent, chkEvent) === false) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                pendingObj = new PendingObject();
                pendingObj.pendingID = setTimeout(function () {
                    pendingObj.setCancelFlag(false);

                    _events[chkEvent.id] = chkEvent;
                    _save_calendars(_name, _type, _events);
                    onSuccess();
                }, _FAKEWAITTIME);
                pendingOperation = new PendingOperation(pendingObj);
                return pendingOperation;
            };

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "Calendar:updateEvent", _doUpdateEvent);
        },

        deleteEvent: function (onSuccess, onError, id) {
            var pendingOperation, pendingObj = {},
                _doDeleteEvent;

            _doDeleteEvent = function () {
                /* according to spec  "If any of the input parameters are not 
                   compatible with the expected type for that parameter, 
                   a DeviceAPIError with code TYPE_MISMATCH_ERR MUST be 
                   synchronously thrown." 
                   so an error is raised synchronously */
                utils.validateArgumentType(id, "string", null,
                                       "Calendar:deleteEvent: " + " invalid id parameter",
                                       new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));

                if (!_deleteEventAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                if (!_events[id]) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.NOT_FOUND_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                pendingObj = new PendingObject();
                pendingObj.pendingID = setTimeout(function () {
                    pendingObj.setCancelFlag(false);

                    delete _events[id];
                    _save_calendars(_name, _type, _events);
                    onSuccess();
                }, _FAKEWAITTIME);
                pendingOperation = new PendingOperation(pendingObj);
                return pendingOperation;
            };

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "Calendar:deleteEvent", _doDeleteEvent);
        },

        findEvents: function (onSuccess, onError, eventFilter) {
            var pendingOperation, pendingObj = {}, i,
                tmp = [], valid_tmp = false, rst = [], _doFindEvents,
                _eventFilter = Object(eventFilter);

            _doFindEvents = function () {
                if (!_eventFilterCheck(_eventFilter)) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                if (!_findEventsAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                pendingObj = new PendingObject();
                pendingObj.pendingID = setTimeout(function () {
                    pendingObj.setCancelFlag(false);
                    if (_eventFilter.id !== undefined) {
                        tmp = wac2_utils.matchOptionString(_events, "id", _eventFilter.id);
                        valid_tmp = true;
                    }
                    if (_eventFilter.summary !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionString(tmp, "summary", _eventFilter.summary);
                        } else {
                            tmp = wac2_utils.matchOptionString(_events, "summary", _eventFilter.summary);
                            valid_tmp = true;
                        }
                    }
                    if (_eventFilter.description !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionString(tmp, "description", _eventFilter.description);
                        } else {
                            tmp = wac2_utils.matchOptionString(_events, "description", _eventFilter.description);
                            valid_tmp = true;
                        }
                    }
                    if (_eventFilter.location !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionString(tmp, "location", _eventFilter.location);
                        } else {
                            tmp = wac2_utils.matchOptionString(_events, "location", _eventFilter.location);
                            valid_tmp = true;
                        }
                    }
                    if (_eventFilter.category !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionArrayString(tmp, "categories", _eventFilter.category);
                        } else {
                            tmp = wac2_utils.matchOptionArrayString(_events, "categories", _eventFilter.category);
                            valid_tmp = true;
                        }
                    }
                    if (_eventFilter.status !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionShortArray(tmp, "status", _eventFilter.status);
                        } else {
                            tmp = wac2_utils.matchOptionShortArray(_events, "status", _eventFilter.status);
                            valid_tmp = true;
                        }
                    }
                    if (_eventFilter.initialStartDate !== undefined ||
                        _eventFilter.endStartDate !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionDate(tmp, "startTime", _eventFilter.initialStartDate, _eventFilter.endStartDate);
                        } else {
                            tmp = wac2_utils.matchOptionDate(_events, "startTime", _eventFilter.initialStartDate, _eventFilter.endStartDate);
                            valid_tmp = true;
                        }
                    }

                    // to make id readonly
                    if (valid_tmp) {
                        for (i = 0; i < tmp.length; i++) {
                            rst.push(new CalendarEvent(tmp[i], false));
                        }
                    } else {
                        for (var e in _events) {
                            rst.push(new CalendarEvent(_events[e], false));
                        }
                    }
                    onSuccess(rst);
                }, _FAKE_LONG_WAITTIME);
                pendingOperation = new PendingOperation(pendingObj);
                return pendingOperation;
            };

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "Calendar:findEvent", _doFindEvents);
        },
    };
    _self.__defineGetter__("type", function () {
        return _type;
    });
    _self.__defineGetter__("name", function () {
        return name;
    });
    return _self;
};

module.exports = function () {
    this.__defineGetter__("SIM_CALENDAR", function () {
        return 0;
    });
    this.__defineGetter__("DEVICE_CALENDAR", function () {
        return 1;
    });
    this.__defineGetter__("NO_RECURRENCE", function () { 
        return 0;
    });
    this.__defineGetter__("DAILY_RECURRENCE", function () {
        return 1;
    });
    this.__defineGetter__("WEEKLY_RECURRENCE", function () {
        return 2;
    });
    this.__defineGetter__("MONTHLY_RECURRENCE", function () {
        return 3;
    });
    this.__defineGetter__("YEARLY_RECURRENCE", function () {
        return 4;
    });
    this.__defineGetter__("TENTATIVE_STATUS", function () {
        return 0;
    });
    this.__defineGetter__("CONFIRMED_STATUS", function () {
        return 1;
    });
    this.__defineGetter__("CANCELLED_STATUS", function () {
        return 2;
    });
    this.__defineGetter__("NO_ALARM", function () {
        return 0;
    });
    this.__defineGetter__("SILENT_ALARM", function () {
        return 1;
    });
    this.__defineGetter__("SOUND_ALARM", function () {
        return 2;
    });

    this.getCalendars = function (onSuccess, onError) {
        var i, pendingOperation, pendingObj = {}, cal, _doGetCalendars;

        _doGetCalendars = function () {
            pendingObj = new PendingObject();

            pendingObj.pendingID = setTimeout(function () {
                pendingObj.setCancelFlag(false);
                cal = db.retrieveObject(_DB_CALENDARS_KEY) || [];
                _calendars = [];
                if (cal.length === 0) {
                    _calendars.push(new Calendar(_SIM_CALENDAR, "sim cal", {}));
                    _calendars.push(new Calendar(_DEVICE_CALENDAR, "dev cal", {}));
                } else {
                    for (i = 0; i < cal.length; i++) {
                        /* after getting Date out of DB, Date will become 
                           a string, so need to recast it back to Date */
                        /* NOTE: id becomes writable, so need to recast it
                           before passing to application */
                        for (var e in cal[i].events) {
                            if ((cal[i].events[e].startTime !== undefined) &&
                                cal[i].events[e].startTime !== null) {
                                cal[i].events[e].startTime = new Date(cal[i].events[e].startTime);
                            }
                            if ((cal[i].events[e].expires !== undefined) &&
                                cal[i].events[e].expires !== null) {
                                cal[i].events[e].expires = new Date(cal[i].events[e].expires);
                            }
                        }
                        _calendars.push(new Calendar(cal[i].type, cal[i].name, cal[i].events));
                    }
                }
                if (_calendars.length !== 0) {
                    onSuccess(utils.copy(_calendars));
                } else {
                    if (onError) {
                        onError(new DeviceApiError(errorcode.UNKNOWN_ERR));
                    }
                }
            }, _FAKEWAITTIME);
            pendingOperation = new PendingOperation(pendingObj);
            return pendingOperation;
        };
    
        return wac2_utils.validateTypeMismatch(onSuccess, onError, "getCalendars", _doGetCalendars);
    };

    this.handleSubFeatures = function (subFeatures) {
        if (wac2_utils.isEmptyObject(subFeatures) ||
            subFeatures["http://wacapps.net/api/pim.calendar"] ||
            (subFeatures["http://wacapps.net/api/pim.calendar.read"] &&
            subFeatures["http://wacapps.net/api/pim.calendar.write"])) {
            return;
        } 
        if (subFeatures["http://wacapps.net/api/pim.calendar.read"]) {
            _addEventAllowed = false;
            _deleteEventAllowed = false;
            _updateEventAllowed = false;
            return;
        } 
        if (subFeatures["http://wacapps.net/api/pim.calendar.write"]) {
            _findEventsAllowed = false;
            return;
        } 
        _console.warn("WAC-2.0-Calendar-handleSubFeatures: something wrong");
    };
};

});
define('ripple/platform/wac/2.0/task', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    _console = require('ripple/console'),
    exception = require('ripple/exception'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    Task, TaskList, _get,
    _ID_WITHOUT = 0, _ID_GEN_NEW = 1, _ID_FROM_PROP = 2,
    _SIM_TASK_LIST = 0, _DEVICE_TASK_LIST = 1,
    _HIGH_PRIORITY = 0, _MEDIUM_PRIORITY = 1, _LOW_PRIORITY = 2,
    _STATUS_COMPLETED = 0, _STATUS_NEEDS_ACTION = 1, _STATUS_IN_PROCESS = 2, _STATUS_CANCELLED = 3,
    _TASK_OBJECTS = "wac2.0-pim-task-objects",
    _addTaskAllowed = true, _deleteTaskAllowed = true,
    _updateTaskAllowed = true, _findTasksAllowed = true;


module.exports = function () {
    var _taskListArray = [],
        _PENDING_TIME = 10;

    function _pendingOperate(operate) {
        var pendingObj, pendingOperation, i, argumentVector = [];

        for (i = 0; i < arguments.length - 1; i++)
            argumentVector[i] = arguments[i + 1];

        pendingObj = new PendingObject();

        pendingObj.pendingID = window.setTimeout(function () {
            pendingObj.setCancelFlag(false);
            operate.apply(this, argumentVector);
        }, _PENDING_TIME);

        pendingOperation = new PendingOperation(pendingObj);

        return pendingOperation;
    }

    /* taskProperties attribute check & paste */
    function _checkAndPasteProperties(p, dst) {

        if (p.summary !== null && p.summary !== undefined)
            dst.summary = String(p.summary);

        if (p.description !== null && p.description !== undefined)
            dst.description = String(p.description);

        if (p.status !== null && p.status !== undefined) {
            if (p.status === _STATUS_COMPLETED ||
                p.status === _STATUS_NEEDS_ACTION ||
                p.status === _STATUS_IN_PROCESS ||
                p.status === _STATUS_CANCELLED) {
                dst.status = p.status;
            } else
                return false;
        }

        if (p.priority !== null && p.priority !== undefined) {
            if (p.priority === _HIGH_PRIORITY ||
                p.priority === _MEDIUM_PRIORITY ||
                p.priority === _LOW_PRIORITY) {
                dst.priority = p.priority;
            } else
                return false;
        }

        if (p.dueDate !== null && p.dueDate !== undefined) {
            if (!wac2_utils.isValidDate(p.dueDate))
                return false;
            dst.dueDate = new Date(p.dueDate);
        }

        /* dueDate is a option properties.
           "The default value is undefined.
             If no value is provided, the task has no due date."
           If p.dueDate is set its default value 'undefined',
           we assign default value to dst.dueDate */
        if (p.dueDate === undefined) {
            dst.dueDate = undefined;
        }

        return true;
    }

    function _taskFilterCheck(filter) {
        var i;
        if (filter.id !== undefined && filter.id !== null) {
            filter.id = String(filter.id);
        } else {
            filter.id = undefined;
        }
        if (filter.summary !== undefined && filter.summary !== null) {
            filter.summary = String(filter.summary);
        } else {
            filter.summary = undefined;
        }
        if (filter.description !== undefined && filter.description !== null) {
            filter.description = String(filter.description);
        } else {
            filter.description = undefined;
        }
        if (filter.status !== undefined && filter.status !== null) {
            if (!wac2_utils.isValidArray(filter.status))  {
                return false;
            }
            for (i = 0; i < filter.status.length; i++) {
                filter.status[i] = filter.status[i] | 0;
                if (filter.status[i] !== _STATUS_COMPLETED &&
                    filter.status[i] !== _STATUS_NEEDS_ACTION &&
                    filter.status[i] !== _STATUS_IN_PROCESS &&
                    filter.status[i] !== _STATUS_CANCELLED) {
                    return false;
                }
            }
        } else {
            filter.status = undefined;
        }
        if (filter.priority !== undefined && filter.priority !== null) {
            if (!wac2_utils.isValidArray(filter.priority))  {
                return false;
            }
            for (i = 0; i < filter.priority.length; i++) {
                filter.priority[i] = filter.priority[i] | 0;
                if (filter.priority[i] !== _HIGH_PRIORITY &&
                    filter.priority[i] !== _MEDIUM_PRIORITY &&
                    filter.priority[i] !== _LOW_PRIORITY) {
                    return false;
                }
            }
        } else {
            filter.priority = undefined;
        }
        if (filter.dueDate !== undefined && filter.dueDate !== null) {
            if (!wac2_utils.isValidDate(filter.dueDate)) {
                return false;
            }
            filter.dueDate = new Date(filter.dueDate);
        } else {
            filter.dueDate = undefined;
        }
        return true;
    }

    function TaskProperties(prop) {
        var _self;
        _self = {
            priority : _LOW_PRIORITY,
            description : "",
            summary : "",
            dueDate : undefined,
            status : _STATUS_NEEDS_ACTION
        };
        if (prop) {
            if (_checkAndPasteProperties(prop, _self) === false)
                return undefined;
        }
        return _self;
    }

    function Task(prop, idChoice) {
        var id, _self = new TaskProperties(prop);
        /* if error occurs during checking, _self is an empty object.
           so i randomly pick description to check if property check fails */
        if (_self.description === undefined)
            return undefined;

        switch (idChoice) {
        case _ID_WITHOUT:
            // do nothing
            break;
        case _ID_GEN_NEW:
            id = Math.uuid(undefined, 16);
            _self.__defineGetter__("id", function () {
                return id;
            });
            break;
        case _ID_FROM_PROP:
            id = String(prop.id);
            _self.__defineGetter__("id", function () {
                return id;
            });
            break;
        }

        return _self;
    }

    function _get() {
        var taskListArray = [],
            data = db.retrieveObject(_TASK_OBJECTS);
        utils.forEach(data, function (taskList) {
            for (var t in taskList._list) {
                if (taskList._list[t].dueDate !== undefined &&
                    taskList._list[t].dueDate !== null)
                    taskList._list[t].dueDate = new Date(taskList._list[t].dueDate);
            }
            taskListArray.push(new TaskList(taskList._list, taskList.type, taskList.name));
        });

        /* add default taskList if taskListArray is empty */
        if (taskListArray.length === 0) {
            taskListArray = [new TaskList({}, 0, "Office tasks"), new TaskList({}, 1, "Home tasks")];
        }

        return taskListArray;
    }

    function _save() {
        db.saveObject(_TASK_OBJECTS, _taskListArray);
    }

    function TaskList(taskList, type, name) {
        var task;
        this._list = taskList;
        this.type = type;
        this.name = name;

        this.createTask = function (properties) {
            task = new Task(properties, _ID_WITHOUT);
            /* if error occurs during checking, task is an empty object.
               so i randomly pick summary to check if property check fails */
            if (task.summary === undefined) {
                exception.raise(exception.types.Argument,
                        "EventProperties: input parameter contains invalid values",
                        new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                return undefined;
            }
            return task;
        };

        this.addTask = function (onSuccess, onError, task) {
            var inner = this,
                newTask, _task = Object(task);
            function _addTask() {
                var ret;
                if (!_addTaskAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                newTask = new Task(_task, _ID_GEN_NEW);
                /* if error occurs during checking, newTask is an empty object.
                    so i randomly pick id to check if property check fails */
                if (newTask.id === undefined) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                ret = _pendingOperate(function () {
                    inner._list[newTask.id] = newTask;
                    _save();
                    onSuccess(new Task(newTask, _ID_FROM_PROP));
                });
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "addTask", _addTask);
        };

        this.updateTask = function (onSuccess, onError, task) {
            var inner = this,
                newTask, _task = Object(task);
            function _updateTask() {
                var ret;
                if (!_updateTaskAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                if (_checkAndPasteProperties(_task, _task) === false) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }

                ret = _pendingOperate(function () {
                    if (inner._list[_task.id]) {
                        newTask = new Task(inner._list[_task.id], _ID_FROM_PROP);
                        /* Don't need to double check the return of _checkAndPasteProperties 
                           _task has been checked & pasted already */
                        _checkAndPasteProperties(_task, newTask);
                        inner._list[newTask.id] = newTask;
                        _save();
                        onSuccess();
                    } else {
                        if (onError) {
                            onError(new DeviceApiError(errorcode.NOT_FOUND_ERR));
                        }
                    }
                });
                return ret;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "updateTask", _updateTask);
        };

        this.deleteTask = function (onSuccess, onError, id) {
            var inner = this;
            function _deleteTask() {
                var ret;
                /* according to spec  "If any of the input parameters are not 
                   compatible with the expected type for that parameter, 
                   a DeviceAPIError with code TYPE_MISMATCH_ERR MUST be 
                   synchronously thrown." so an error is raised synchronously */
                utils.validateArgumentType(id, "string", null,
                        "Task:deleteTask: " + " invalid id parameter",
                        new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
                if (!_deleteTaskAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                ret = _pendingOperate(function () {
                    if (inner._list[id]) {
                        delete inner._list[id];
                        _save();
                        onSuccess();
                    } else {
                        if (onError)
                            onError(new DeviceApiError(errorcode.NOT_FOUND_ERR));
                    }
                });
                return ret;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "deleteTask", _deleteTask);
        };

        this.findTasks = function (onSuccess, onError, filter) {
            var inner = this, _filter = Object(filter), tmp = [], rst = [], valid_tmp = false;
            function _findTasks() {
                var ret;
                if (!_taskFilterCheck(_filter)) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                if (!_findTasksAllowed) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.SECURITY_ERR));
                        }, 1);
                    }
                    return undefined;
                }
                ret = _pendingOperate(function () {
                    var i, e;
                    if (_filter.id !== undefined) {
                        tmp = wac2_utils.matchOptionString(inner._list, "id", _filter.id);
                        valid_tmp = true;
                    }
                    if (_filter.summary !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionString(tmp, "summary", _filter.summary);
                        } else {
                            tmp = wac2_utils.matchOptionString(inner._list, "summary", _filter.summary);
                            valid_tmp = true;
                        }
                    }
                    if (_filter.description !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionString(tmp, "description", _filter.description);
                        } else {
                            tmp = wac2_utils.matchOptionString(inner._list, "description", _filter.description);
                            valid_tmp = true;
                        }
                    }
                    if (_filter.status !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionShortArray(tmp, "status", _filter.status);
                        } else {
                            tmp = wac2_utils.matchOptionShortArray(inner._list, "status", _filter.status);
                            valid_tmp = true;
                        }
                    }
                    if (_filter.priority !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionShortArray(tmp, "priority", _filter.priority);
                        } else {
                            tmp = wac2_utils.matchOptionShortArray(inner._list, "priority", _filter.priority);
                            valid_tmp = true;
                        }
                    }
                    if (_filter.initialDueDate !== undefined ||
                        _filter.endDueDate !== undefined) {
                        if (valid_tmp) {
                            tmp = wac2_utils.matchOptionDate(tmp, "dueDate", _filter.initialDueDate, _filter.endDueDate);
                        } else {
                            tmp = wac2_utils.matchOptionDate(inner._list, "dueDate", _filter.initialDueDate, _filter.endDueDate);
                            valid_tmp = true;
                        }
                    }

                    if (valid_tmp) {
                        for (i = 0; i < tmp.length; i++) {
                            rst.push(new Task(tmp[i], _ID_FROM_PROP));
                        } 
                    } else {
                        for (e in inner._list) {
                            rst.push(new Task(inner._list[e], _ID_FROM_PROP));
                        }
                    }
                    onSuccess(rst);
                });
                return ret;
            }

            return wac2_utils.validateTypeMismatch(onSuccess, onError, "findTasks", _findTasks);
        };
    }

    this.getTaskLists = function (onSuccess, onError) {
        function _getTaskLists() {
            var ret;
            ret = _pendingOperate(function () {
                if (_taskListArray.length === 0) {
                    _taskListArray = _get();
                }
                onSuccess(_taskListArray);
            }, 1);
            return ret;
        }

        return wac2_utils.validateTypeMismatch(onSuccess, onError, "getTaskLists", _getTaskLists);
    };

    this.__defineGetter__("SIM_TASK_LIST", function () {
        return 0;
    });
    this.__defineGetter__("DEVICE_TASK_LIST", function () {
        return 1;
    });
    this.__defineGetter__("HIGH_PRIORITY", function () {
        return 0;
    });
    this.__defineGetter__("MEDIUM_PRIORITY", function () {
        return 1;
    });
    this.__defineGetter__("LOW_PRIORITY", function () {
        return 2;
    });
    this.__defineGetter__("STATUS_COMPLETED", function () {
        return 0;
    });
    this.__defineGetter__("STATUS_NEEDS_ACTION", function () {
        return 1;
    });
    this.__defineGetter__("STATUS_IN_PROCESS", function () {
        return 2;
    });
    this.__defineGetter__("STATUS_CANCELLED", function () {
        return 3;
    });

    this.handleSubFeatures = function (subFeatures) {
        if (wac2_utils.isEmptyObject(subFeatures) ||
            subFeatures["http://wacapps.net/api/pim.task"] ||
            (subFeatures["http://wacapps.net/api/pim.task.read"] &&
            subFeatures["http://wacapps.net/api/pim.task.write"])) {
            return;
        }
        if (subFeatures["http://wacapps.net/api/pim.task.read"] &&
           !subFeatures["http://wacapps.net/api/pim.task.write"]) {
            _addTaskAllowed = false;
            _deleteTaskAllowed = false;
            _updateTaskAllowed = false;
            return;
        }
        if (subFeatures["http://wacapps.net/api/pim.task.write"] &&
           !subFeatures["http://wacapps.net/api/pim.task.read"]) {
            _findTasksAllowed = false;
            return;
        }
        _console.warn("WAC-2.0-Task-handleSubFeatures: something wrong");
    };

};


});
define('ripple/platform/wac/2.0/wac2_utils', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var utils = require('ripple/utils'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror');

module.exports = {
    _wac2_regexSanitize: function (regexString) {
        var escapePattern = /([^\\]|^)(%)/g, percentPattern = /\\%/g;
        return regexString.replace("^", "\\^")
                .replace("$", "\\$")
                .replace("(", "\\(")
                .replace(")", "\\)")
                .replace("<", "\\<")
                .replace("[", "\\[")
                .replace("{", "\\{")
                .replace(/\\([^%])/, "\\\\$1")    /* don't replace \\% */
                .replace("|", "\\|")
                .replace(">", "\\>")
                .replace(".", "\\.")
                .replace("*", "\\*")
                .replace("+", "\\+")
                .replace("?", "\\?")
                .replace(escapePattern, "$1.*")  /* replace % with .* */
                .replace(percentPattern, "%");   /* strip excape of % */ 
    }, 

    isValidDate: function (d) {
        if (Object.prototype.toString.call(d) !== "[object Date]")
            return false;
        return !isNaN(d.getTime());
    },

    isValidArray: function (a) {
        return (Object.prototype.toString.call(a) === "[object Array]");
    },
    
    matchOptionArrayString: function (src, attr, pattern) {
        /* src.obj[attr] is a StringArray */
        var _pattern, re, _stringMatch;
        _pattern = this._wac2_regexSanitize(pattern); 
        re = new RegExp("^" + _pattern + "$", "i");

        _stringMatch = function (obj, index) {
            if (pattern.search(/^%*$/i) === 0) 
                return true;
            if (obj[attr] === undefined || obj[attr] === null)
                return false;
            return obj[attr].some(function (f) {
                return f.search(re) !== -1;
            });
        };
        return utils.filter(src, _stringMatch);
    },

    matchOptionString: function (src, attr, pattern) {
        /* src.obj[attr] is a string */
        var _stringMatch, _pattern, _re;
        _pattern = this._wac2_regexSanitize(pattern); 
        _re = new RegExp("^" + _pattern + "$", "mi");

        _stringMatch = function (obj, index) {
            return (obj[attr].search(_re) !== -1);
        };
        return utils.filter(src, _stringMatch);
    },

    matchOptionDate: function (src, attr, filterStart, filterEnd) {
        var _dateMatch;
        _dateMatch = function (obj, index) {
            var matched = true, valueDate = obj[attr];
    
            if (filterStart !== undefined && filterStart !== null) {
                matched = (valueDate.getTime() >= filterStart.getTime());
            }
            if (matched && (filterEnd !== undefined && filterEnd !== null)) {
                matched = (valueDate.getTime() <= filterEnd.getTime());
            }
            return matched;
        };
        return utils.filter(src, _dateMatch);
    },

    matchOptionShortArray: function (src, attr, filterArray) {
        /* src.obj[attr] is a short, filterArray is an array 
           i.e. find status is [CONFRIMED or TENTATIVE] */
        var arraySome = function (obj, index) {
            return filterArray.some(function (f) {
                return f === obj[attr];  
            });
        };
        return utils.filter(src, arraySome);
    },

    validateTypeMismatch: function (onSuccess, onError, name, callback) {
        if (onSuccess) {
            utils.validateArgumentType(onSuccess, "function", null,
                                       name + " invalid successCallback parameter",
                                       new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (onError) {
            utils.validateArgumentType(onError, "function", null,
                                       name + " invalid errorCallback parameter",
                                       new DeviceApiError(errorcode.TYPE_MISMATCH_ERR));
        }

        if (onSuccess) {
            return callback && callback();
        } else {
            if (onError) {
                setTimeout(function () {
                    onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                }, 1);
            }
        }
        return undefined;
    },

    isEmptyObject: function (obj) {
        var prop;

        for (prop in obj) {
            return false;
        }
        return true;
    }
};


});
define('ripple/platform/wac/2.0/dbfs', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* We know the dbfs is not an accurate simulation of WAC 2.0 filesystem.
 *
 * 1) We have tried W3C File API, as some of WAC filesystem APIs are synchronous, 
 * it is impossible to simulate them by using the asynchronous API in the main
 * UI thread and although we could use synchronous W3C API in a worker, it is
 * not reasonable to limit WAC filesystem API usage in a worker.
 *
 * 2) The problem is partially solved by using database to simulate the filesystem,
 * For the asynchronous aspect, actually all the files are read into memory (cache 
 * object in this file) and the cache operation is synchronous. It is not perfect.
 * And the database has 5MB limitation when running in Chrome.
 *
 * In the future, we might use ajax or NPAPI to get a better simulation.
 */

/* Note: The entry object is shared between this module and filesystem */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    _console = require('ripple/console'),
    _cache = {},
    _self;

function _get(path) {
    return path.replace(/^\//, '').split("/").reduce(function (obj, token) {
        return token === "" ? obj : (obj.children ? obj.children[token] || null : null);
    }, _cache);
}

function _getInfo(path) {
    var parent = ("/" + path.replace(/^\//, '').replace(/\/$/, '')).split("/"),
        name = parent.splice(parent.length - 1, 1).join("");

    return {
        name: name,
        parent: parent.join("/") || "/"
    };
}

function _set(path, obj) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    parent.children = parent.children || {};
    parent.children[child] = obj;
}

function _delete(path) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    delete parent.children[child];
}

function _save() {
    db.saveObject("wac2-db-filesystem", _cache);
}

function _walk(path, parent) { 
    _self.ls(path, function (entries) { 
        parent.children = parent.children || {}; 

        entries.forEach(function (entry) { 
            parent.children[entry.name] = entry; 

            if (entry.isDirectory) { 
                _walk(entry.fullPath, entry); 
            } else { 
                /* after getting Date out of DB, Date will become 
                   a string, so need to recast it back to Date */
                if (entry.lastModifiedDate !== null && entry.lastModifiedDate !== undefined)
                    entry.lastModifiedDate = new Date(entry.lastModifiedDate);

                _self.read(entry.fullPath, function (data) { 
                    parent.children[entry.name].data = data; 
                }, function (e) { 
                    _console.error(e); 
                }); 
            } 
        }); 
    }, function (e) { 
        _console.error(e); 
    }); 
} 
 
function _createPath(path) { 
    var parts = path.replace(/^\//, '').split("/"), 
        workflow = jWorkflow.order(); 
 
    parts.forEach(function (part, index) { 
        var dir = "/" + utils.copy(parts).splice(0, index + 1).join("/"); 
 
        workflow.andThen(function (prev, baton) { 
            baton.take(); 
            _self.mkdir(dir, baton.pass, baton.pass); 
        }); 
    }); 
 
    workflow.start(); 
}

_self = {
    // The order is consistent with _virtualRoots in filesystem.js
    roots: ["/opt/documents", "/opt/images", "/opt/music", "/opt/videos", "/opt/downloads", "/home/user/appdata/simulatedapp/wgt-package", "/home/user/appdata/simulatedapp/wgt-private", "/home/user/appdata/simulatedapp/wgt-private-tmp", "/SDCard", "/opt/attachments"],
    initialize: function () {
        // TODO: Initialize at bootstrap and emulatorBridge.link 
        _cache = db.retrieveObject("wac2-db-filesystem") || {};
        // create real root paths if empty
        _self.roots.every(function (root) {
            _createPath(root);
            return true;
        }); 
       // build the file system cache so that we could access information synchronously
        _walk("/", _cache);
    },
    ls: function (path, success, error) {
        try {
            var dir = _get(path),
                items = [];

            if (dir) {
                utils.forEach(dir.children, function (item) {
                    items.push(item);
                });
            }
            else {
                items = {};
            }

            success(items);
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },
    rm: function (path, success, error, options) {
        _delete(path);
        _save();
        success();
    },
    rmdir: function (path, success, error, options) {
        _delete(path);
        _save();
        success();
    },
    mkdir: function (path, success, error) {
        var entry = _get(path),
            info = _getInfo(path);

        if (!entry) {
            _set(path, {
                name: info.name,
                isDirectory: true,
                fullPath: path
            });
            entry = _get(path);
            _save();
        }
        
        if (entry) {
            success(entry);
        }
        else {
            error({code: 1});
        }
    },
    mv: function (from, to, success, error) {
        try {
            var fromEntry = _get(from),
                toInfo = _getInfo(to);

            fromEntry.fullPath = to;
            fromEntry.name = toInfo.name;

            _set(to, fromEntry);
            _delete(from);
            _save();
            success();
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },
    touch: function (path, success, error) {
        var entry = _get(path),
            info  = _getInfo(path);

        if (!entry) {
            _set(path, {
                lastModifiedDate: new Date(),
                name: info.name,
                isDirectory: false,
                fullPath: path,
                data: ""
            });
            entry = _get(path);
        }
        _save();
        success(entry);
    },
    cp: function (from, to, success, error) {
        try {
            var fromEntry = _get(from),
                copied = utils.copy(fromEntry);

            copied.name  = _getInfo(to).name;
            copied.fullPath = to;
            _set(to, copied);
            _save();
            success();
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },
    stat: function (path, success, error) {
        var entry = _get(path);
        
        if (entry) {
            success(entry);
        } else {
            error({code: 1});
        }
    },
    write: function (path, contents, success, error, options) {
        var entry = _get(path);

        if (entry) {
            entry.lastModifiedDate = new Date();
            entry.data = contents;
            _save();
            success();
        } else {
            error({code: 1});
        }

    },
    read: function (path, success, error) {
        var entry = _get(path);

        if (entry) {
            success(utils.copy(entry.data));
        }
        else {
            error({code: 1});
        }
    }
};

module.exports = _self;


});
define('ripple/platform/wac/2.0/deviceinteraction', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    PendingOperation = require('ripple/platform/wac/2.0/pendingoperation'),
    PendingObject = require('ripple/platform/wac/2.0/pendingObject'),
    DeviceApiError = require('ripple/platform/wac/2.0/deviceapierror'),
    errorcode = require('ripple/platform/wac/2.0/errorcode'),
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    deviceSettings = require('ripple/deviceSettings'),
    wac2_utils = require('ripple/platform/wac/2.0/wac2_utils'),
    _self,
    NOTIFY_DURATION_LIMIT = 5000;

function pendingOperation(f) {
    var _FAKEWAITTIME = 0,
        pendingObj;
    
    if (_FAKEWAITTIME === 0) {
        f();
        return undefined;
    }
    else {
        pendingObj = new PendingObject();
        pendingObj.pendingID = setTimeout(function () {
            pendingObj.setCancelFlag(false);
            f();
        }, _FAKEWAITTIME);
        return new PendingOperation(pendingObj);
    }
}

function checkDuration(duration) {
    if (duration) {
        duration = duration | 0;  
        if (duration <= 0 || duration > NOTIFY_DURATION_LIMIT) {
            return NOTIFY_DURATION_LIMIT;
        } else {
            return duration;
        }
    } else {
        return NOTIFY_DURATION_LIMIT;
    }
}

function isMute() {
    return deviceSettings.retrieve("Config.soundVolume") <= 0;
}

function isInVibrateMode() {
    return deviceSettings.retrieve("Config.vibratingMode");
}

function isBacklightOn() {
    return deviceSettings.retrieve("Config.backlight");
}

var vibrator = (function () {
    var isVibrating = false,
        terminateAfterPattern = false,
        pattern = null,
        pulseIndex = 0,
        vibrateTimeout = null,
        terminateTimeout = null,
        MILLILSECONDS_OF_ONE_VIBRATION = 100,
        node = jQuery("#" + constants.COMMON.DEVICE_CONTAINER),
        movementIndex = 0,
        movement = [{ left: -10 }, { left: 0 }, { left: 10 }, { left: 0 },
             {top: -10 }, { top: 0 }, {top: 10 }, { top: 0 }];

    function _clearTimeout() {
        if (vibrateTimeout) {
            clearInterval(vibrateTimeout);
            vibrateTimeout = null;        
        }
        if (terminateTimeout) {
            clearTimeout(terminateTimeout);
            terminateTimeout = null;        
        }
    }  
    
    function stopVibrate() {
        isVibrating = false;
        _clearTimeout();
        node.css({left: 0, top: 0}, MILLILSECONDS_OF_ONE_VIBRATION);
    }
    
    function vibrate() {
        //node.animate(movement[movementIndex], MILLILSECONDS_OF_ONE_VIBRATION);
        node.css(movement[movementIndex]);
        movementIndex = (movementIndex + 1) % 8;
    }
    
    function changePulse() {
        //pattern != null
        var pulse = pattern[pulseIndex];
        if (pulse === '.') vibrate();
        ++pulseIndex;
        if (pulseIndex >= pattern.length) {
            if (terminateAfterPattern) {
                setTimeout(stopVibrate, 1);
                return;
            }
            pulseIndex = 0;
        }
    }
    
    function terminateVibrate() {
        terminateAfterPattern = true;
        terminateTimeout = null;
        if (pattern === null) {
            stopVibrate();        
        }
    }  
  
    function startVibrate(duration, _pattern) {
        if (!isInVibrateMode()) return;
        _clearTimeout();
        terminateAfterPattern = false;
        movementIndex = 0;
        
        if (_pattern) {
            pattern = _pattern;
            pulseIndex = 0;
            vibrateTimeout = setInterval(changePulse, MILLILSECONDS_OF_ONE_VIBRATION);
            if (duration) 
                terminateAfterPattern = false;
            else 
                terminateAfterPattern = true;
        } else {
            pattern = null;
            vibrateTimeout = setInterval(vibrate, MILLILSECONDS_OF_ONE_VIBRATION);
        }
        terminateTimeout = setTimeout(terminateVibrate, checkDuration(duration));        
        isVibrating = true;
    }

    event.on("VibratingModeChanged", function (value) {
        if (value === false) {
            stopVibrate();
        }
    });

    return {
        startVibrate: startVibrate,
        stopVibrate: stopVibrate
    };
}()); //jslint style

var backlight = (function () {
    var timeout = null,
        isNotifying = false,
        node = jQuery("#" + constants.COMMON.VIEWPORT_CONTAINER);
        
    function _clearTimeout() {
        if (timeout) {
            clearTimeout(timeout); 
            timeout = null;
        }
    }
    
    function _switch(on) {
        node.css('opacity', on ? '':'0.4');
    }
    
    function switchOff() {
        if (!isNotifying) return;
        _clearTimeout();
        _switch(false);
        isNotifying = false;
    }
    
    function switchOn(duration) {
        if (isBacklightOn()) return;
        _clearTimeout();
        _switch(true);
        timeout = setTimeout(switchOff, checkDuration(duration));
        isNotifying = true;
    }

    _switch(isBacklightOn());
    event.on("BacklightChanged", function (value) {
        _clearTimeout();
        isNotifying = false;
        _switch(value);
    });

    return {
        switchOn  : switchOn,
        switchOff : switchOff
    };
}()); //jslint style

var beeper = (function () {
    var isBeeping = false,
        timeout = null,
        beepFile = "beep.wav", //TODO: license issues
        errorHandler = null,
        _beeper = utils.createElement("audio", {"id": "notify-beeper"});
        
    document.getElementById("ui").appendChild(_beeper);
    _beeper.setAttribute("src", beepFile);
    _beeper.setAttribute("loop", "true");
    _beeper.load();
    
    function _clearTimeout() {
        if (timeout) {
            clearTimeout(timeout);
            timeout = false;
        }
    }
    
    function raiseError() {
        if (errorHandler) {
            setTimeout(function () {
                errorHandler(new DeviceApiError(errorcode.UNKNOWN_ERR));
            }, 1);
        }
    }
    
    function stopBeep() {
        _clearTimeout();
        if (isBeeping) {
            try {
                _beeper.pause();
            } catch (e) {}
            isBeeping = false;
        }
    }
    
    _beeper.addEventListener('error', function () {
        stopBeep();
        raiseError();
    });
   
    function startBeep(onSuccess, onError, duration) {
        errorHandler = onError;
        try {
            stopBeep();
            _beeper.currentTime = 0;
            _beeper.play();
            isBeeping = true;
            timeout = setTimeout(stopBeep, checkDuration(duration));
            setTimeout(function () {
                onSuccess();
            }, 1);
        }catch (e) {
            raiseError();
        }
    }
    
    event.on("VolumeChanged", function (value) {
        value = value | 0;
        if (value < 0) value = 0;
        else if (value > 100) value = 100;       
        _beeper.volume = value / 100.0;
    });
    
    return {
        startBeep : startBeep,
        stopBeep  : stopBeep
    };
}()); //jslint style

module.exports = _self = {

    startNotify : function (onSuccess, onError, duration) {
        return wac2_utils.validateTypeMismatch(onSuccess, onError, "startNotify", function () {
            if (!isMute()) {
                return pendingOperation(function () {
                    beeper.startBeep(onSuccess, onError, duration);
                });
            } else if (isInVibrateMode()) {
                return _self.startVibrate(onSuccess, onError, duration);
            } else {
                return _self.lightOn(onSuccess, onError, duration);
            }
        });
    },

    stopNotify : function () {
        beeper.stopBeep();
        vibrator.stopVibrate();
        backlight.switchOff();
    },

    startVibrate : function (onSuccess, onError, duration, pattern) {       
        return wac2_utils.validateTypeMismatch(onSuccess, onError, "startVibrate", function () {
            if (pattern) {
                pattern = String(pattern);
                if (!pattern.match(/[\._]{1,10}/)) {
                    if (onError) {
                        setTimeout(function () {
                            onError(new DeviceApiError(errorcode.INVALID_VALUES_ERR));
                        }, 1);
                    }
                    return undefined;
                }   
            }
            
            if (!isInVibrateMode()) {
                if (onError) {
                    setTimeout(function () {
                        onError(new DeviceApiError(errorcode.UNKNOWN_ERR));
                    }, 1);
                }
                return undefined;          
            }
  
            setTimeout(function () {
                onSuccess();
            }, 1);
            return pendingOperation(function () {
                vibrator.startVibrate(duration, pattern);
            });

        });
    },
    
    stopVibrate : function () {
        vibrator.stopVibrate();
    },

    lightOn : function (onSuccess, onError, duration) {
        return wac2_utils.validateTypeMismatch(onSuccess, onError, "lightOn", function () {
            if (isBacklightOn()) {
                if (onError) {
                    setTimeout(function () {
                        onError(new DeviceApiError(errorcode.UNKNOWN_ERR));
                    }, 1);
                }
                return undefined;               
            }
        
            setTimeout(function () {
                onSuccess();
            }, 1);
            return pendingOperation(function () {
                backlight.switchOn(duration);
            });
        });
    },

    lightOff : function () {
        backlight.switchOff();
    },

    setWallpaper : function (onSuccess, onError, fileName) {
        //TODO: file name, existance, extension checking.
        return wac2_utils.validateTypeMismatch(onSuccess, onError, "setWallpaper", function () {
            return pendingOperation(function () {
                notifications.openNotification("normal", "setWallpaper:" + fileName);
                setTimeout(function () {
                    onSuccess();
                }, 1);
            });
        });
    }
};


});
define('ripple/platform/wac/2.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

function deviceStatusEventTrigger(setting) {
    event.trigger("DeviceStatusChanged", [setting]);
}

module.exports = {
    "Config": {
        "vibratingMode": {
            "name": "Vibrator",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("VibratingModeChanged", [setting]);
            }
        },
        "soundVolume": {
            "name": "Sound Volume",
            "control": {
                "type": "range",
                "value": 100,
                "min": 0,
                "max": 100
            },
            "callback": function (setting) {
                event.trigger("VolumeChanged", [setting]);
            }
        },
        "backlight": {
            "name": "Backlight",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("BacklightChanged", [setting]);
            }
        }
    },
    "Battery": {
        "batteryLevel": {
            "name": "Battery Remaining %",
            "control": {
                "type": "select",
                "value": 100
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i += 10) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "event": "BatteryLevelChanged",
            "callback": function (setting) {
                event.trigger("BatteryLevelChanged", [setting]);
            }
        },

        "batteryBeingCharged": {
            "name": "Battery Is Charging",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "BatteryBeingChargedChanged",
            "callback": function (setting) {
                event.trigger("BatteryBeingChargedChanged", [setting]);
            }
        },
    },
    "CellularHardware": {
        "status": {
            "name": "status",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "CellularHardwareStatusChanged",
            "callback": function (setting) {
                event.trigger("CellularHardwareStatusChanged", [setting]);
            }
        }
    },
    "CellularNetwork": {
        "isInRoaming": {
            "name": "Roaming",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "CellularNetworkIsInRoamingChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkIsInRoamingChanged", [setting]);
            }
        }, 
        "mcc": {
            "name": "mcc",
            "control": {
                "type": "text",
                "value": "460",
                "readonly": "readonly"
            }
        }, 
        "mnc": {
            "name": "mnc",
            "control": {
                "type": "text",
                "value": "0",
                "readonly": "readonly"
            }
        }, 
        "signalStrength": {
            "name": "Signal Strength",
            "control": {
                "type": "select",
                "value": 100
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i += 10) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "event": "CellularNetworkSignalStrengthChanged",
            "callback": function (setting) {
                event.trigger("CellularNetworkSignalStrengthChanged", [setting]);
            }
        }, 
        "operatorName": {
            "name": "Operator Name",
            "control": {
                "type": "text",
                "value": "CMCC",
                "readonly": "readonly"
            }
        }
    },
    "Device": {
        "imei": {
            "name": "IMEI",
            "control": {
                "type": "text",
                "value": "860398001689659",
                "readonly": "readonly"
            }
        }, 
        "model": {
            "name": "Model",
            "control": {
                "type": "text",
                "value": "",
                "readonly": "readonly"
            }
        }, 
        "version": {
            "name": "Version",
            "control": {
                "type": "text",
                "value": "",
                "readonly": "readonly"
            }
        }, 
        "vendor": {
            "name": "Vendor.",
            "control": {
                "type": "text",
                "value": "",
                "readonly": "readonly"
            }
        }
    },
    "Display": {
        "resolutionHeight": {
            "name": "Resolution Height",
            "control": {
                "type": "number",
                "value": 0,
                "readonly": "readonly"
            }
        }, 
        "resolutionWidth": {
            "name": "Resolution Width",
            "control": {
                "type": "number",
                "value": 0,
                "readonly": "readonly"
            }
        }, 
        "pixelAspectRatio": {
            "name": "Pixel Aspectratio",
            "control": {
                "type": "number",
                "value": 0,
                "readonly": "readonly"
            }
        }, 
        "dpiY": {
            "name": "DPI-Y",
            "control": {
                "type": "number",
                "value": 0,
                "readonly": "readonly"
            }
        },         
        "dpiX": {
            "name": "DPI-X",
            "control": {
                "type": "number",
                "value": 0,
                "readonly": "readonly"
            }
        }, 
        "colorDepth": {
            "name": "Color Depth",
            "control": {
                "type": "number",
                "value": 32,
                "readonly": "readonly"
            }
        }
    },
    "MemoryUnit": {
        "removable": {
            "name": "Removable",
            "control": {
                "type": "checkbox",
                "value": true,
                "readonly": "readonly"
            }
        },
        "size": {
            "name": "Total Memory",
            "control": {
                "type": "number",
                "value": 262144,
                "readonly": "readonly"
            }
        },        
        "availableSize": {
            "name": "Available Size",
            "control": {
                "type": "range",
                "value": 16384,
                "min": 0,
                "max": 262144
            },
            "event": "MemoryUnitAvailableSizeChanged",
            "callback": function (setting) {
                event.trigger("MemoryUnitAvailableSizeChanged", [setting]);
            }
        }
    },
    "OperatingSystem": {
        "language": {
            "name": "Language",
            "control": {
                "type": "text",
                "value": "English",
                "readonly": "readonly"
            }
        }, 
        "version": {
            "name": "Version",
            "control": {
                "type": "text",
                "value": "",
                "readonly": "readonly"
            }
        }, 
        "name": {
            "name": "Name",
            "control": {
                "type": "text",
                "value": "",
                "readonly": "readonly"
            }
        }, 
        "vendor": {
            "name": "Vendor",
            "control": {
                "type": "text",
                "value": "",
                "readonly": "readonly"
            }
        }
    },
    "WebRuntime": {
        "wacVersion": {
            "name": "WAC Version",
            "control": {
                "type": "text",
                "value": "2.0",
                "readonly": "readonly"
            }
        }, 
        "supportedImageFormats": {
            "name": "Image Formats",
            "control": {
                "type": "text",
                "value": "gif87, gif89, png, jpeg",
                "readonly": "readonly"
            },
            "event": "WebRuntimeSupportedImageFormatsChanged",
            "callback": function (setting) {
                event.trigger("WebRuntimeSupportedImageFormatsChanged", [setting]);
            }
        }, 
        "version": {
            "name": "Web Runtime Version",
            "control": {
                "type": "text",
                "value": "1.0",
                "readonly": "readonly"
            }
        }, 
        "name": {
            "name": "Web Runtime Name",
            "control": {
                "type": "text",
                "value": "Tizen Web Simulator",
                "readonly": "readonly"
            }
        }, 
        "vendor": {
            "name": "Vendor Name",
            "control": {
                "type": "text",
                "value": "Tizen SDK team",
                "readonly": "readonly"
            }
        }
    },
    "WiFiHardware": {
        "status": {
            "name": "Status",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "WiFiHardwareStatusChanged",
            "callback": function (setting) {
                event.trigger("WiFiHardwareStatusChanged", [setting]);
            }
        }
    },
    "WiFiNetwork": {
        "ssid": {
            "name": "SSID",
            "control": {
                "type": "text",
                "value": "OfficeWLAN"
            },
            "event": "WiFiHardwareSsidChanged",
            "callback": function (setting) {
                event.trigger("WiFiHardwareSsidChanged", [setting]);
            }
        }, 
        "signalStrength": {
            "name": "Signal Strength",
            "control": {
                "type": "select",
                "value": 10
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 10; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "event": "WiFiHardwareSignalStrengthChanged",
            "callback": function (setting) {
                event.trigger("WiFiHardwareSignalStrengthChanged", [setting]);
            }
        }, 
        "networkStatus": {
            "name": "Network Status",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "event": "WiFiHardwareNetworkStatusChanged",
            "callback": function (setting) {
                event.trigger("WiFiHardwareNetworkStatusChanged", [setting]);
            }
        }
    }
};


});
define('ripple/platform/wac/2.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        "messaging",
        "geoView",
        "widgetConfig",
        "deviceSettings"
    ]
};

});
define('ripple/platform/wac/2.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var platform = require('ripple/platform'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    constants = require('ripple/constants');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (configValidationObject) {
        var valid = true;
        // no xmlns:JIL in wac 2.0 spec
        valid = !!configValidationObject.widget.validationResult[0].attributes.xmlns.valid;

        return valid;
    },
    extractInfo: function (configValidationObject) {
        if (!configValidationObject) {
            return null;
        }

        var widgetInfo = {},
            configFeatures,
            configPreferences,
            preferenceName,
            platform;

        widgetInfo.id = configValidationObject.widget.validationResult[0].attributes.id.value || "";
        widgetInfo.name = configValidationObject.widget.children.name.validationResult[0].value;
        widgetInfo.icon = configValidationObject.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = configValidationObject.widget.validationResult[0].attributes.version.value;

        widgetInfo.features = {};

        configFeatures = configValidationObject.widget.children.feature.validationResult;
        utils.forEach(configFeatures, function (f) {
            if (f.valid === true) {
                var feature = {id: f.attributes.name.value,
                         required: f.attributes.required.valid};
                widgetInfo.features[feature.id] = feature;
            }
        });

        widgetInfo.preferences = {};

        configPreferences = configValidationObject.widget.children.preference.validationResult;

        platform = require('ripple/platform');
        utils.forEach(configPreferences, function (preference) {
            preferenceName = preference.attributes.name.value;
            if (preferenceName) {
                widgetInfo.preferences[preferenceName] = {
                    "key": preferenceName,
                    "value": preference.attributes.value.value || "",
                    "readonly": preference.attributes.readonly.value === "true"
                };

                db.save(preferenceName,
                        widgetInfo.preferences[preferenceName].value,
                        platform.getPersistencePrefix(widgetInfo.id));
            }
        });

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            helpText: "\"widget\" element describes widget information in configuration documents and serves as a container for other elements. It must be used in configuration document and may have following child elments: name,description,icon,author,license,content,feature and preference. \"widget\" element MAY have following attributes: id,version,height,width, defaultlocale, xml:lang and dir",
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                },
                dir: {
                    attributeName: "dir",
                    required: false,
                    type: "list",
                    listValues: ["ltr", "rtl", "lro", "rlo"]
                },
                id: {
                    attributeName: "id",
                    required: false,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    required: false,
                    type: "string"
                },
                height: {
                    attributeName: "height",
                    required: false,
                    type: "integer"
                },
                width: {
                    attributeName: "width",
                    required: false,
                    type: "integer"
                },
                viewmodes: {
                    attributeName: "viewmodes",
                    required: false,
                    type: "list",
                    listValues: ["windowed", "floating", "fullscreen", "maximized", "minimized"]
                },
                defaultlocale: {
                    attributeName: "defaultlocale",
                    required: false,
                    type: "iso-language"
                },
            },
            children: {
                name: {
                    nodeName: "name",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                            unique: true
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        "short": {
                            attributeName: "short",
                            required: false,
                            type: "string"
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                            unique: true
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        href: {
                            attributeName: "href",
                            required: false,
                            type: "regex",
                            regex: constants.REGEX.URL
                        },
                        email: {
                            attributeName: "email",
                            required: false,
                            type: "regex",
                            regex: constants.REGEX.EMAIL
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        }
                    },
                    children: {
                        span: {
                            nodeName: "span",
                            required: false,
                            type: "string",
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                    unique: true
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                }
                            }
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        src: {
                            attributeName: "src",
                            required: true,
                            type: "string"
                        },
                        width: {
                            attributeName: "width",
                            required: false,
                            type: "integer"
                        },
                        height: {
                            attributeName: "height",
                            required: false,
                            type: "integer"
                        }
                    }
                },
                content: {
                    nodeName: "content",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                            unique: true
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        src: {
                            attributeName: "src",
                            required: true,
                            type: "string"
                        },
                        encoding: {
                            attributeName: "encoding",
                            required: false,
                            type: "string"
                        },
                        type: {
                            attributeName: "type",
                            required: false,
                            type: "string"
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        name: {
                            attributeName: "name",
                            required: true,
                            type: "list",
                            listValues: ["http://www.w3.org/TR/geolocation-API/",
                                            "http://wacapps.net/api/deviceapis", "http://wacapps.net/api/accelerometer",
                                            "http://wacapps.net/api/orientation", "http://wacapps.net/api/camera",
                                            "http://wacapps.net/api/camera.show", "http://wacapps.net/api/camera.capture",
                                            "http://wacapps.net/api/devicestatus", "http://wacapps.net/api/devicestatus.deviceinfo",
                                            "http://wacapps.net/api/devicestatus.networkinfo", "http://wacapps.net/api/filesystem",
                                            "http://wacapps.net/api/filesystem.read", "http://wacapps.net/api/filesystem.write",
                                            "http://wacapps.net/api/messaging", "http://wacapps.net/api/messaging.send", 
                                            "http://wacapps.net/api/messaging.find", "http://wacapps.net/api/messaging.subscribe",
                                            "http://wacapps.net/api/messaging.write", "http://wacapps.net/api/pim.contact",
                                            "http://wacapps.net/api/pim.contact.read", "http://wacapps.net/api/pim.contact.write",
                                            "http://wacapps.net/api/pim.calendar", "http://wacapps.net/api/pim.calendar.read",
                                            "http://wacapps.net/api/pim.calendar.write", "http://wacapps.net/api/pim.task", 
                                            "http://wacapps.net/api/pim.task.read", "http://wacapps.net/api/pim.task.write",
                                            "http://wacapps.net/api/deviceinteraction"]
                        },
                        required: {
                            attributeName: "required",
                            type: "boolean",
                            required: false
                        }
                    },
                    children: {
                        param: {
                            nodeName: "param",
                            required: false,
                            occurrence: 0,
                            attributes: {
                                "xml:lang": {
                                    attributeName: "xml:lang",
                                    required: false,
                                    type: "iso-language",
                                },
                                dir: {
                                    attributeName: "dir",
                                    required: false,
                                    type: "list",
                                    listValues: ["ltr", "rtl", "lro", "rlo"]
                                },
                                name: {
                                    attributeName: "name",
                                    required: true,
                                    type: "string",
                                },
                                value: {
                                    attributeName: "value",
                                    required: true,
                                    type: "string",
                                }
                            }
                        }
                    }
                },
                preference: {
                    nodeName: "preference",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            required: false,
                            type: "iso-language",
                        },
                        dir: {
                            attributeName: "dir",
                            required: false,
                            type: "list",
                            listValues: ["ltr", "rtl", "lro", "rlo"]
                        },
                        name: {
                            attributeName: "name",
                            required: true,
                            type: "string"
                        },
                        value: {
                            type: "string",
                            required: false,
                            attributeName: "value"
                        },
                        readonly: {
                            attributeName: "readonly",
                            type: "boolean",
                            required: false
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/wac/2.0/spec', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {

    id: "wac",
    version: "2.0",
    name: "WAC",

    persistencePrefix: "wac2-",

    config: require('ripple/platform/wac/2.0/spec/config'),
    ui: require('ripple/platform/wac/2.0/spec/ui'),
    device: require('ripple/platform/wac/2.0/spec/device'),

    objects: {
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        navigator: {
            path: "w3c/1.0/navigator",
            children: {
                geolocation: {
                    path: "wac/2.0/geolocation",
                    feature: "http://www.w3.org/TR/geolocation-API/"
                }
            }
        },
        deviceapis: {
            path: "wac/2.0/deviceapis",
            feature: "http://wacapps.net/api/deviceapis",
            /*
             * Before we inject those cloned objects into the simulated application
             * namespace, we will handle the feature requests from config.xml.
             * Especially for:
             * - camera.show, camera.capture
             * - devicestatus.deviceinfo, devicestatus.networkinfo
             * - filesystem.read, filesystem.write
             * - messaging.send, messaging.find, messaging.subscribe, messaging.write
             * - pim
             *  - contact.read, contact.write
             *  - calendar.read, calendar.write
             *  - task.read, task.write
             */
            children: {
                accelerometer: {
                    path: "wac/2.0/accelerometer",
                    feature: "http://wacapps.net/api/accelerometer"
                },
                orientation: {
                    path: "wac/2.0/orientation",
                    feature: "http://wacapps.net/api/orientation"
                },
                camera: {
                    path: "wac/2.0/camera",
                    feature: "http://wacapps.net/api/camera|http://wacapps.net/api/camera.show|http://wacapps.net/api/camera.capture",
                    handleSubfeatures: true
                },
                devicestatus: {
                    path: "wac/2.0/devicestatus",
                    feature: "http://wacapps.net/api/devicestatus|http://wacapps.net/api/devicestatus.deviceinfo|http://wacapps.net/api/devicestatus.networkinfo",
                    handleSubfeatures: true
                },
                filesystem: {
                    path: "wac/2.0/filesystem",
                    feature: "http://wacapps.net/api/filesystem|http://wacapps.net/api/filesystem.read|http://wacapps.net/api/filesystem.write",
                    handleSubfeatures: true
                },
                messaging: {
                    path: "wac/2.0/messaging",
                    feature: "http://wacapps.net/api/messaging|http://wacapps.net/api/messaging.send|http://wacapps.net/api/messaging.find|http://wacapps.net/api/messaging.subscribe|http://wacapps.net/api/messaging.write",
                    handleSubfeatures: true
                },
                pim: {
                    children: {
                        contact: {
                            path: "wac/2.0/contact",
                            feature: "http://wacapps.net/api/pim.contact|http://wacapps.net/api/pim.contact.read|http://wacapps.net/api/pim.contact.write",
                            handleSubfeatures: true
                        },
                        calendar: {
                            path: "wac/2.0/calendar",
                            feature: "http://wacapps.net/api/pim.calendar.write|http://wacapps.net/api/pim.calendar.read|http://wacapps.net/api/pim.calendar",
                            handleSubfeatures: true
                        },
                        task: {
                            path: "wac/2.0/task",
                            feature: "http://wacapps.net/api/pim.task|http://wacapps.net/api/pim.task.read|http://wacapps.net/api/pim.task.write",
                            handleSubfeatures: true
                        }
                    }
                },
                deviceinteraction: {
                    path: "wac/2.0/deviceinteraction",
                    feature: "http://wacapps.net/api/deviceinteraction"
                }
            }
        }
    }
};


});
define('ripple/platform/wac/2.0/pendingoperation', function (require, exports, module) {
/*
 *  Copyright 2011 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function (pendingObj) {
    var pending = true;
    this.cancel = function () {
        if (pending === true) {
            if (typeof (pendingObj.getCancelFlag) === "function" && pendingObj.getCancelFlag() === false) {
                pending = false;
                // this clearTimeout is for the case when a 3rd party is invoked to do the task, and it's finished sooner than the intended timeout. therefore, the 3rd party set CancelFlag false, and this cancel is called before timeout
                clearTimeout(pendingObj.pendingID);
                return false;
            }
            if (typeof (pendingObj.userCancel) === "function") {
                pendingObj.userCancel();
            }
            clearTimeout(pendingObj.pendingID);
            pending = false;
            return true;
        } else {
            return false;
        }
    };
};


});
define('ripple/platform/wac/1.0/PositionInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var geo = require('ripple/geo'),
    event = require('ripple/event'),
    exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    _self = {
        latitude: undefined,
        longitude: undefined,
        altitude: undefined,
        cellID: undefined,
        accuracy: undefined,
        altitudeAccuracy: undefined,
        timeStamp: undefined
    };

utils.forEach(_self, function (value, property) {
    _self.__defineGetter__(property, function () {
        return geo.getPositionInfo()[property];
    });
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/MessageTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    EmailMessage: "email",
    MMSMessage: "mms",
    SMSMessage: "sms"
};

});
define('ripple/platform/wac/1.0/DataNetworkConnectionTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    _self = {
        "BLUETOOTH": undefined,
        "EDGE": undefined,
        "EVDO": undefined,
        "GPRS": undefined,
        "IRDA": undefined,
        "LTE": undefined,
        "ONEXRTT": undefined,
        "WIFI": undefined
    };

utils.forEach(_self, function (value, property) {
    _self.__defineGetter__(property, function () {
        return property;
    });
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/DeviceStateInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    _console = require('ripple/console'),
    geo = require('ripple/geo'),
    event = require('ripple/event'),
    deviceSettings = require('ripple/deviceSettings'),
    PositionInfo = require('ripple/platform/wac/1.0/PositionInfo'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    _self;

event.on("ScreenChangeDimensions", function (width, height) {
    try {
        if (typeof _self.onScreenChangeDimensions === 'function') {
            _self.onScreenChangeDimensions(width, height);
        }
        _console.log("called DeviceStateInfo.onScreenChangeDimensions callback function with width = " + width + " and height = " + height);
    } catch (e) {
        exception.handle(e, false);
    }
});

_self = {
    availableMemory: undefined,
    language: undefined,
    keypadLightOn: undefined,
    backLightOn: undefined,
    processorUtilizationPercent: undefined,
    audioPath: undefined,

    onPositionRetrieved: undefined,

    requestPositionInfo: function (method) {
        utils.validateNumberOfArguments(1, 1, arguments.length,
            ExceptionTypes.INVALID_PARAMETER, "requestPositionInfo invalid number of parameters", new Exception());
        utils.validateArgumentType(method, "string",
            ExceptionTypes.INVALID_PARAMETER, "requestPositionInfo invalid parameter", new Exception());

        if (!(method.match(/gps|agps|cellid/))) {
            exception.raise(ExceptionTypes.INVALID_PARAMETER,
                    "Invalid method, expected (gps, agps or cellid)", Exception);
        }

        if (typeof _self.onPositionRetrieved === "function") {
            var delay = geo.delay * 1000,
                timeout = geo.timeout;
            setTimeout(function () {
                var pos = PositionInfo,
                    errorObj = {};

                if (timeout) {
                    //create
                    utils.forEach(pos, function (val, key) {
                        errorObj[key] = undefined;
                    });
                    pos = errorObj;
                }
                _self.onPositionRetrieved(pos, method);
            }, delay);
        }
    },

    onScreenChangeDimensions: undefined,

    onFlipEvent: undefined
};

_self.__defineGetter__("availableMemory", function () {
    return deviceSettings.retrieveAsInt("DeviceStateInfo.availableMemory");
});

_self.__defineGetter__("language", function () {
    return deviceSettings.retrieve("DeviceStateInfo.language");
});

_self.__defineGetter__("keypadLightOn", function () {
    return deviceSettings.retrieveAsBoolean("DeviceStateInfo.keypadLightOn");
});

_self.__defineGetter__("backLightOn", function () {
    return deviceSettings.retrieveAsBoolean("DeviceStateInfo.backLightOn");
});

_self.__defineGetter__("audioPath", function () {
    return deviceSettings.retrieve("DeviceStateInfo.audioPath");
});

_self.__defineGetter__("processorUtilizationPercent", function () {
    return deviceSettings.retrieve("DeviceStateInfo.processorUtilizationPercent");
});

module.exports = _self;


});
define('ripple/platform/wac/1.0/CallRecord', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function () {
    this.callRecordType = undefined;
    this.callRecordId = undefined;
    this.callRecordAddress = undefined;
    this.callRecordName = undefined;
    this.durationSeconds = undefined;
    this.startTime = undefined;
};

});
define('ripple/platform/wac/1.0/Telephony', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    constants = require('ripple/constants'),
    Device = require('ripple/platform/wac/1.0/Device'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception');


function _throwUnsupportedException(method) {
    exception.raise(ExceptionTypes.UNSUPPORTED, "Method not supported." + (method || ""), new Exception());
}

_self = {

    // Public Callbacks
    onCallEvent: undefined,// function (callType, phoneNumber) { },
    onCallRecordsFound: undefined,// function (callRecords) { };

    // Public Methods
    initiateVoiceCall: function (phoneNumber) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "initiateVoiceCall invalid number of parameters", new Exception());
        //HACK: should this be hardcoded?
        //I am still not even sure this is the correct behaviour
        Device.launchApplication("PHONECALL", phoneNumber);

        if (_self.onCallEvent) {
            //HACK: shouldn't be hardcoded
            //also what should the context be? isn't spec'ed
            _self.onCallEvent.apply(_self, ["outgoing", phoneNumber]);
        }
    },
    getCallRecordCnt: function (callRecordType) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "getCallRecordCnt invalid number of parameters", new Exception());
        var calls = db.retrieveObject(constants.TELEPHONY.CALL_LIST_KEY);

        return utils.sum(calls, function (call) {
            return call.callRecordType === callRecordType;
        });
    },
    getCallRecord: function (callRecordType, id) {
        utils.validateNumberOfArguments(2, 2, arguments.length, ExceptionTypes.INVALID_PARAMETER, "getCallRecord invalid number of parameters", new Exception());
        var calls = db.retrieveObject(constants.TELEPHONY.CALL_LIST_KEY);

        return utils.map(calls, function (call) {
            return call.callRecordType === callRecordType ? call : null;
        }).reduce(function (match, call) {
            return match || call.callRecordId === id || null;
        }, null);
    },
    deleteCallRecord: function (callRecordType, id) {
        utils.validateNumberOfArguments(2, 2, arguments.length, ExceptionTypes.INVALID_PARAMETER, "deleteCallRecord invalid number of parameters", new Exception());
        var calls = db.retrieveObject(constants.TELEPHONY.CALL_LIST_KEY),
            indexToDelete = calls.reduce(function (result, call, index) {
                return call.callRecordType === callRecordType &&
                       call.callRecordId === id ? index : result;
            }, -1);

        if (indexToDelete >= 0) {
            calls.splice(indexToDelete, 1);
            db.saveObject(constants.TELEPHONY.CALL_LIST_KEY, calls);
        }

    },

    deleteAllCallRecords: function (callRecordType) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "deleteAllCallRecords invalid number of parameters", new Exception());
        var calls = db.retrieveObject(constants.TELEPHONY.CALL_LIST_KEY),
            indexesToDelete = calls.reduce(function (result, call, index) {
                if (call.callRecordType === callRecordType) {
                    result.push(index);
                }
                return result;
            }, []);

        utils.forEach(indexesToDelete, function (index) {
            calls.splice(index, 1);
        });

        if (indexesToDelete.length > 0) {
            db.saveObject(constants.TELEPHONY.CALL_LIST_KEY, calls);
        }

    },

    findCallRecords: function (comparisonRecord, startInx, endInx) {
        utils.validateNumberOfArguments(1, 3, arguments.length, ExceptionTypes.INVALID_PARAMETER, "findCallRecords invalid number of parameters", new Exception());
        var calls = db.retrieveObject(constants.TELEPHONY.CALL_LIST_KEY);
        utils.find(comparisonRecord, calls, startInx, endInx, _self.onCallRecordsFound);

    }

};

module.exports = _self;

});
define('ripple/platform/wac/1.0/AccountInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    _self = {
        phoneUserUniqueId: undefined,
        phoneMSISDN: undefined,
        phoneOperatorName: undefined,
        userAccountBalance: undefined,
        userSubscriptionType: undefined
    };

_self.__defineGetter__("phoneUserUniqueId", function () {
    return deviceSettings.retrieve("AccountInfo.phoneUserUniqueId");
});

_self.__defineGetter__("phoneMSISDN", function () {
    return deviceSettings.retrieve("AccountInfo.phoneMSISDN");
});

_self.__defineGetter__("phoneOperatorName", function () {
    return deviceSettings.retrieve("AccountInfo.phoneOperatorName");
});

_self.__defineGetter__("userAccountBalance", function () {
    return deviceSettings.retrieve("AccountInfo.userAccountBalance");
});

_self.__defineGetter__("userSubscriptionType", function () {
    return deviceSettings.retrieve("AccountInfo.userSubscriptionType");
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/CalendarItem', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    db = require('ripple/db'),
    exception = require('ripple/exception'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes');

module.exports = function () {
    this.calendarItemId = undefined;
    this.alarmDate = undefined;
    this.eventStartTime = undefined;
    this.eventEndTime = undefined;
    this.eventName = undefined;
    this.eventNotes = undefined;
    this.alarmed = undefined;

    this.update = function () {
        var events = db.retrieveObject(constants.PIM.CALENDAR_LIST_KEY) || [],
            that = this,
            eventIndex = events.reduce(function (match, value, i) {
                return value.calendarItemId === that.calendarItemId ?
                    i : match;
            }, -1);


        if (eventIndex >= 0) {
            events[eventIndex] = this;
            db.saveObject(constants.PIM.CALENDAR_LIST_KEY, events);
        }
        else {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "Calendar Item not found: " + (this.calendarItemId || ""), new Exception());
        }
    };
};

});
define('ripple/platform/wac/1.0/AccelerometerInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var accelerometer = require('ripple/accelerometer'),
    _self = {};

_self.__defineGetter__("xAxis", function () {
    return accelerometer.getInfo().accelerationIncludingGravity.x;
});

_self.__defineGetter__("yAxis", function () {
    return accelerometer.getInfo(true).accelerationIncludingGravity.y;
});

_self.__defineGetter__("zAxis", function () {
    return accelerometer.getInfo(true).accelerationIncludingGravity.z;
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/MessageFolderTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    DRAFTS: "drafts",
    INBOX: "inbox",
    OUTBOX: "outbox",
    SENTBOX: "sentbox"
};

});
define('ripple/platform/wac/1.0/Config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    deviceSettings = require('ripple/deviceSettings'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    _self = {
        ringtoneVolume: undefined,
        msgRingtoneVolume: undefined,
        vibrationSetting: undefined,

        setDefaultRingtone: function (ringtoneUrl) {
            utils.validateArgumentType(ringtoneUrl, "string", ExceptionTypes.INVALID_PARAMETER, "ringtoneUrl paramter is not a string", new Exception());
            notifications.openNotification("normal", "Setting default ringtone to: " + ringtoneUrl);
        },

        setAsWallpaper: function (wallpaperUrl) {
            utils.validateArgumentType(wallpaperUrl, "string", ExceptionTypes.INVALID_PARAMETER, "wallpaperUrl paramter is not a string", new Exception());
            notifications.openNotification("normal", "Setting wallpaper to: " + wallpaperUrl);
        }
    };

_self.__defineGetter__("ringtoneVolume", function () {
    return deviceSettings.retrieve("Config.ringtoneVolume");
});

_self.__defineGetter__("msgRingtoneVolume", function () {
    return deviceSettings.retrieve("Config.msgRingtoneVolume");
});

_self.__defineGetter__("vibrationSetting", function () {
    return deviceSettings.retrieve("Config.vibrationSetting");
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/Message', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var exception = require('ripple/exception'),
    Attachment = require('ripple/platform/wac/1.0/Attachment'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception');

function _throwUnsupportedException(method) {
    exception.raise(ExceptionTypes.UNSUPPORTED, "Method not supported." + (method || ""), new Exception());
}

module.exports = function () {
    this.messageId = Math.uuid(undefined, 16);
    this.callbackNumber = undefined;
    this.destinationAddress = [];
    this.isRead = undefined;
    this.messagePriority = undefined;
    this.messageType = undefined;
    this.subject = undefined;
    this.body = undefined;
    this.sourceAddress = undefined;
    this.validityPeriodHours = undefined;
    this.time = undefined;
    this.ccAddress = [];
    this.bccAddress = [];
    this.attachments = [];

    this.addAttachment = function (fileFullName) {
        var attachment = new Attachment();
        attachment.fileName = fileFullName;
        this.attachments.push(attachment);
    };
    this.deleteAttachment = function (attachment) {

        for (var i = this.attachments.length - 1; i >= 0; i--) {
            if (this.attachments[i].fileName === attachment.fileName) {
                this.attachments.splice(i, 1);
            }
        }
    };
    this.saveAttachment = function (fileFullName, attachment) {
        _throwUnsupportedException("Widget.Messaging.Message.addAddress");
    };
    this.addAddress = function (type, address) {

        var addresses = address.split(";");

        switch (type) {
        case "destination":
            this.destinationAddress = this.destinationAddress.concat(addresses);
            break;
        case "cc":
            this.ccAddress = this.ccAddress.concat(addresses);
            break;
        case "bcc":
            this.bccAddress = this.bccAddress.concat(addresses);
            break;
        }
    };

    this.deleteAddress = function (type, address) {
        var addresses = address.split(";"),
            filter = function (orig) {
                return orig.filter(function (address) {
                    return !addresses.some(function (x) {
                        return address === x;
                    });
                });
            };

        switch (type) {
        case "destination":
            this.destinationAddress = filter(this.destinationAddress);
            break;
        case "cc":
            this.ccAddress = filter(this.ccAddress);
            break;
        case "bcc":
            this.bccAddress = filter(this.bccAddress);
            break;
        }
    };

};

});
define('ripple/platform/wac/1.0/VideoPlayer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    _console = require('ripple/console'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    fileSystem = require('ripple/fileSystem'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    exception = require('ripple/exception'),
    _currentlySet,
    _currentVideoFile,
    _state = null,
    _loopCount, _video,
    _STATES = {
        "OPENED": "opened",
        "STOPPED": "stopped",
        "PAUSED": "paused",
        "PLAYING": "playing",
        "COMPLETED": "completed"
    };

function _validateVideoType(fileUrl) {
    var matched = fileUrl.match(/\.(\w*)$/),
        maps = {
            "ogv": "ogg",
            "flv": "mp4"
        },
        type = matched ? matched[1] : "";

    if (_video && _video.canPlayType("video/" + (maps[type] || type)) === "") {
        _console.warn("Attempting to load a video that might not work in the current browser [" + fileUrl + "]");
    }
}

function _validateAndSet(state, validStates, callbackBeforeSuccess) {
    var i, valid = false;

    for (i = 0; i < validStates.length; i++) {
        if (validStates[i] === _state) {
            valid = true;
        }
    }

    if (!valid) {
        _console.warn("Attempted to initiate VideoPlayer." + state +
            " in invalid state. current state: " + _state);
    } else {
        if (typeof(callbackBeforeSuccess) === "function") {
            callbackBeforeSuccess.apply();
        }
        event.trigger("MultimediaVideoStateChanged", [state], true);
    }

    return valid;
}

event.on("MultimediaVideoStateChanged", function (state) {
    _state = state;
    if (typeof _self.onStateChange === "function") {
        _self.onStateChange.apply(_self, [state]);
    }
});

_self = module.exports = {
    onStateChange: undefined,

    open: function (fileUrl) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER,
           "VideoPlayer.open invalid number of arguments", new Exception());
        utils.validateArgumentType(fileUrl, "string", ExceptionTypes.INVALID_PARAMETER,
           "VideoPlayer.open expected valid fileUrl but got ->" + fileUrl, new Exception());

        if (!_video) {
            return;
        }

        _validateAndSet(_STATES.OPENED, [_STATES.OPENED, _STATES.STOPPED, _STATES.COMPLETED, null], function () {
            _validateVideoType(fileUrl);
            _currentVideoFile = fileSystem.getURI(fileUrl);
            _video.setAttribute("src", _currentVideoFile);
            _video.setAttribute("width", "100%");
            _video.addEventListener("ended", function () {
                event.trigger("MultimediaVideoStateChanged", [_STATES.COMPLETED], true);
                if (_loopCount > 1) {
                    _self.open(_currentVideoFile);
                    _self.play(_loopCount--);
                }
            }, false);
        });
    },

    setWindow: function (domObject) {
        utils.validateNumberOfArguments(0, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER,
           "VideoPlayer.setWindow invalid number of arguments", new Exception());

        if (_currentlySet) {
            _currentlySet.removeChild(_video);
            _currentlySet = null;
            _video = null;
        }

        if (domObject !== null) {
            _video = utils.createElement("video", {
                "id": "multimedia-video"
            });
            domObject.appendChild(_video);
            _currentlySet = domObject;
            event.trigger("MultimediaAppVideoPlayerCreated", [_video], true);
        }
    },

    play: function (repeatTimes) {
        utils.validateNumberOfArguments(1, 1, arguments.length,
            ExceptionTypes.INVALID_PARAMETER, "invalid number of arguments (expected one)", new Exception());

        if (typeof repeatTimes !== "number" || repeatTimes < 0) {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "VideoPlayer.play was passed an invalid number of play times: " + repeatTimes, new Exception());
        }
        if (repeatTimes !== 0) {
            if (!_video) {
                return;
            }
            _loopCount = repeatTimes;
            _validateAndSet(_STATES.PLAYING, [_STATES.OPENED, _STATES.STOPPED, _STATES.COMPLETED], function () {
                _video.play();
            });
        }
    },

    pause: function () {
        if (!_video) {
            return;
        }
        _validateAndSet(_STATES.PAUSED, [_STATES.PLAYING], function () {
            _video.pause();
        });
    },

    resume: function () {
        if (!_video) {
            return;
        }
        _validateAndSet(_STATES.PLAYING, [_STATES.PAUSED], function () {
            _video.play();
        });
    },

    stop: function () {
        if (!_video) {
            return;
        }
        _validateAndSet(_STATES.STOPPED, [_STATES.PAUSED, _STATES.PLAYING], function () {
            _video.pause();
            _video.setAttribute("src", _currentVideoFile); // hack
        });
    }

};

});
define('ripple/platform/wac/1.0/File', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.expots = function () {
    this.createDate = undefined;
    this.fileName = undefined;
    this.filePath = undefined;
    this.fileSize = undefined;
    this.isDirectory = undefined;
    this.lastModifyDate = undefined;
};

});
define('ripple/platform/wac/1.0/RadioSignalSourceTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    utils = require('ripple/utils');

_self = {
    "CDMA": undefined,
    "GSM": undefined,
    "LTE": undefined,
    "TDSCDMA": undefined,
    "WCDMA": undefined
};

utils.forEach(_self, function (value, property) {
    _self.__defineGetter__(property, function () {
        return property;
    });
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/ExceptionTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self =  {};

_self.__defineGetter__("INVALID_PARAMETER", function () {
    return "invalid_parameter";
});

_self.__defineGetter__("SECURITY", function () {
    return "security";
});

_self.__defineGetter__("UNKNOWN", function () {
    return "unknown";
});

_self.__defineGetter__("UNSUPPORTED", function () {
    return "unsupported";
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/RadioInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    event = require('ripple/event'),
    _console = require('ripple/console'),
    deviceSettings = require('ripple/deviceSettings');

_self = {
    isRoaming: undefined,
    radioSignalStrengthPercent: undefined,
    isRadioEnabled: undefined,
    radioSignalSource: undefined,
    onSignalSourceChange: undefined
};

event.on("RadioSignalSourceChanged", function () {
    var callback = _self.onSignalSourceChange,
        isRoaming = _self.isRoaming,
        signalSource = _self.radioSignalSource,
        msg = "Fired onSignalSourceChange. signalSource: " + signalSource + ", isRoaming: " + isRoaming;

    if (callback && typeof callback === "function") {
        callback.apply(null, [signalSource, isRoaming]);
    }
    else {
        msg += " --> BUT there was no registered callback found.";
    }

    _console.log(msg);
});

_self.__defineGetter__("radioSignalSource", function () {
    return deviceSettings.retrieve("RadioInfo.radioSignalSource");
});

_self.__defineGetter__("isRoaming", function () {
    return deviceSettings.retrieveAsBoolean("RadioInfo.isRoaming");
});

_self.__defineGetter__("isRadioEnabled", function () {
    return deviceSettings.retrieveAsBoolean("RadioInfo.isRadioEnabled");
});

_self.__defineGetter__("radioSignalStrengthPercent", function () {
    return deviceSettings.retrieveAsInt("RadioInfo.radioSignalStrengthPercent");
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/PIM', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    exception = require('ripple/exception'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    AddressBookItem = require('ripple/platform/wac/1.0/AddressBookItem'),
    CalendarItem = require('ripple/platform/wac/1.0/CalendarItem'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    constants = require('ripple/constants');

function _throwUnsupportedException(method) {
    exception.raise(ExceptionTypes.UNSUPPORTED, "Method not supported." + (method || ""), new Exception());
}

function _toAddressBookItem(contact) {
    if (!contact) {
        return null;
    }

    var addressBookItem = new AddressBookItem();

    utils.forEach(contact, function (prop, key) {
        addressBookItem[key] = contact[key];
    });

    return addressBookItem;
}

function _toCalendarItem(item) {
    if (!item) {
        return null;
    }

    var calendarItem = new CalendarItem();

    utils.forEach(item, function (prop, key) {
        calendarItem[key] = item[key];
    });

    return calendarItem;
}

function _getData(type) {
    var data = db.retrieveObject(type) || [];
    return data;
}

function _saveData(type, items) {
    db.saveObject(type, items);
}

function _getContacts() {
    var contacts = _getData(constants.PIM.ADDRESS_LIST_KEY),
        gord,
        dan,
        brent,
        pj,
        mark;

    if (contacts.length === 0) {

        gord = new AddressBookItem();
        gord.addressBookItemId = "0";
        gord.fullName = "Gord Tanner";
        gord.eMail = "gord@tinyHippos.com";
        gord.company = "tinyHippos Inc";
        gord.title = "Code Poet";
        gord.address = "121 Charles Street W, Kitchener, Ontario, Canada";

        dan = new AddressBookItem();
        dan.addressBookItemId = "1";
        dan.fullName = "Dan Silivestru";
        dan.eMail = "dan@tinyHippos.com";
        dan.company = "tinyHippos Inc";
        dan.title = "Co-Founder And Chief Technology Officer";
        dan.address = "121 Charles Street W, Kitchener, Ontario, Canada";

        pj = new AddressBookItem();
        pj.addressBookItemId = "2";
        pj.fullName = "PJ Lowe";
        pj.eMail = "pj@tinyHippos.com";
        pj.company = "tinyHippos Inc";
        pj.title = "Co-Founder And Chief Operations Officer";
        pj.address = "121 Charles Street W, Kitchener, Ontario, Canada";

        brent = new AddressBookItem();
        brent.addressBookItemId = "2";
        brent.fullName = "Brent Lintner";
        brent.eMail = "brent@tinyHippos.com";
        brent.company = "tinyHippos Inc";
        brent.title = "Co-Founder And Chief Operations Officer";
        brent.address = "121 Charles Street W, Kitchener, Ontario, Canada";

        mark = new AddressBookItem();
        mark.addressBookItemId = "3";
        mark.fullName = "Mark McArdle";
        mark.eMail = "mark@tinyHippos.com";
        mark.company = "tinyHippos Inc";
        mark.title = "Chief Executive Officer";
        mark.address = "121 Charles Street W, Kitchener, Ontario, Canada";

        contacts.push(gord);
        contacts.push(dan);
        contacts.push(pj);
        contacts.push(brent);
        contacts.push(mark);

        _saveData(constants.PIM.ADDRESS_LIST_KEY, contacts);
    }
    return contacts.map(_toAddressBookItem);
}

function _getEvents() {
    var events = _getData(constants.PIM.CALENDAR_LIST_KEY);
    return events.map(_toCalendarItem);
}

function _get(type, id, fetchIDFunc) {
    var items = _getData(type);
    return items.reduceRight(function (match, item) {
        return fetchIDFunc(item) === id ? item : match;
    }, null);
}

function _getAddressBookID(item) {
    return item.addressBookItemId;
}

function _getCalendarID(item) {
    return item.calendarItemId;
}

function _getContact(id) {
    return _toAddressBookItem(_get(constants.PIM.ADDRESS_LIST_KEY, id, _getAddressBookID));
}

function _getEvent(id) {
    return _toCalendarItem(_get(constants.PIM.CALENDAR_LIST_KEY, id, _getCalendarID));
}

function _add(type, item, idProp) {
    var items = _getData(type);

    if (!item[idProp]) {
        item[idProp] = Math.uuid(undefined, 16);
    }

    items.push(item);
    _saveData(type, items);
}

function _delete(type, id, fetchIDFunc) {
    var items = _getData(type);

    _saveData(type, items.filter(function (item) {
        return fetchIDFunc(item) !== id;
    }));
}

function _validateArgs(min, max, len) {
    utils.validateNumberOfArguments(min, max, len,
        ExceptionTypes.INVALID_PARAMETER, "invalid number of parameters", new Exception());
}

function _validateType(arg, argType) {
    utils.validateArgumentType(arg, argType,
        ExceptionTypes.INVALID_PARAMETER,  "argument of wrong type provided",
        new Exception());
}

function _validateAddressBookItem(item) {
    if ((item instanceof AddressBookItem) === false) {
        exception.raise(ExceptionTypes.INVALID_PARAMETER, "invalid contact, not instance of AddressBookItem.", new Exception());
    }
}

_self = {
    addAddressBookItem: function (contact) {
        _validateArgs(1, 1, arguments.length);
        _validateAddressBookItem(contact);

        _add(constants.PIM.ADDRESS_LIST_KEY, contact, "addressBookItemId");
    },
    createAddressBookGroup: function (groupName) {
        _throwUnsupportedException("Widget.PIM.createAddressBookGroup");
    },
    createAddressBookItem: function () {
        return new AddressBookItem();
    },
    deleteAddressBookItem: function (contactid) {
        _validateArgs(1, 1, arguments.length);
        _validateType(contactid, "string");
        _delete(constants.PIM.ADDRESS_LIST_KEY, contactid, _getAddressBookID);
    },
    deleteAddressBookGroup: function (groupName) {
        _throwUnsupportedException("Widget.PIM.deleteAddressBookGroup");
    },
    getAddressBookItem: function (contactid) {
        _validateArgs(1, 1, arguments.length);
        _validateType(contactid, "string");
        return _getContact(contactid);
    },
    getAddressBookItemsCount: function () {
        _validateArgs(0, 0, arguments.length);
        var items = _getContacts();
        return items.length;
    },
    getAvailableAddressGroupNames: function () {
        _throwUnsupportedException("Widget.PIM.getAvailableAddressGroupNames");
    },
    getAddressBookGroupMembers: function (groupName) {
        _throwUnsupportedException("Widget.PIM.getAddressBookGroupMembers");
    },
    findAddressBookItems: function (comparisonContact, startInx, endInx) {
        _validateArgs(3, 3, arguments.length);
        utils.validateMultipleArgumentTypes([comparisonContact, startInx, endInx], ["object", "number", "number"], ExceptionTypes.INVALID_PARAMETER,  "argument of wrong type provided",
            new Exception());

        if (endInx < 0) {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "invalid number of parameters", new Exception());
        }

        startInx = startInx < 0 ? 0 : startInx;

        var contacts = _getContacts();
        utils.find(comparisonContact, contacts, startInx, endInx, _self.onAddressBookItemsFound);
    },

    addCalendarItem: function (calendarItem) {
        _validateArgs(1, 1, arguments.length);
        _add(constants.PIM.CALENDAR_LIST_KEY, calendarItem, "calendarItemId");
    },
    deleteCalendarItem: function (calendarId) {
        _validateArgs(1, 1, arguments.length);
        _delete(constants.PIM.CALENDAR_LIST_KEY, calendarId, _getCalendarID);
    },
    getCalendarItem: function (calendarId) {
        _validateArgs(1, 1, arguments.length);
        return _getEvent(calendarId);
    },
    findCalendarItems: function (itemToMatch, startInx, endInx) {
        _validateArgs(1, 3, arguments.length);
        var events = _getEvents();
        utils.find(itemToMatch, events, startInx, endInx, _self.onCalendarItemsFound);
    },
    getCalendarItems: function (startTime, endTime) {
        var events = _getEvents();

        return events.reduce(function (matches, event) {
            if (event.eventStartTime >= startTime && event.eventStartTime <= endTime) {
                matches.push(event);
            }
            return matches;
        }, []);
    },
    exportAsVCard: function (addressBookItems) {
        _throwUnsupportedException("Widget.PIM.exportAsVCard");
    },

    onAddressBookItemsFound: undefined, // function (addressBookItemsFound) { }
    onCalendarItemsFound: undefined, // function (calendarItemsFound) { }
    onCalendarItemAlert: undefined, // function (calendarItem) { }
    onVCardExportingFinish: undefined // function (vCardFilePath) { }
};

module.exports = _self;

});
define('ripple/platform/wac/1.0/WidgetManager', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var exception = require('ripple/exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception');

module.exports = {
    // This method is used to check the installation status of a specific widget.
    checkWidgetInstallationStatus: function () {

        exception.raise(ExceptionTypes.UNSUPPORTED, "WidgetManager.checkWidgetInstallationStatus not supported", new Exception());
    }
};

});
define('ripple/platform/wac/1.0/ApplicationTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    _self = {};

utils.forEach(constants.PLATFORMS.WAC.APPLICATIONS, function (application) {
    _self.__defineGetter__(application, function () {
        return application;
    });
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/EventRecurrenceTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    NOT_REPEAT: "NOT_REPEAT",
    DAILY: "DAILY",
    EVERY_WEEKDAY: "EVERY_WEEKDAY",
    WEEKLY_ON_DAY: "WEEKLY_ON_DAY",
    MONTHLY_ON_DAY: "MONTHLY_ON_DAY",
    MONTHLY_ON_DAY_COUNT: "MONTHLY_ON_DAY_COUNT",
    YEARLY: "YEARLY"
};

});
define('ripple/platform/wac/1.0/PowerInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    event = require('ripple/event'),
    _console = require('ripple/console'),
    deviceSettings = require('ripple/deviceSettings'),
    _lastPercentRemaining;

_self = {
    isCharging: undefined,
    percentRemaining: undefined,

    onChargeStateChange: undefined,
    onLowBattery: undefined,
    onChargeLevelChange: undefined
};

function _getCurrentChargeState(percentRemaining, isCharging) {
    var batteryState;
    if (percentRemaining === 100 && isCharging) {
        batteryState = "full";
    }
    else if (!isCharging) {
        batteryState = "discharging";
    }
    else {
        batteryState = "charging";
    }
    return batteryState;
}

event.on("DeviceBatteryStateChanged", function (isCharging) {
    var callback = _self.onChargeStateChange,
        msg = "",
        batteryLevel = _self.percentRemaining,
        batteryState;

    batteryState = _getCurrentChargeState(batteryLevel, isCharging);

    msg += "Fired onChargeStateChange with batteryState: " + batteryState;

    if (callback && typeof callback === "function") {
        callback.apply(null, [batteryState]);
    }
    else {
        msg += " --> BUT there was no registered callback found.";
    }

    _console.log(msg);
});

event.on("DeviceBatteryLevelChanged", function (percentRemaining) {

    var callback = _self.onChargeLevelChange,
        lowBatteryCallback = _self.onLowBattery,
        msg = "Fired onChargeLevelChange with percentRemaining: " + percentRemaining;

    // blah, stupid Options returning strings
    percentRemaining = parseInt(percentRemaining, 10);

    if (callback && typeof callback === "function") {
        callback.apply(null, [percentRemaining]);
    }
    else {
        msg += " --> BUT there was no registered callback found.";
    }

    _console.log(msg);

    if (percentRemaining <= 10) {

        msg = "Fired onLowBattery with percentRemaining: " + percentRemaining;

        if (lowBatteryCallback && typeof lowBatteryCallback === "function") {
            lowBatteryCallback.apply(null, [percentRemaining]);
        }
        else {
            msg += " --> BUT there was no registered callback found.";
        }

        _console.log(msg);
    }

    if (percentRemaining === 100 || (percentRemaining < 100 && _lastPercentRemaining === 100)) {
        event.trigger("DeviceBatteryStateChanged", [_self.isCharging]);
    }

    _lastPercentRemaining = percentRemaining;

});

_self.__defineGetter__("isCharging", function () {
    return deviceSettings.retrieveAsBoolean("PowerInfo.isCharging");
});

_self.__defineGetter__("percentRemaining", function () {
    return deviceSettings.retrieveAsInt("PowerInfo.percentRemaining");
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/DeviceInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    deviceSettings = require('ripple/deviceSettings'),
    platform = require('ripple/platform'),
    devices = require('ripple/devices'),
    _self;

_self = {
    ownerInfo: undefined, // return AddressBookItem
    phoneColorDepthDefault: undefined,
    phoneFirmware: undefined,
    phoneManufacturer: undefined,
    phoneModel: undefined,
    phoneOS: undefined,
    phoneSoftware: undefined,
    phoneScreenHeightDefault: undefined,
    phoneScreenWidthDefault: undefined,
    totalMemory: undefined
};

function _getDeviceAttribute(attr) {
    var devicePointer = devices.getCurrentDevice();
    utils.forEach(attr.split("."), function (dot) {
        devicePointer = devicePointer[dot];
    });
    return devicePointer;
}

_self.__defineGetter__("phoneColorDepthDefault", function () {
    return deviceSettings.retrieveAsInt("DeviceInfo.phoneColorDepthDefault");
});

_self.__defineGetter__("phoneFirmware", function () {
    return _getDeviceAttribute("firmware");
});

_self.__defineGetter__("phoneManufacturer", function () {
    return _getDeviceAttribute("manufacturer");
});

_self.__defineGetter__("phoneOS", function () {
    return _getDeviceAttribute("osName") + " " + _getDeviceAttribute("osVersion");
});

_self.__defineGetter__("phoneModel", function () {
    return _getDeviceAttribute("model");
});

_self.__defineGetter__("phoneSoftware", function () {
    return _getDeviceAttribute("osVersion");
});

_self.__defineGetter__("phoneScreenHeightDefault", function () {
    return _getDeviceAttribute("screen.height");
});

_self.__defineGetter__("phoneScreenWidthDefault", function () {
    return _getDeviceAttribute("screen.width");
});

_self.__defineGetter__("totalMemory", function () {
    return deviceSettings.retrieveAsInt("DeviceInfo.totalMemory");
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/CallRecordTypes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    RECEIVED: "received",
    OUTGOING: "outgoing",
    MISSED: "missed"
};

});
define('ripple/platform/wac/1.0/Device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    exception = require('ripple/exception'),
    _console = require('ripple/console'),
    utils = require('ripple/utils'),
    notifications = require('ripple/notifications'),
    ApplicationTypes = require('ripple/platform/wac/1.0/ApplicationTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    _applicationTypes = {
        FILES: "FILES",
        MEDIAPLAYER: "MEDIAPLAYER",
        PHONECALL: "PHONECALL",
        PICTURES: "PICTURES"
    },
    _self;

function _throwUnsupportedException(method) {
    exception.raise(ExceptionTypes.UNSUPPORTED, "Method not supported." + (method || ""), new Exception());
}

_self = {
    // Properties
    clipboardString: undefined,
    widgetEngineName: undefined,
    widgetEngineProvider: undefined,
    widgetEngineVersion: undefined,

    // Methods
    getAvailableApplications: function () {
        return constants.PLATFORMS.WAC.APPLICATIONS || [];
    },

    getDirectoryFileNames: function () {
        _throwUnsupportedException("Device.getDirectoryFileNames");
    },
    getFile: function () {
        _throwUnsupportedException("Device.getFile");
    },

    launchApplication: function launchApplication(application, startParameter) {
        if (!application || typeof(application) !== "string") {
            exception.raise(ExceptionTypes.INVALID_PARAMETER,
                    "Invalid argument 'application' at Device.launchApplication(): expected to be of type 'string' but was of type: " + (application ? typeof(application) : "null"),
                    Exception);
        }

        if (startParameter && typeof(startParameter) !== "string") {
            exception.raise(ExceptionTypes.INVALID_PARAMETER,
                    "Invalid argument 'startParameter' at Device.launchApplication(): expected to be 'string' but was : " + typeof(startParameter),
                    Exception);
        }

        // rudimentary implementation for now
        var message = "The widget has requested application: '" + application + "' to be launched. \n\n";

        if (startParameter) {
            message += "The following start parameter was sent in: " + startParameter + "\n\n";
        }

        if (_applicationTypes[application] && !startParameter) {
            message += "Launching this application can also be done with an optional startParameter which was not provided" + "\n\n";
        }

        if (!ApplicationTypes[application]) {
            message += "Note: the application requested is not part of the common values specified by the WAC API.";
        }

        notifications.openNotification("normal", message);
        _console.log(message);
    },

    copyFile: function () {
        _throwUnsupportedException("Device.copyFile");
    },
    deleteFile: function () {
        _throwUnsupportedException("Device.deleteFile");
    },
    findFiles: function () {
        _throwUnsupportedException("Device.findFiles");
    },
    getFileSystemRoots: function () {
        _throwUnsupportedException("Device.getFileSystemRoots");
    },
    getFileSystemSize: function () {
        _throwUnsupportedException("Device.getFileSystemSize");
    },
    moveFile: function () {
        _throwUnsupportedException("Device.moveFile");
    },
    onFilesFound: function () {
        _throwUnsupportedException("Device.onFilesFound");
    },
    setRingtone: function () {
        _throwUnsupportedException("Device.setRingtone");
    },

    vibrate: function (duration) {
        utils.validateArgumentType(duration, "number", ExceptionTypes.INVALID_PARAMETER, "duration paramter is not a number", new Exception());
        notifications.openNotification("normal", "Vibrating for " + duration + " second(s).");
    }

};

_self.__defineGetter__("widgetEngineName", function () {
    return constants.PLATFORMS.WAC.DEVICE.WIDGET_ENGINE_NAME;
});

_self.__defineGetter__("widgetEngineProvider", function () {
    return constants.PLATFORMS.WAC.DEVICE.WIDGET_ENGINE_PROVIDER;
});

_self.__defineGetter__("widgetEngineVersion", function () {
    return constants.PLATFORMS.WAC.DEVICE.WIDGET_ENGINE_VERSION;
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/DataNetworkInfo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    utils = require('ripple/utils'),
    _console = require('ripple/console'),
    deviceSettings = require('ripple/deviceSettings'),
    DataNetworkConnectionTypes = require('ripple/platform/wac/1.0/DataNetworkConnectionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),

_self = {
    isDataNetworkConnected: undefined,
    networkConnectionType: undefined,
    onNetworkConnectionChanged: undefined,

    getNetworkConnectionName: function (networkConnectionType) {
        var foundConnectionType;
        utils.validateArgumentType(networkConnectionType, "string", ExceptionTypes.INVALID_PARAMETER, "networkConnectionType is invalid, expected a string", new Exception());
        foundConnectionType = DataNetworkConnectionTypes[networkConnectionType.toUpperCase()];
        return foundConnectionType || null;
    }
};

event.on("DataNetworkConnectionChanged", function (newConnectionName) {
    var callback = _self.onNetworkConnectionChanged,
        msg = "Fired onNetworkConnectionChanged with newConnectionName: " + newConnectionName;

    if (callback && typeof callback === "function") {
        callback.apply(null, [newConnectionName]);
    }
    else {
        msg += " --> BUT there was no registered callback found.";
    }

    _console.log(msg);
});

_self.__defineGetter__("isDataNetworkConnected", function () {
    return deviceSettings.retrieveAsBoolean("DataNetworkInfo.isDataNetworkConnected");
});

_self.__defineGetter__("networkConnectionType", function () {
    var value = deviceSettings.retrieve("DataNetworkInfo.networkConnectionType");
    return value instanceof Array ? value : [value];
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/AudioPlayer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event'),
    exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    fileSystem = require('ripple/fileSystem'),
    _console = require('ripple/console'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    _self,
    _state = null,
    _STATES = constants.MULTIMEDIA.AUDIO_STATES,
    _currentAudioFile,
    _audio, _loopCount;

event.on("MultimediaAudioStateChanged", function updateAudioState(state) {
    _state = state;
    if (typeof _self.onStateChange === 'function') {
        _self.onStateChange.apply(_self, arguments);
    }
});

_audio = utils.createElement("audio", {
    "id": "multimedia-audio"
});

_audio.addEventListener('error', function () {
    _console.warn("AudioPlayer encountered an error: " + _audio.error.code);
    if (_audio.error.code === 4) {
        _console.warn("AudioPlayer error 4 could be caused by missing codecs");
    }
    _state = null;
    event.trigger("MultimediaAudioStateChanged", [null], true);
});

_audio.addEventListener('ended', function handleAudioEnded() {
    event.trigger("MultimediaAudioStateChanged", [_STATES.COMPLETED], true);
    if (_loopCount > 1) {
        _self.open(_currentAudioFile);
        _self.play(_loopCount--);
    }
});

document.getElementById("ui").appendChild(_audio);

function _validateAndSet(state, validStates, callbackBeforeSuccess) {
    var i, valid = false;

    for (i = 0; i < validStates.length; i++) {
        if (validStates[i] === _state) {
            valid = true;
        }
    }

    if (!valid) {
        _console.warn("Attempted to initiate AudioPlayer." + state +
            " in invalid state. current state: " + _state);
    } else {
        if (typeof(callbackBeforeSuccess) === "function") {
            callbackBeforeSuccess.apply();
        }
        event.trigger("MultimediaAudioStateChanged", [state], true);
    }

    return valid;
}

function _validateAudioType(fileUrl) {
    var matched = fileUrl.match(/\.(\w*)$/),
        type = matched ? matched[1] : "";

    if (_audio && _audio.canPlayType("audio/" + type) === "") {
        _console.warn("Attempting to load an audio that might not work in the current browser [" + fileUrl + "]");
    }
}

_self = {
    onStateChange: undefined,

    open: function (fileUrl) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "Multimedia.js.AudioPlayer.open wrong number of arguments", new Exception());
        utils.validateArgumentType(fileUrl, "string", ExceptionTypes.INVALID_PARAMETER, "Multimedia.js.AudioPlayer.open invalid parameter! expected string, fileUrl: " +
            fileUrl, new Exception());

        if (fileUrl.match(/^rtsp:\/\//)) {
            exception.raise(exception.types.MethodNotImplemented, "rtsp:// scheme not yet supported. sorry :(");
        }

        _validateAndSet(_STATES.OPENED, [_STATES.OPENED, _STATES.STOPPED, _STATES.COMPLETED, null], function () {
            _validateAudioType(fileUrl);
            _currentAudioFile = fileSystem.getURI(fileUrl);
            _audio.setAttribute("src", _currentAudioFile);
            _audio.load();
        });
    },

    play: function (repeatTimes) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "Multimedia.js.AudioPlayer.play wrong number of arguments", new Exception());
        utils.validateArgumentType(repeatTimes, "integer", ExceptionTypes.INVALID_PARAMETER, "Multimedia.js.AudioPlayer.play invalid parameter! expected integer, repeatTimes: " + repeatTimes, new Exception());

        if (repeatTimes < 0) {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "value of repeatTimes must be greater than 0", new Exception());
        }

        if (repeatTimes !== 0) {
            _validateAndSet(_STATES.PLAYING, [_STATES.OPENED, _STATES.STOPPED, _STATES.COMPLETED], function () {
                _loopCount = repeatTimes;
                _audio.play();
            });
        }
    },

    pause: function () {
        _validateAndSet(_STATES.PAUSED, [_STATES.PLAYING], function () {
            _audio.pause();
        });
    },

    resume: function () {
        _validateAndSet(_STATES.PLAYING, [_STATES.PAUSED], function () {
            _audio.play();
        });
    },

    stop: function () {
        _validateAndSet(_STATES.STOPPED, [_STATES.PAUSED, _STATES.PLAYING], function () {
            try {
                _audio.pause();
                _audio.currentTime = 0;
            } catch (e) {
                //HACK: do nothing, this could throw a dom exception 11 sometimes when playing an mp3 or before the file has loaded.
                //see http://developer.palm.com/distribution/viewtopic.php?f=11&t=7568
            }
        });
    }
};

module.exports = _self;

});
define('ripple/platform/wac/1.0/Account', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings'),
    _self;

_self = {
    accountName: undefined,
    accountId: undefined
};

_self.__defineGetter__("accountName", function () {
    return deviceSettings.retrieve("Account.accountName");
});

_self.__defineGetter__("accountId", function () {
    return deviceSettings.retrieve("Account.accountId");
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/Multimedia', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    VideoPlayer = require('ripple/platform/wac/1.0/VideoPlayer'),
    AudioPlayer = require('ripple/platform/wac/1.0/AudioPlayer'),
    constants = require('ripple/constants'),
    _volume = 5,
    _audioState,
    _videoState,
    _self;

event.on("MultimediaVolumeChanged", function updateVolume(volume) {
    _volume = volume;
});

event.on("MultimediaAudioStateChanged", function updateAudioState(state) {
    _audioState = state;
});

event.on("MultimediaVideoStateChanged", function updateVideoState(state) {
    _videoState = state;
});

_self = {

    isAudioPlaying: undefined,
    isVideoPlaying: undefined,

    getVolume: function () {
        return _volume;
    },

    stopAll: function () {
        VideoPlayer.stop();
        AudioPlayer.stop();
    }
};

_self.__defineGetter__("isAudioPlaying", function () {
    return _audioState === constants.MULTIMEDIA.AUDIO_STATES.PLAYING;
});

_self.__defineGetter__("isVideoPlaying", function () {
    return _videoState === "playing";
});

module.exports = _self;

});
define('ripple/platform/wac/1.0/MessageQuantities', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    totalMessageCnt: undefined,
    totalMessageReadCnt: undefined,
    totalMessageUnreadCnt: undefined
};

});
define('ripple/platform/wac/1.0/Attachment', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function () {
    this.fileName = "";
    this.MIMEType = "";
    this.size = 0;
};

});
define('ripple/platform/wac/1.0/Camera', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var exception = require('ripple/exception'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    constants = require('ripple/constants'),
    _console = require('ripple/console'),
    utils = require('ripple/utils'),
    notifications = require('ripple/notifications'),
    _currentlySet,
    _img,
    _buttons,
    _self,
    _videoCapture;


function _populateWindow(domObject) {
    var record = document.createElement("button"),
        pause = document.createElement("button"),
        stop = document.createElement("button");

    _img = document.createElement("img");
    _img.setAttribute("id", "jil-camera-window");
    //_img.setAttribute("src", document.querySelector("#extension-url").innerHTML + constants.CAMERA.WINDOW_ANIMATION);
    _img.setAttribute("src", document.documentURI.replace(/index\.html$/, "") + constants.CAMERA.WINDOW_ANIMATION);
    _img.setAttribute("width", "100%");
    _currentlySet = domObject;
    domObject.appendChild(_img);

    _buttons = document.createElement("div");
    _buttons.setAttribute("id", "jil-camera-window-buttons");
    _buttons.setAttribute("style", "display: none");

    record.setAttribute("id", "jil-camera-window-buttons-record");
    record.innerHTML = "Record";
    pause.setAttribute("id", "jil-camera-window-buttons-pause");
    pause.innerHTML = "Pause";
    stop.setAttribute("id", "jil-camera-window-buttons-stop");
    stop.innerHTML = "Stop";
    stop.addEventListener("click", _self.stopVideoCapture);

    _buttons.appendChild(record);
    _buttons.appendChild(pause);
    _buttons.appendChild(stop);

    domObject.appendChild(_buttons);

}

function _verifySetWindow(method) {
    if (!_img) {
        exception.raise(ExceptionTypes.UNKNOWN, "Camera." +
          method + " was (most likely) called before using the setWindow method.", new Exception());
    }
}

_self = {
    onCameraCaptured: undefined, //function (fileName) { }

    captureImage: function (fileName, lowRes) {
        utils.validateNumberOfArguments(2, 2, arguments.length, ExceptionTypes.INVALID_PARAMETER, "captureImage invalid number of parameters", new Exception());
        utils.validateMultipleArgumentTypes([fileName, lowRes], ['string', 'boolean'], ExceptionTypes.INVALID_PARAMETER, "invalid parameter type", new Exception());

        _verifySetWindow("captureImage");
        var msg = constants.CAMERA.WARNING_TEXT;
        msg = msg.replace("{file}", fileName);
        notifications.openNotification("normal", msg);
        _console.log("simulated saved image as: " + fileName);
        if (_self.onCameraCaptured) {
            _self.onCameraCaptured.apply(_self, [fileName]);
        }

        return fileName;
    },
    setWindow: function (domObject) {

        if (_currentlySet) {
            _currentlySet.removeChild(_img);
            _currentlySet.removeChild(_buttons);
            _currentlySet = null;
            _img = null;
            _buttons = null;
        }
        if (domObject !== null) {
            _populateWindow(domObject);
        }
    },
    startVideoCapture: function (fileName, lowRes, maxDurationSeconds, showDefaultControls) {
        _verifySetWindow("startVideoCapture");
        utils.validateNumberOfArguments(1, 4, arguments.length, ExceptionTypes.INVALID_PARAMETER, "startVideoCapture invalid number of parameters", new Exception());
        utils.validateMultipleArgumentTypes(
            [fileName, lowRes, maxDurationSeconds, showDefaultControls],
            ['string', 'boolean', 'integer', 'boolean'],
            ExceptionTypes.INVALID_PARAMETER,
            "invalid parameter type", new Exception());
        _console.log("started recording video");
        var interval = window.setTimeout(function () {
            _self.stopVideoCapture();
        }, maxDurationSeconds * 1000);

        if (showDefaultControls) {
            _buttons.removeAttribute("style");
        }

        _videoCapture = {
            fileName: fileName,
            stop: function () {
                window.clearInterval(interval);
                var msg = constants.CAMERA.WARNING_TEXT;
                msg = msg.replace("{file}", fileName);
                notifications.openNotification("normal", msg);
                if (_self.onCameraCaptured) {
                    _self.onCameraCaptured.apply(_self, [fileName]);
                }
            }
        };

        return fileName;
    },
    stopVideoCapture: function () {
        utils.validateNumberOfArguments(0, 0, arguments.length, ExceptionTypes.INVALID_PARAMETER, "stopVideoCapture invalid number of parameters", new Exception());
        if (_videoCapture) {
            _console.log("simulated saving a video as: " + _videoCapture.fileName);
            if (_buttons) {
                _buttons.setAttribute("style", "display: none");
            }
            _videoCapture.stop();
            _videoCapture = null;
        }
    }

};

module.exports = _self;

});
define('ripple/platform/wac/1.0/Exception', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = function () {
    this.message = "";
    this.type =  "";

    this.toString = function () {
        var result = this.type + ': "' + this.message + '"';

        if (this.stack) {
            result += "\n" + this.stack;
        }
        return result;
    };
};

});
define('ripple/platform/wac/1.0/Messaging', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    notifications = require('ripple/notifications'),
    _console = require('ripple/console'),
    Message = require('ripple/platform/wac/1.0/Message'),
    MessageTypes = require('ripple/platform/wac/1.0/MessageTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes');

function _throwUnsupportedException(method) {
    exception.raise(ExceptionTypes.UNSUPPORTED, "Method not supported." + (method || ""), new Exception());
}

module.exports = {
    onMessageArrived: undefined,
    onMessageSendingFailure: undefined,
    onMessagesFound: undefined,

    createMessage: function (messageType) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "createMessage invalid number of arguments", new Exception());
        utils.validateArgumentType(messageType, "string", ExceptionTypes.INVALID_PARAMETER, "createMessage invalid arguments", new Exception());

        if (!utils.some(MessageTypes, function (value) {
                return value === messageType;
            })) {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "createMessage invalid arguments", new Exception());
        }

        var message = new Message();
        message.messageType = messageType;

        return message;
    },
    deleteMessage: function () {
        _throwUnsupportedException("Messaging.deleteMessage");
    },
    getMessage: function () {
        _throwUnsupportedException("Messaging.getMessage");
    },
    getMessageQuantities: function () {
        _throwUnsupportedException("Messaging.getMessageQuantities");
    },
    sendMessage: function (msg) {
        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.UNSUPPORTED, "sendMessage invalid number of arguments", new Exception());
        if (msg instanceof Message === false) {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "expected a valid Message object", new Exception());
        }

        //TODO: Must be modded to fail and to then call the onMessageSendingFailure callback
        var message = "Sent " + msg.messageType + " " + msg.messageId + " to " + msg.destinationAddress;

        // insert fail check here
        notifications.openNotification("normal", message);
        _console.log(message);
    },
    moveMessageToFolder: function () {
        _throwUnsupportedException("Messaging.moveMessageToFolder");
    },
    copyMessageToFolder: function () {
        _throwUnsupportedException("Messaging.copyMessageToFolder");
    },
    createFolder: function () {
        _throwUnsupportedException("Messaging.createFolder");
    },
    deleteFolder: function () {
        _throwUnsupportedException("Messaging.deleteFolder");
    },
    getFolderNames: function () {
        _throwUnsupportedException("Messaging.getFolderNames");
    },
    findMessages: function () {
        _throwUnsupportedException("Messaging.findMessages");
    },
    getCurrentEmailAccount: function () {
        _throwUnsupportedException("Messaging.getCurrentEmailAccount");
    },
    getEmailAccounts: function () {
        _throwUnsupportedException("Messaging.getEmailAccounts");
    },
    setCurrentEmailAccount: function () {
        _throwUnsupportedException("Messaging.setCurrentEmailAccount");
    },
    deleteEmailAccount: function () {
        _throwUnsupportedException("Messaging.deleteEmailAccount");
    }

};

});
define('ripple/platform/wac/1.0/spec/events', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event');

module.exports = {
    "WidgetWakeup": {
        callback: function () {
            event.trigger("WidgetWakeup");
        }
    },
    "WidgetMaximize": {
        callback: function () {
            event.trigger("WidgetMaximize");
        }
    },
    "WidgetFocus": {
        callback: function () {
            event.trigger("WidgetFocus");
        }
    },
    "WidgetRestore": {
        callback: function () {
            event.trigger("WidgetRestore");
        }
    }
};

});
define('ripple/platform/wac/1.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event');

module.exports = {
    "AccountInfo": {
        "phoneUserUniqueId": {
            "name": "User Unique Id",
            "control": {
                "type": "text",
                "value": new Date().getTime().toString()
            }
        },
        "phoneMSISDN":  {
            "name": "MSISDN",
            "control": {
                "type": "text",
                "value": "15199999999"
            }
        },
        "phoneOperatorName":  {
            "name": "Operator Name",
            "control": {
                "type": "text",
                "value": ""
            }
        },
        "userAccountBalance":  {
            "name": "Account Balance",
            "control": {
                "type": "number",
                "value": 0
            }
        },
        "userSubscriptionType":  {
            "name": "Subscription Type",
            "control": {
                "type": "select",
                "value": "other"
            },
            "options": {
                "other": "other",
                "prepaid": "prepaid",
                "postpaid": "postpaid"
            }
        }
    },
    "RadioInfo": {
        "isRoaming": {
            "name": "Is Roaming",
            "control": {
                "type": "checkbox",
                "value": false
            },
            "callback": function () {
                event.trigger("RadioSignalSourceChanged");
            }
        },
        "isRadioEnabled":  {
            "name": "Is Radio Enabled",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "radioSignalSource": {
            "name": "Radio Signal Source",
            "control": {
                "type": "select",
                "value": "GSM"
            },
            // TODO: try not to duplicate from RadioSignalSourceTypes
            "options": {
                "CDMA": "cdma",
                "GSM": "gsm",
                "LTE": "lte",
                "TDSCDMA": "tdscdma",
                "WCDMA": "wcdma"
            },
            "callback": function () {
                event.trigger("RadioSignalSourceChanged");
            }
        },
        "radioSignalStrengthPercent": {
            "name": "Signal Strength %",
            "control": {
                "type": "select",
                "value": 80
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }())
        }
    },
    "Config": {
        "ringtoneVolume": {
            "name": "Ringtone Volume",
            "control": {
                "type": "select",
                "value": 10
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 10; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }())
        },
        "msgRingtoneVolume":  {
            "name": "Msg Ringtone Volume",
            "control": {
                "type": "select",
                "value": 10
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 10; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }())
        },
        "vibrationSetting":  {
            "name": "Vibration",
            "control": {
                "type": "select",
                "value": "off"
            },
            "options": {
                "on": "ON",
                "off": "OFF"
            }
        }
    },
    "Account": {
        "accountName":  {
            "name": "Name",
            "control": {
                "type": "text",
                "value": ""
            }
        },
        "accountId":  {
            "name": "Id",
            "control": {
                "type": "text",
                "value": ""
            }
        }
    },
    "DeviceInfo": {
        "totalMemory": {
            "name": "Total Memory",
            "control": {
                "type": "range",
                "value": 262144,
                "min": 0,
                "max": 4096000
            }
        },
        "phoneColorDepthDefault": {
            "name": "Color Depth",
            "control": {
                "type": "number",
                "value": 24
            }
        }
    },
    "DeviceStateInfo": {
        "availableMemory": {
            "name": "Available Memory",
            "control": {
                "type": "range",
                "value": 262144,
                "min": 0,
                "max": 4096000
            }
        },
        "keypadLightOn":   {
            "name": "Keypad Light On",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "backLightOn": {
            "name": "Back Light On",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "audioPath":  {
            "name": "Audio Path",
            "control": {
                "type": "select",
                "value": "receiver"
            },
            "options": {
                "speaker": "speaker",
                "receiver": "receiver",
                "earphone": "earphone"
            }
        },
        "processorUtilizationPercent":  {
            "name": "CPU Utilization %",
            "control": {
                "type": "select",
                "value": "5"
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }())
        },
        "language":  {
            "name": "Language",
            "control": {
                "type": "select",
                "value": "eng"
            },
            "options": (function () {
                var i,
                    optionList = {},
                    iterator = constants.LANG.ISO6392_LIST;

                for (i = 0; i <= iterator.length; i++) {
                    optionList[iterator[i]] = iterator[i];
                }

                return optionList;
            }())
        }
    },
    "DataNetworkInfo": {
        "isDataNetworkConnected": {
            "name": "Data Network Is Connected",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "networkConnectionType": {
            "name": "Network Connection Type",
            "control": {
                "type": "select",
                "value": ["GPRS"]
            },
            // TODO: try not to duplicate from DataNetworkConnectionTypes
            "options": {
                "BLUETOOTH": "bluetooth",
                "EDGE": "edge",
                "EVDO": "evdo",
                "GPRS": "gprs",
                "IRDA": "irda",
                "LTE": "lte",
                "ONEXRTT": "1xrtt",
                "WIFI": "wifi"
            },
            "callback": function (setting) {
                event.trigger("DataNetworkConnectionChanged", [setting]);
            }
        }
    },
    "PowerInfo": {
        "isCharging": {
            "name": "Battery Is Charging",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("DeviceBatteryStateChanged", [setting]);
            }
        },
        "percentRemaining":  {
            "name": "Battery Remaining %",
            "control": {
                "type": "select",
                "value": 100
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "callback": function (setting) {
                event.trigger("DeviceBatteryLevelChanged", [setting]);
            }
        }
    }
};

});
define('ripple/platform/wac/1.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        //"deviceSettings",
        "fileSystem",
        "geoView",
/*
        "multimedia",
        "audioPlayer",
        "telephony",
*/
        "platformEvents",
        "storage",
        "widgetConfig"
    ]
};

});
define('ripple/platform/wac/1.0/spec/config', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var platform = require('ripple/platform'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    constants = require('ripple/constants');

module.exports = {
    fileName: "config.xml",
    validateVersion: function (configValidationObject) {
        var valid = true;
        valid = !((!configValidationObject.widget.validationResult[0].attributes.xmlns.valid) ||
            (!configValidationObject.widget.validationResult[0].attributes["xmlns:JIL"].valid));

        return valid;
    },
    extractInfo: function (configValidationObject) {
        if (!configValidationObject) {
            return null;
        }

        var widgetInfo = {},
            configFeatures,
            configPreferences,
            preferenceName,
            platform;

        widgetInfo.id = configValidationObject.widget.validationResult[0].attributes.id.value || "";
        widgetInfo.name = configValidationObject.widget.children.name.validationResult[0].value;
        widgetInfo.icon = configValidationObject.widget.children.icon.validationResult[0].attributes.src.value;
        widgetInfo.version = configValidationObject.widget.validationResult[0].attributes.version.value;

        widgetInfo.features = {};

        configFeatures = configValidationObject.widget.children.feature.validationResult;
        utils.forEach(configFeatures, function (f) {
            if (f.valid === true) {
                var feature = {id: f.attributes.name.value,
                         required: f.attributes.required.valid};
                widgetInfo.features[feature.id] = feature;
            }
        });

        widgetInfo.preferences = {};

        configPreferences = configValidationObject.widget.children.preference.validationResult;

        platform = require('ripple/platform');
        utils.forEach(configPreferences, function (preference) {
            preferenceName = preference.attributes.name.value;
            if (preferenceName) {
                widgetInfo.preferences[preferenceName] = {
                    "key": preferenceName,
                    "value": preference.attributes.value.value || "",
                    "readonly": preference.attributes.readonly.value === "true"
                };

                db.save(preferenceName,
                        widgetInfo.preferences[preferenceName].value,
                        platform.getPersistencePrefix(widgetInfo.id));
            }
        });

        return widgetInfo;
    },
    schema: {
        rootElement: "widget",
        widget: {
            nodeName: "widget",
            required: true,
            occurrence: 1,
            helpText: "\"widget\" element describes widget information in configuration documents and serves as a container for other elements. It must be used in configuration document and may have following child elments: name,description,icon,author,license,content,maximum_display_mode,update,feature,access,billing. \"widget\" element MAY have following attributes: id,version,height,width,xml:lang",
            attributes: {
                xmlns: {
                    attributeName: "xmlns",
                    required: true,
                    type: "list",
                    listValues: ["http://www.w3.org/ns/widgets"]
                },
                "xmlns:JIL": {
                    attributeName: "xmlns:JIL",
                    required: true,
                    type: "list",
                    listValues: ["http://www.jil.org/ns/widgets1.2"]
                },
                "xmlns:its": {
                    attributeName: "xmlns:its",
                    helpText: "Indicates Text Directionality can be used. According to W3C spec, this feature is at risk, therefore we don't currently validate this.",
                    required: false,
                    type: "string"
                },
                id: {
                    attributeName: "id",
                    required: true,
                    type: "string"
                },
                version: {
                    attributeName: "version",
                    helpText: "Version must be in the following format: jil-rec-version-tag = major-version \".\" minor-version [\".\" version-desc]",
                    required: true,
                    type: "regex",
                    regex: /^\d{1,2}\.\d{1,2}(\.[A-Za-z0-9]{1,10})?$/
                },
                height: {
                    attributeName: "height",
                    required: true,
                    type: "integer"
                },
                width: {
                    attributeName: "width",
                    required: true,
                    type: "integer"
                },
                viewmodes: {
                    attributeName: "viewmodes",
                    required: false,
                    type: "list",
                    listValues: ["floating", "fullscreen"]
                },
                "xml:lang": {
                    attributeName: "xml:lang",
                    required: false,
                    type: "iso-language"
                }
            },
            children: {
                preference: {
                    nodeName: "preference",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        name: {
                            attributeName: "name",
                            type: "string",
                            required: true
                        },
                        value: {
                            type: "string",
                            attributeName: "value",
                            required: false
                        },
                        readonly: {
                            attributeName: "readonly",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                name: {
                    nodeName: "name",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "short": {
                            attributeName: "short",
                            type: "string",
                            required: false
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                description: {
                    nodeName: "description",
                    required: false,
                    occurrence: 0,
                    type: "string",
                    attributes: {
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                icon: {
                    nodeName: "icon",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        height: {
                            attributeName: "height",
                            required: false,
                            type: "integer"
                        },
                        width: {
                            attributeName: "width",
                            required: false,
                            type: "integer"
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                author: {
                    nodeName: "author",
                    required: false,
                    occurrence: 1,
                    type: "string",
                    attributes: {
                        email: {
                            attributeName: "email",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.EMAIL
                        },
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                license: {
                    nodeName: "license",
                    required: false,
                    occurrence: 1,
                    type: "string",
                    attributes: {
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: false,
                            regex: constants.REGEX.URL
                        },
                        "xml:lang": {
                            attributeName: "xml:lang",
                            type: "string",
                            required: false,
                            unique: true
                        }
                    }
                },
                content: {
                    nodeName: "content",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        src: {
                            attributeName: "src",
                            type: "string",
                            required: true
                        },
                        encoding: {
                            attributeName: "encoding",
                            type: "string",
                            required: false
                        },
                        type: {
                            attributeName: "type",
                            type: "string",
                            required: false
                        }
                    }
                },
                feature: {
                    nodeName: "feature",
                    required: false,
                    occurrence: 0,
                    attributes: {
                        name: {
                            attributeName: "name",
                            type: "list",
                            required: true,
                            listValues: ["http://jil.org/jil/api/1.1/widget", "http://jil.org/jil/api/1.1.5/exception",
                                            "http://jil.org/jil/api/1.1.5/exceptiontypes", "http://jil.org/jil/api/1.1/device",
                                            "http://jil.org/jil/api/1.1/accountinfo", "http://jil.org/jil/api/1.1/deviceinfo",
                                            "http://jil.org/jil/api/1.1.1/datanetworkinfo", "http://jil.org/jil/api/1.1/devicestateinfo",
                                            "http://jil.org/jil/api/1.1/accelerometerinfo", "http://jil.org/jil/api/1.1/config",
                                            "http://jil.org/jil/api/1.1.1/file", "http://jil.org/jil/api/1.1/positioninfo",
                                            "http://jil.org/jil/api/1.1/powerinfo", "http://jil.org/jil/api/1.1.1/radioinfo",
                                            "http://jil.org/jil/api/1.1.5/radiosignalsourcetypes", "http://jil.org/jil/api/1.1.5/applicationtypes",
                                            "http://jil.org/jil/api/1.1/messaging", "http://jil.org/jil/api/1.1/account",
                                            "http://jil.org/jil/api/1.1/attachment", "http://jil.org/jil/api/1.1/message",
                                            "http://jil.org/jil/api/1.1.4/messagefoldertypes", "http://jil.org/jil/api/1.1/messagequantities",
                                            "http://jil.org/jil/api/1.1/messagetypes", "http://jil.org/jil/api/1.1/multimedia",
                                            "http://jil.org/jil/api/1.1/audioplayer", "http://jil.org/jil/api/1.1.2/camera",
                                            "http://jil.org/jil/api/1.1.2/videoplayer", "http://jil.org/jil/api/1.1.1/pim",
                                            "http://jil.org/jil/api/1.1/addressbookitem", "http://jil.org/jil/api/1.1/calendaritem",
                                            "http://jil.org/jil/api/1.1/eventrecurrencetypes", "http://jil.org/jil/api/1.1.1/telephony",
                                            "http://jil.org/jil/api/1.1/callrecord", "http://jil.org/jil/api/1.1.1/callrecordtypes",
                                            "http://jil.org/jil/api/1.1.1/widgetmanager"]
                        },
                        required: {
                            attributeName: "required",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                "JIL:maximum_display_mode": {
                    nodeName: "JIL:maximum_display_mode",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        height: {
                            attributeName: "height",
                            type: "integer",
                            required: false
                        },
                        width: {
                            attributeName: "width",
                            type: "integer",
                            required: false
                        }
                    }
                },
                "JIL:update": {
                    nodeName: "JIL:update",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        href: {
                            attributeName: "href",
                            type: "regex",
                            required: true,
                            regex: constants.REGEX.URL
                        },
                        period: {
                            attributeName: "period",
                            helpText: "Possible values for the period attribute are: 0, 1, 2, 3 meaning: every time the widget is opened in maximum display mode, every day, every week, every month; respectivly",
                            type: "list",
                            required: true,
                            listValues: ["0", "1", "2", "3"]
                        }
                    }
                },
                "JIL:access": {
                    nodeName: "JIL:access",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        network: {
                            attributeName: "network",
                            type: "boolean",
                            required: false
                        },
                        localfs: {
                            attributeName: "localfs",
                            type: "boolean",
                            required: false
                        },
                        remote_scripts: {
                            attributeName: "remote_scripts",
                            type: "boolean",
                            required: false
                        }
                    }
                },
                "JIL:billing": {
                    nodeName: "JIL:billing",
                    required: false,
                    occurrence: 1,
                    attributes: {
                        required: {
                            attributeName: "required",
                            type: "boolean",
                            required: true
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/platform/wac/1.0/AddressBookItem', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    db = require('ripple/db'),
    constants = require('ripple/constants'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes');

function _validateArgs(min, max, len) {
    utils.validateNumberOfArguments(min, max, len,
        ExceptionTypes.INVALID_PARAMETER, "invalid number of parameters", new Exception());
}

function _validateType(arg, argType) {
    utils.validateArgumentType(arg, argType,
        ExceptionTypes.INVALID_PARAMETER,  "argument of wrong type provided",
        new Exception());
}

module.exports = function () {
    function _throwUnsupportedException(method) {
        exception.raise(ExceptionTypes.UNSUPPORTED, "Method not supported." + (method || ""), new Exception());
    }

    this.addressBookItemId = undefined;
    this.fullName = undefined;
    this.mobilePhone = undefined;
    this.homePhone = undefined;
    this.workPhone = undefined;
    this.eMail = undefined;
    this.company = undefined;
    this.title = undefined;
    this.address = undefined;

    this.setAttributeValue = function (attribute, value) {
        _validateArgs(2, 2, arguments.length);
        _validateType(attribute, "string");
        this[attribute] = value;
    };
    this.setAddressGroupNames = function (groups) {
        _throwUnsupportedException("PIM.AddressBookItem.setAddressGroupNames");
    };
    this.getAttributeValue = function (attribute) {
        _validateArgs(1, 1, arguments.length);
        _validateType(attribute, "string");
        return this[attribute];
    };
    this.getAddressGroupNames = function () {
        _throwUnsupportedException("PIM.AddressBookItem.getAddressGroupNames");
    };
    this.getAvailableAttributes = function () {
        return utils.reduce(this, function (attributes, value, key) {
            if (typeof(value) !== 'function') {
                attributes.push(key);
            }
            return attributes;
        }, []).sort();
    };
    this.update = function () {
        var items = db.retrieveObject(constants.PIM.ADDRESS_LIST_KEY),
            that = this,
            itemIndex = items.reduce(function (current, value, i) {
                return value.addressBookItemId === that.addressBookItemId ?
                    i : current;
            }, -1);

        if (itemIndex >= 0) {
            items[itemIndex] = this;
            db.saveObject(constants.PIM.ADDRESS_LIST_KEY, items);
        }
        else {
            exception.raise(ExceptionTypes.INVALID_PARAMETER, "Address Book Item not found: " + (this.addressBookItemId || ""), new Exception());
        }

    };
};

});
define('ripple/platform/wac/1.0/spec', function (require, exports, module) {
module.exports = {

    id: "wac",
    version: "1.0",
    name: "WAC",
    type: "plaform",

    persistencePrefix: "wac-",

    config: require('ripple/platform/wac/1.0/spec/config'),
    device: require('ripple/platform/wac/1.0/spec/device'),
    ui: require('ripple/platform/wac/1.0/spec/ui'),
    events: require('ripple/platform/wac/1.0/spec/events'),

    objects: {
        navigator: {
            path: "w3c/1.0/navigator"
        },
        WidgetManager: {
            path: "wac/1.0/WidgetManager",
            feature: "http://jil.org/jil/api/1.1.1/widgetmanager"
        },
        Widget: {
            path: "wac/1.0/Widget",
            feature: "http://jil.org/jil/api/1.1/widget",
            children: {
                Device: {
                    path: "wac/1.0/Device",
                    feature: "http://jil.org/jil/api/1.1/device",
                    children: {
                        AccountInfo: {
                            path: "wac/1.0/AccountInfo",
                            feature: "http://jil.org/jil/api/1.1/accountinfo"
                        },
                        ApplicationTypes: {
                            path: "wac/1.0/ApplicationTypes",
                            feature: "http://jil.org/jil/api/1.1.5/applicationtypes"
                        },
                        DataNetworkInfo: {
                            path: "wac/1.0/DataNetworkInfo",
                            feature: "http://jil.org/jil/api/1.1.1/datanetworkinfo",
                            children: {
                                DataNetworkConnectionTypes: {
                                    path: "wac/1.0/DataNetworkConnectionTypes"
                                }
                            }
                        },
                        DeviceInfo: {
                            path: "wac/1.0/DeviceInfo",
                            feature: "http://jil.org/jil/api/1.1/deviceinfo"
                        },
                        DeviceStateInfo: {
                            path: "wac/1.0/DeviceStateInfo",
                            feature: "http://jil.org/jil/api/1.1/devicestateinfo",
                            children: {
                                Config: {
                                    path: "wac/1.0/Config",
                                    feature: "http://jil.org/jil/api/1.1/config"
                                },
                                AccelerometerInfo: {
                                    path: "wac/1.0/AccelerometerInfo",
                                    feature: "http://jil.org/jil/api/1.1/accelerometerinfo"
                                }
                            }
                        },
                        File: {
                            path: "wac/1.0/File",
                            feature: "http://jil.org/jil/api/1.1.1/file"
                        },
                        PositionInfo: {
                            path: "wac/1.0/PositionInfo",
                            feature: "http://jil.org/jil/api/1.1/positioninfo"
                        },
                        RadioInfo: {
                            path: "wac/1.0/RadioInfo",
                            feature: "http://jil.org/jil/api/1.1.1/radioinfo",
                            children: {
                                RadioSignalSourceTypes: {
                                    path: "wac/1.0/RadioSignalSourceTypes",
                                    feature: "http://jil.org/jil/api/1.1.5/radiosignalsourcetypes"
                                }
                            }
                        },
                        PowerInfo: {
                            path: "wac/1.0/PowerInfo",
                            feature: "http://jil.org/jil/api/1.1/powerinfo"
                        }
                    }
                },
                ExceptionTypes: {
                    path: "wac/1.0/ExceptionTypes",
                    feature: "http://jil.org/jil/api/1.1.5/exceptiontypes"
                },
                Exception: {
                    path: "wac/1.0/Exception",
                    feature: "http://jil.org/jil/api/1.1.5/exception"
                },
                Multimedia: {
                    path: "wac/1.0/Multimedia",
                    feature: "http://jil.org/jil/api/1.1/multimedia",
                    children: {
                        Camera: {
                            path: "wac/1.0/Camera",
                            feature: "http://jil.org/jil/api/1.1.2/camera"
                        },
                        AudioPlayer: {
                            path: "wac/1.0/AudioPlayer",
                            feature: "http://jil.org/jil/api/1.1/audioplayer"
                        },
                        VideoPlayer: {
                            path: "wac/1.0/VideoPlayer",
                            feature: "http://jil.org/jil/api/1.1.2/videoplayer"
                        }
                    }
                },
                Telephony: {
                    path: "wac/1.0/Telephony",
                    feature: "http://jil.org/jil/api/1.1.1/telephony",
                    children: {
                        CallRecord: {
                            path: "wac/1.0/CallRecord",
                            feature: "http://jil.org/jil/api/1.1/callrecord"
                        },
                        CallRecordTypes: {
                            path: "wac/1.0/CallRecordTypes",
                            feature: "http://jil.org/jil/api/1.1.1/callrecordtypes"
                        }
                    }
                },
                PIM: {
                    path: "wac/1.0/PIM",
                    feature: "http://jil.org/jil/api/1.1.1/pim",
                    children: {
                        AddressBookItem: {
                            path: "wac/1.0/AddressBookItem",
                            feature: "http://jil.org/jil/api/1.1/addressbookitem"
                        },
                        CalendarItem: {
                            path: "wac/1.0/CalendarItem",
                            feature: "http://jil.org/jil/api/1.1/calendaritem"
                        },
                        EventRecurrenceTypes: {
                            path: "wac/1.0/EventRecurrenceTypes",
                            feature: "http://jil.org/jil/api/1.1/eventrecurrencetypes"
                        }
                    }
                },
                Messaging: {
                    path: "wac/1.0/Messaging",
                    feature: "http://jil.org/jil/api/1.1/messaging",
                    children: {
                        Account: {
                            path: "wac/1.0/Account",
                            feature: "http://jil.org/jil/api/1.1/account"
                        },
                        Attachment: {
                            path: "wac/1.0/Attachment",
                            feature: "http://jil.org/jil/api/1.1/attachment"
                        },
                        Message: {
                            path: "wac/1.0/Message",
                            feature: "http://jil.org/jil/api/1.1/message"
                        },
                        MessageFolderTypes: {
                            path: "wac/1.0/MessageFolderTypes",
                            feature: "http://jil.org/jil/api/1.1.4/messagefoldertypes"
                        },
                        MessageQuantities: {
                            path: "wac/1.0/MessageQuantities",
                            feature: "http://jil.org/jil/api/1.1/messagequantities"
                        },
                        MessageTypes: {
                            path: "wac/1.0/MessageTypes",
                            feature: "http://jil.org/jil/api/1.1/messagetypes"
                        }
                    }
                }
            }
        }
    }

};

});
define('ripple/platform/wac/1.0/Widget', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    _console = require('ripple/console'),
    app = require('ripple/app'),
    platform = require('ripple/platform'),
    exception = require('ripple/exception'),
    ExceptionTypes = require('ripple/platform/wac/1.0/ExceptionTypes'),
    Exception = require('ripple/platform/wac/1.0/Exception'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    _self;

event.on("ScreenChangeDimensions", function (height, width) {
    try {
        // TODO: are these per spec to call?
        if (typeof app.onMaximize === 'function') {
            app.onMaximize();
        }
        if (typeof app.onRestore === 'function') {
            app.onRestore();
        }
        _console.log("called Widget.onRestore and Widget.onMaximize callback function");
    }
    catch (e) {
        exception.handle(e, false);
    }
});

event.on("WidgetWakeup", function () {
    if (_self.onWakeup) {
        _self.onWakeup();
    }
});

event.on("WidgetMaximize", function () {
    if (_self.onMaximize) {
        _self.onMaximize();
    }
});

event.on("WidgetFocus", function () {
    if (_self.onFocus) {
        _self.onFocus();
    }
});

event.on("WidgetRestore", function () {
    if (_self.onRestore) {
        _self.onRestore();
    }
});

_self = {
    onWakeup: undefined,
    onMaximize: undefined,
    onFocus: undefined,
    onRestore: undefined,

    openURL: function (url) {
        window.open(url);
    },

    setPreferenceForKey: function (value, key) {

        utils.validateNumberOfArguments(1, 2, arguments.length, ExceptionTypes.INVALID_PARAMETER, "setPreferenceForKey invalid number of paramters", new Exception());
        utils.validateArgumentType(key, "string", ExceptionTypes.INVALID_PARAMETER, "setPreferenceForKey invalid parameter! Key:" +
            key + ", Value: " + value, new Exception());

        var msg = "",
            prefix;
        if (app.isPreferenceReadOnly(key)) {
            msg += "Cannot modify a read only preference. Preference key: " + key;
        }
        else {
            prefix = platform.getPersistencePrefix();
            if (value === null) {
                msg += "deleting preference " + key;
                db.remove(key, prefix);
            }
            else {
                msg += "setting preference " + key + " == " + value;
                utils.validateArgumentType(value, "string", ExceptionTypes.INVALID_PARAMETER, msg, new Exception());
                db.save(key, value, prefix);
            }
        }


        _console.log(msg);

        // Trigger storageUpdatedEvent
        event.trigger("StorageUpdatedEvent");

    },

    // return value or undefined
    preferenceForKey: function (key) {

        utils.validateNumberOfArguments(1, 1, arguments.length, ExceptionTypes.INVALID_PARAMETER, "preferenceForKey invalid number of parameters", new Exception());
        utils.validateArgumentType(key, "string", ExceptionTypes.INVALID_PARAMETER, "preferenceForKey invalid paramters", new Exception());

        var prefix = platform.getPersistencePrefix(),
            value = db.retrieve(key, prefix);

        if (!value && value !== "") {
            value = undefined;
        }

        _console.log("retrieving preference " + key + " == " + value);

        return value;

    }
};

module.exports = _self;

});
define('ripple/platform/spec', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    //"phonegap": {"1.0.0": require('ripple/platform/phonegap/1.0.0/spec')},
    "tizen": {"2.0": require('ripple/platform/tizen/2.0/spec')},
    "cordova": {"2.0.0": require('ripple/platform/cordova/2.0.0/spec')},
    //"webworks.bb10": {"1.0.0": require('ripple/platform/webworks.bb10/1.0.0/spec')},
    //"webworks.handset": {"2.0.0": require('ripple/platform/webworks.handset/2.0.0/spec')},
    //"webworks.tablet": {"2.0.0": require('ripple/platform/webworks.tablet/2.0.0/spec')},
    //"web": {"default": require('ripple/platform/web/default/spec')},

    "get": function (name, version) {
        var platform = module.exports[name] || {};
        return (platform[version] || platform[Object.keys(platform)[0]]);
    }
};

});
define('ripple/platform/web/default/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.addEventListener("load", function () {
    var event = require('ripple/event');

    event.on("HardwareKey", function (key) {
        event.trigger("HardwareKeyDefault", [key]);
    });

    //HACK: Remove this guy from namespace since we are just hacking this in as a bootstrapper
    delete window.device;
});

});
define('ripple/platform/web/default/spec/ui', function (require, exports, module) {
module.exports = {
    plugins: [
        "accelerometer",
        "geoView"
    ]
};

});
define('ripple/platform/web/default/spec', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {

    id: "web",
    version: "default",
    name: "Mobile Web",

    ui: require('ripple/platform/web/default/spec/ui'),
    device: {},

    persistencePrefix: "tinyhippos-",

    initialize: function () {},

    objects: {
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        navigator: {
            path: "w3c/1.0/navigator",
            children: {
                geolocation: {
                    path: "w3c/1.0/geolocation"
                }
            }
        },
        device: {
            path: "web/default/device"
        }
    },
};

});
define('ripple/platform/webworks.tablet/2.0.0/server/appEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    notifications = require('ripple/notifications'),
    _bg,
    _fg,
    _swipeDown,
    _swipeStart,
    _exit;

event.on("AppExit", function () {
    var baton = _exit;
    _exit = null;
    notifications.openNotification("normal", "blackberry.app.exit() as called, in the real world your app will exit, here... you get this notification");
    return baton && baton.pass({code: 1});
});

event.on("AppRequestBackground", function () {
    var baton = _bg;
    _bg = null;
    return baton && baton.pass({code: 1});
});

event.on("AppRequestForeground", function () {
    var baton = _fg;
    _fg = null;
    return baton && baton.pass({code: 1});
});

event.on("AppSwipeDown", function () {
    var baton = _swipeDown;
    _swipeDown = null;
    return baton && baton.pass({code: 1});
});

event.on("AppSwipeStart", function () {
    var baton = _swipeStart;
    _swipeStart = null;
    return baton && baton.pass({code: 1});
});

module.exports = {
    onBackground: function (get, post, baton) {
        baton.take();
        _bg = baton;
        return {code: 1};
    },

    onForeground: function (get, post, baton) {
        baton.take();
        _fg = baton;
        return {code: 1};
    },

    onSwipeDown: function (get, post, baton) {
        baton.take();
        _swipeDown = baton;
        return {code: 1};
    },

    onSwipeStart: function (get, post, baton) {
        baton.take();
        _swipeStart = baton;
        return {code: 1};
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/server/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    app = require('ripple/app'),
    _self;

_self = {
    event: require('ripple/platform/webworks.tablet/2.0.0/server/appEvent'),

    exit: function () {
        event.trigger("AppExit");
        return {code: 1};
    },

    author: function () {
        return {code: 1, data: app.getInfo().author};
    },

    authorEmail: function () {
        return {code: 1, data: app.getInfo().authorEmail};
    },

    authorURL: function () {
        return {code: 1, data: app.getInfo().authorURL};
    },

    copyright: function () {
        return {code: 1, data: app.getInfo().copyright};
    },

    description: function () {
        return {code: 1, data: app.getInfo().description};
    },

    id: function () {
        return {code: 1, data: app.getInfo().id};
    },

    license: function () {
        return {code: 1, data: app.getInfo().license};
    },

    licenseURL: function () {
        return {code: 1, data: app.getInfo().licenseURL};
    },

    name: function () {
        return {code: 1, data: app.getInfo().name};
    },

    version: function () {
        return {code: 1, data: app.getInfo().version};
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/server/invoke', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var notifications = require('ripple/notifications'),
    constants = require('ripple/constants'),
    type = "normal",
    name = {
        "camera://": "Camera",
        "camera://video": "Video Camera",
        "map://": "Maps",
        "http://": "Browser",
        "music://": "Music",
        "photos://": "Photos",
        "videos://": "Videos",
        "appworld://": "App World",
        "update://": "Update"
    };

module.exports = {
    invoke: function (opts) {
        var app = name[opts.appType];
        if (app === undefined && opts.appType && opts.appType.match(/^http/i)) {
            app = "Browser";
        }

        notifications.openNotification(type,
           "Requested to launch: " + app + " application.");
        return {code: 1};
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/server/identity', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var deviceSettings = require('ripple/deviceSettings');

module.exports = {
    PIN: function () {
        return {code: 1, data: deviceSettings.retrieve("identity.PIN")};
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/server/systemEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    _onBatteryStateChange,
    _onBatteryLevelChange,
    _states = {
        UNKNOWN: 0,
        FULL: 1,
        CHARGING: 2,
        UNPLUGGED: 3
    },
    _battery = {
        state: _states.UNKNOWN,
        charging: null,
        level: null
    };

function _getState() {
    return _battery.level === 100 ? _states.FULL :
           _battery.charging ? _states.CHARGING : _states.UNPLUGGED;
}

function _pass(baton, data) {
    if (baton) {
        baton.pass({code: 1, data: data});
    }
}

event.on("DeviceBatteryStateChanged", function (charging) {
    _battery.charging = charging;
    _battery.state = _getState();
    _pass(_onBatteryStateChange, _battery.state);
});

event.on("DeviceBatteryLevelChanged", function (level) {
    level = parseInt(level, 10);

    _battery.level = level;
    _pass(_onBatteryLevelChange, level);

    if (level === 100) {
        _battery.state = _getState();
        _pass(_onBatteryStateChange, _battery.state);
    }
});

module.exports = {
    deviceBatteryLevelChange: function (get, post, baton) {
        baton.take();
        _onBatteryLevelChange = baton;
    },
    deviceBatteryStateChange: function (get, post, baton) {
        baton.take();
        _onBatteryStateChange = baton;
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/server', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    platform = "ripple/platform/webworks.tablet/2.0.0/server/",
    core = "ripple/platform/webworks.core/2.0.0/server/",
    systemEvent = require(platform + 'systemEvent'),
    system = {};

// ugh, thanks to the spec...
system.event = systemEvent;
utils.mixin(require(core + "system"), system);

module.exports = {
    blackberry: {
        identity: require(platform + "identity"),
        app: require(platform + "app"),
        invoke: require(platform + "invoke"),
        system: system,
        ui: {
            dialog: require(core + "dialog")
        },
        io: {
            dir: require(core + "io/dir"),
            file: require(core + "io/file")
        }
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/XMLHttpRequest', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var xhr = require("ripple/platform/webworks.core/2.0.0/XMLHttpRequest");
module.exports = xhr.create("ripple/platform/webworks.tablet/2.0.0/server");

});
define('ripple/platform/webworks.tablet/2.0.0/client/BrowserArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.BrowserArguments ( url : String ,  [transport : blackberry.identity.Transport ] )
module.exports = function (url, transport) {
    return {
        url: url
    };
};

});
define('ripple/platform/webworks.tablet/2.0.0/client/appEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _callbacks = {},
    _self;

function _poll(evt, handler) {
    _callbacks[evt] = handler;

    transport.poll("blackberry/app/event/" + evt, {}, function () {
        var func = _callbacks[evt];

        if (func) {
            func();
        }

        return !!func;
    });
}

_self = {
    onBackground: function (handler) {
        _poll("onBackground", handler);
    },

    onForeground: function (handler) {
        _poll("onForeground", handler);
    },

    onSwipeDown: function (handler) {
        _poll("onSwipeDown", handler);
    },

    onSwipeStart: function (handler) {
        _poll("onSwipeStart", handler);
    }
};

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/client/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/app/",
    _self;

_self = {
    exit: function () {
        transport.call(_uri + "exit", {async: true});
    }
};

_self.__defineGetter__("author", function () {
    return transport.call(_uri + "author");
});

_self.__defineGetter__("authorEmail", function () {
    return transport.call(_uri + "authorEmail");
});

_self.__defineGetter__("authorURL", function () {
    return transport.call(_uri + "authorURL");
});

_self.__defineGetter__("copyright", function () {
    return transport.call(_uri + "copyright");
});

_self.__defineGetter__("description", function () {
    return transport.call(_uri + "description");
});

_self.__defineGetter__("id", function () {
    return transport.call(_uri + "id");
});

_self.__defineGetter__("license", function () {
    return transport.call(_uri + "license");
});

_self.__defineGetter__("licenseURL", function () {
    return transport.call(_uri + "licenseURL");
});

_self.__defineGetter__("name", function () {
    return transport.call(_uri + "name");
});

_self.__defineGetter__("version", function () {
    return transport.call(_uri + "version");
});

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/client/io/dir', function (require, exports, module) {
/*
 * Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var dir = require('ripple/platform/webworks.core/2.0.0/client/io/dir'),
    utils = require('ripple/utils'),
    _self = {};

utils.mixin({
    appDirs: {
        "app": {
            "storage" : {
                "path" : "file:///accounts/1000/appdata/emulatedapp/data"
            }
        },
        "shared": {
            "bookmarks": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/bookmarks"
            },
            "books": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/books"
            },
            "camera": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/camera"
            },
            "documents": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/documents"
            },
            "downloads": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/downloads"
            },
            "misc": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/misc"
            },
            "music": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/music"
            },
            "photos": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/photos"
            },
            "print": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/print"
            },
            "videos": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/videos"
            },
            "voice": {
                "path" : "file:///accounts/1000/appdata/emulatedapp/shared/voice"
            }
        }
    }
}, _self);

utils.mixin(dir, _self);

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/client/system', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    system = require('ripple/platform/webworks.core/2.0.0/client/system'),
    _uri = "blackberry/system/";

system.__defineGetter__("scriptApiVersion", function () {
    return transport.call(_uri + "softwareVersion");
});


module.exports = system;

});
define('ripple/platform/webworks.tablet/2.0.0/client/invoke', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _uri = "blackberry/invoke/invoke",
    APP_TYPE = "appType",
    APP_URL_CAMERA = "camera://",
    APP_URL_CAMERA_VIDEO = "camera://video",
    APP_URL_MAP = "map://",
    APP_URL_MUSIC = "music://",
    APP_URL_PHOTOS = "photos://",
    APP_URL_VIDEOS = "videos://",
    APP_URL_APPWORLD = "appworld://",
    APP_URL_UPDATE = "update://",
    APP_TYPE_ERROR = "appType not supported",
    APP_BROWSER_ERROR = "Protocol specified in the url is not supported.",
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _self;

_self = {
    invoke: function (appType, args) {
        var get = {};

        switch (appType) {

        //Camera
        case 4:
            if (!args || args.view === 1) {
                get.appType = APP_URL_CAMERA_VIDEO;
            } else {
                get.appType = APP_URL_CAMERA;
            }
            break;

        //Maps
        case 5:
            get.appType = APP_URL_MAP;
            break;

        //Browser
        case 11:

            if (!args) {
                get.appType = "http://";
            }
            else {
                get.appType = args.url.split("://");

                if (get.appType.length === 1) {
                    get.appType = "http://" + get.appType[0];
                }
                else if (get.appType.length === 2) {
                    if (get.appType[0].indexOf("http") !== 0) {
                        throw APP_BROWSER_ERROR;
                    }
                    else {
                        get.appType = args.url;
                    }
                }
            }
            break;

        //Music
        case 13:
            get.appType = APP_URL_MUSIC;
            break;

        //Photos
        case 14:
            get.appType = APP_URL_PHOTOS;
            break;

        //Videos
        case 15:
            get.appType = APP_URL_VIDEOS;
            break;

        //AppWorld
        case 16:
            get.appType = APP_URL_APPWORLD;
            break;

        //Update
        case 17:
            get.appType = APP_URL_UPDATE;
            break;

        default:
            throw APP_TYPE_ERROR;
        }

        transport.call(_uri, {
            get: get,
            async: true
        });
    }
};

_self.__defineGetter__("APP_CAMERA", function () {
    return 4;
});
_self.__defineGetter__("APP_MAPS", function () {
    return 5;
});
_self.__defineGetter__("APP_BROWSER", function () {
    return 11;
});
_self.__defineGetter__("APP_MUSIC", function () {
    return 13;
});
_self.__defineGetter__("APP_PHOTOS", function () {
    return 14;
});
_self.__defineGetter__("APP_VIDEOS", function () {
    return 15;
});
_self.__defineGetter__("APP_APPWORLD", function () {
    return 16;
});

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/client/identity', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    _uri = "blackberry/identity/",
    _self = {};

_self.__defineGetter__("PIN", function () {
    return transport.call(_uri + "PIN");
});

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/client/CameraArguments', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//blackberry.invoke.CameraArguments ( )
var _self = function () {
    return {
        //readwrite  property  Number   view
        view: 0
    };
};

//const Number  VIEW_CAMERA  = 0
_self.__defineGetter__("VIEW_CAMERA", function () {
    return 0;
});
//const Number  VIEW_RECORDER  = 1
_self.__defineGetter__("VIEW_RECORDER", function () {
    return 1;
});

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/client/systemEvent', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    api = "blackberry/system/event/";

function _poll(evt, handler) {
    transport.poll(api + evt, {}, function (data, response) {
        if (handler) {
            handler(data);
        }
        return !!handler;
    });
}

module.exports = {
    deviceBatteryLevelChange: function (handler) {
        _poll("deviceBatteryLevelChange", handler);
    },
    deviceBatteryStateChange: function (handler) {
        _poll("deviceBatteryStateChange", handler);
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/spec/events', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    events = require('ripple/platform/webworks.core/2.0.0/spec/events');

_self = {
    "app.event.onSwipeDown": {
        callback: function () {
            event.trigger("AppSwipeDown");
        }
    },
    "app.event.onSwipeStart": {
        callback: function () {
            event.trigger("AppSwipeStart");
        }
    }
};

utils.mixin(events, _self);

module.exports = _self;

});
define('ripple/platform/webworks.tablet/2.0.0/spec/device', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event');

module.exports = {
    "transports": {
        "TCPCellular": {
            "name": "Cellular TCP",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "WAP": {
            "name": "WAP",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "WAP2": {
            "name": "WAP 2.0",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "MDS": {
            "name": "MDS",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "BISB": {
            "name": "BIS B",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "Unite": {
            "name": "Unite!",
            "control": {
                "type": "checkbox",
                "value": false
            }
        },
        "TCPWifi": {
            "name": "Wifi TCP",
            "control": {
                "type": "checkbox",
                "value": true
            }
        }
    },
    "identity": {
        "PIN": {
            "name": "PIN",
            "control": {
                "type": "text",
                "value": "43A8C489"
            }
        }
    },
    "battery": {
        "state": {
            "name": "Handset is Charging",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("DeviceBatteryStateChanged", [setting]);
            }
        },
        "level":  {
            "name": "Charge Level (% remaining)",
            "control": {
                "type": "select",
                "value": 100
            },
            "options": (function () {
                var i,
                    optionList = {};

                for (i = 0; i <= 100; i++) {
                    optionList[i] = i;
                }

                return optionList;
            }()),
            "callback": function (setting) {
                event.trigger("DeviceBatteryLevelChanged", [setting]);
            }
        }
    },
    "system": {
        "isMassStorageActive": {
            "name": "Mass Storage Is Connected",
            "control": {
                "type": "checkbox",
                "value": true
            }
        },
        "hasDataCoverage": {
            "name": "Has Data Coverage",
            "control": {
                "type": "checkbox",
                "value": true
            },
            "callback": function (setting) {
                event.trigger("CoverageChange");
                require('ripple/bus').send("network", setting);
            }
        },
        "lag": {
            "name": "Lag the network",
            "control": {
                type: "checkbox",
                value: false
            },
            "callback": function (setting) {
                require('ripple/bus').send("lag", setting);
            }
        },
        "network": {
            "name": "Data Network",
            "control": {
                "type": "select",
                "value": "3GPP"
            },
            "options": {
                "3GPP" : "3GPP",
                "CDMA": "CDMA",
                "iDEN": "iDEN",
                "Wi-Fi": "Wi-Fi"
            },
            "callback": function (setting) {
                event.trigger("CoverageChange");
            }
        }
    }
};

});
define('ripple/platform/webworks.tablet/2.0.0/spec/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    plugins: [
        "accelerometer",
        "deviceSettings",
        "geoView",
        "platformEvents",
        "widgetConfig",
        "build"
    ]
};

});
define('ripple/platform/webworks.tablet/2.0.0/spec', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {

    id: "webworks.tablet",
    version: "2.0.0",
    name: "WebWorks-TabletOS",

    persistencePrefix: "rim-tablet-",

    ui: require('ripple/platform/webworks.tablet/2.0.0/spec/ui'),
    device: require('ripple/platform/webworks.tablet/2.0.0/spec/device'),
    config: require('ripple/platform/webworks.core/2.0.0/spec/config'),
    events: require('ripple/platform/webworks.tablet/2.0.0/spec/events'),

    initialize: function () {},

    objects: {
        XMLHttpRequest: {
            path: "webworks.tablet/2.0.0/XMLHttpRequest"
        },
        Coordinates: {
            path: "w3c/1.0/Coordinates"
        },
        Position: {
            path: "w3c/1.0/Position"
        },
        PositionError: {
            path: "w3c/1.0/PositionError"
        },
        navigator: {
            path: "w3c/1.0/navigator",
            children: {
                geolocation: {
                    path: "w3c/1.0/geolocation"
                }
            }
        },
        blackberry: {
            children: {
                transport: {
                    path: "webworks.core/2.0.0/client/transport"
                },
                events: {
                    path: "webworks.core/2.0.0/client/events"
                },
                app: {
                    path: "webworks.tablet/2.0.0/client/app",
                    feature: "blackberry.app",
                    children: {
                        event: {
                            path: "webworks.tablet/2.0.0/client/appEvent",
                            feature: "blackberry.app.event"
                        }
                    }
                },
                invoke: {
                    path: "webworks.tablet/2.0.0/client/invoke",
                    feature: "blackberry.invoke",
                    children: {
                        BrowserArguments: {
                            path: "webworks.tablet/2.0.0/client/BrowserArguments",
                            feature: "blackberry.invoke.BrowserArguments"
                        },
                        CameraArguments: {
                            path: "webworks.tablet/2.0.0/client/CameraArguments",
                            feature: "blackberry.invoke.CameraArguments"
                        }
                    }
                },
                identity: {
                    path: "webworks.tablet/2.0.0/client/identity",
                    feature: "blackberry.identity"
                },
                system: {
                    path: "webworks.tablet/2.0.0/client/system",
                    children: {
                        event: {
                            path: "webworks.tablet/2.0.0/client/systemEvent"
                        }
                    }
                },
                ui: {
                    children: {
                        dialog: {
                            path: "webworks.core/2.0.0/client/dialog",
                            feature: "blackberry.ui.dialog"
                        }
                    }
                },
                utils: {
                    path: "webworks.core/2.0.0/client/utils",
                    feature: "blackberry.utils"
                },
                io: {
                    children: {
                        dir: {
                            path: "webworks.tablet/2.0.0/client/io/dir",
                            feature: "blackberry.io.dir"
                        },
                        file: {
                            path: "webworks.core/2.0.0/client/io/file",
                            feature: "blackberry.io.file"
                        }
                    }
                }
            }
        }
    }
};

});
define('ripple/omgwtf', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event'),
    db = require('ripple/db'),
    _loaded = false,
    _self;

function _delay(action) {
    window.setTimeout(function () {
        if (!_loaded) {
            if (jQuery(".first-run-window").is(":visible")) {
                _delay(action);
            } else {
                action();
            }
        }
    }, 10000);
}

function _hide() {
    jQuery(".error-window").css({display: 'none'});
    jQuery(".error-dialog").css({display: 'none'});
}

function _show() {
    jQuery(".error-window").css({display: 'block'});

    jQuery(".error-dialog").css({
        display: 'block',
        left: (jQuery(document).width() / 2) - 277 + "px"
    });

    jQuery("#error-wait").click(function () {
        _hide();
        _delay(_show);
    });

    jQuery("#error-panic").click(function () {
        db.removeAll(null, function () {
            window.tinyHipposReload = true;
            localStorage.clear();
            location.reload();
        });
    });
}

_delay(_show);

_self = {
    initialize: function (previous, baton) {
        event.on("TinyHipposLoaded", function () {
            _loaded = true;
        });
    },
    show: _show,
    hide: _hide
};

module.exports = _self;

});
define('ripple/bus', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _send = document.getElementById("bus-send"),
    _receive = document.getElementById("bus-receive"),
    _evt = document.createEvent("Events");

_evt.initEvent('bus-init', true, true);
document.dispatchEvent(_evt);

module.exports = {
    send: function (msg, data, callback) {
        var m = document.createElement("span");
        m.dataset.msg = msg;
        m.innerHTML = JSON.stringify(data);

        if (callback) {
            m.dataset.callback = Math.uuid();
            this.receive(m.dataset.callback, callback);
        }

        _send.appendChild(m);
    },

    receive: function (msg, handler) {
        if (!handler) {
            return;
        }

        _receive.addEventListener("DOMNodeInserted", function (evt) {
            if (evt.target.dataset.msg === msg) {
                handler(JSON.parse(evt.target.innerHTML));
            }
        });
    },

    ajax: function (method, url, data, success, fail) {
        this.send("xhr", {
            method: method,
            url: url,
            data: data
        }, function (result) {
            if (result.code === 200) {
                success(result.data);
            }
            else {
                fail(result);
            }
        });
    }
};

});
define('ripple/accelerometer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    event = require('ripple/event'),
    Rotation = require('ripple/platform/w3c/1.0/Rotation'),
    Acceleration = require('ripple/platform/w3c/1.0/Acceleration'),
    _motion = {
        acceleration: new Acceleration(0, 0, 0),
        accelerationIncludingGravity: new Acceleration(0, 0, -9.81),
        rotationRate: new Rotation(0, 0, 0),
        orientation: new Rotation(0, 0, 0),
        timestamp: new Date().getTime()
    };

function _validateAccelerometerInfo(x, y, z) {
    return !(isNaN(x) || isNaN(y) || isNaN(z));
}

_self = {
    getInfo: function () {
        return utils.copy(_motion);
    },

    setInfo: function (e) {
        var triggerDeviceMotion = false,
            triggerDeviceOrientation = false;

        if (e.x !== undefined && e.y !== undefined && e.z !== undefined) {
            _motion = {
                acceleration: new Acceleration(e.x, e.y, e.z),
                accelerationIncludingGravity: new Acceleration(e.x, e.y, e.z),
                rotationRate: new Rotation(0, 0, 0),
                orientation: new Rotation(e.alpha, e.beta, e.gamma),
                timestamp: new Date().getTime()
            };
            triggerDeviceMotion = true;
            triggerDeviceOrientation = true;
        }
        else {
            _motion = {
                acceleration: new Acceleration(0, 0, 0),
                accelerationIncludingGravity: new Acceleration(0, 0, -9.81),
                rotationRate: new Rotation(0, 0, 0),
                orientation: new Rotation(0, 0, 0),
                timestamp: new Date().getTime()
            };
        }

        if (triggerDeviceMotion) {
            event.trigger("DeviceMotionEvent", [_motion]);
        }

        if (triggerDeviceOrientation) {
            event.trigger("DeviceOrientationEvent", [_motion]);
        }

        event.trigger("AccelerometerInfoChangedEvent", [_motion]);
    },

    shake: function (shakeXtimes) {
        var id,
            count = 1,
            stopCount = shakeXtimes || 17,
            oldX = _motion.accelerationIncludingGravity.x;


        id = setInterval(function () {
            var freq = 1,
                amp = 30,
                value = Math.round(amp * Math.sin(freq * count * (180 / Math.PI)) * 100) / 100;

            if (count > stopCount) {
                _motion.acceleration.x = oldX;
                _motion.accelerationIncludingGravity.x = oldX;
                event.trigger("AccelerometerInfoChangedEvent", [_motion]);
                clearInterval(id);
                return;
            }

            _motion.acceleration.x = value;
            _motion.accelerationIncludingGravity.x = value;

            event.trigger("AccelerometerInfoChangedEvent", [_motion]);

            count++;

        }, 80);

    }
};

module.exports = _self;

});
define('ripple/db', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    _db,
    utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    _cache = {};

function _validateAndSetPrefix(prefix) {
    if (prefix) {
        utils.validateArgumentType(prefix, "string");
    }

    return prefix || constants.COMMON.PREFIX;
}

function _createKey(key, prefix) {
    return _validateAndSetPrefix(prefix) + key;
}

function _createItem(key, value, prefix) {
    return {
        id: _createKey(key, prefix),
        key: key,
        value: value,
        prefix: _validateAndSetPrefix(prefix)
    };
}

function _save(key, value, prefix, callback) {
    var item = _createItem(key, value, prefix);
    _cache[item.id] = item;

    _db.transaction(function (tx) {
        tx.executeSql('REPLACE INTO persistence (id, key, value, prefix) VALUES (?, ?, ?, ?)', [item.id, item.key, item.value, item.prefix], function () {
            return callback && callback();
        });
    });
}

function _retrieve(key, prefix) {
    var item = _cache[_createKey(key, prefix)];
    return item ? item.value : undefined;
}

function _retrieveAll(prefix, callback) {
    var result = {};

    if (prefix) {
        utils.forEach(_cache, function (value, key) {
            if (value.prefix === prefix) {
                result[value.key] = value.value;
            }
        });
    }

    callback.apply(null, [result]);
}

function _remove(key, prefix, callback) {
    delete _cache[_createKey(key, prefix)];

    _db.transaction(function (tx) {
        tx.executeSql('DELETE FROM persistence WHERE key = ? AND prefix = ?', [key, _validateAndSetPrefix(prefix)], function () {
            return callback && callback();
        });
    });
}

function _removeAll(prefix, callback) {
    utils.forEach(_cache, function (value, key) {
        if (!prefix || key.indexOf(prefix) === 0) {
            delete _cache[key];
        }
    });

    _db.transaction(function (tx) {
        if (prefix) {
            tx.executeSql('DELETE FROM persistence WHERE prefix = ?', [prefix], function () {
                return callback && callback();
            });
        } else {
            tx.executeSql('DELETE FROM persistence', [], function () {
                return callback && callback();
            });
        }
    });
}

_self = {
    save: function (key, value, prefix, callback) {
        _save(key, value, prefix, callback);
        event.trigger("StorageUpdatedEvent");
    },

    saveObject: function (key, obj, prefix, callback) {
        _save(key, JSON.stringify(obj), prefix, callback);
        event.trigger("StorageUpdatedEvent");
    },

    retrieve: function (key, prefix) {
        return _retrieve(key, prefix);
    },

    retrieveObject: function (key, prefix) {
        var retrievedValue = _retrieve(key, prefix);
        return retrievedValue ? JSON.parse(retrievedValue) : retrievedValue;
    },

    retrieveAll: function (prefix, callback) {
        return _retrieveAll(prefix, callback);
    },

    remove: function (key, prefix, callback) {
        event.trigger("StorageUpdatedEvent");
        _remove(key, prefix, callback);
    },

    removeAll: function (prefix, callback) {
        _removeAll(prefix, callback);
        event.trigger("StorageUpdatedEvent");
    },

    initialize: function (previous, baton) {
        baton.take();

        _db = openDatabase('tinyHippos', '1.0', 'tiny Hippos persistence', 1024 * 1024);
        _db.transaction(function (tx) {
            tx.executeSql('CREATE TABLE IF NOT EXISTS persistence (id unique, key, value, prefix)');

            tx.executeSql('SELECT id, key, value, prefix FROM persistence', [], function (tx, results) {
                var len = results.rows.length, i, item;

                for (i = 0; i < len; i++) {
                    item = results.rows.item(i);
                    _cache[item.id] = item;
                }

                baton.pass();
            });
        });
    }
};

module.exports = _self;

});
define('ripple/notifications', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    event = require('ripple/event');

function _validateAndInitNType(nType) {
    nType = nType || "normal";

    if (nType !== "normal" && nType !== "error") {
        exception.raise(exception.types.NotificationType, "Unknown Notification Type == " + nType + ",when dealing with Console notification.");
    }

    return nType;
}

function _processNotification(nType, stateType, message) {
    nType = _validateAndInitNType(nType);
    message = message || "";

    var display,
        displayText,
        className,
        notificationIcon,
        box = document.getElementById(constants.NOTIFICATIONS.MAIN_CONTAINER_CLASS),
        msgBox = document.getElementById(constants.NOTIFICATIONS.MESSAGE_TEXT_CONTAINER_CLASS);

    className = "ui-widget";

    switch (stateType) {

    case constants.NOTIFICATIONS.STATE_TYPES.CLOSE:
        display = "display: none;"; //need to do this better.
        displayText = "";
        break;

    case constants.NOTIFICATIONS.STATE_TYPES.OPEN:
        display = "display: block;"; //need to do this better.
        displayText = message;
        if (nType === "error") {
            displayText = "Oh Snap!\n\n" + displayText;
            className += " ui-state-error ui-corner-all";
            notificationIcon = '<span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span>';
        }
        else {
            className += " ui-state-highlight ui-corner-all";
            notificationIcon = '<span class="ui-icon ui-icon-info" style="float: left; margin-right: .3em;"></span>';
        }
        break;

    default:
        exception.raise(exception.types.NotificationStateType, "Unknown StateType == " + stateType.toString());
    }

    msgBox.innerHTML = notificationIcon + displayText;
    box.setAttribute("class", className);
    box.setAttribute("style", display);

}

module.exports = {
    openNotification: function (nType, msg) {
        _processNotification(nType, constants.NOTIFICATIONS.STATE_TYPES.OPEN, msg);
    },

    closeNotification: function (nType) {
        _processNotification(nType, constants.NOTIFICATIONS.STATE_TYPES.CLOSE);
    }
};

});
define('ripple/xhr', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    utils = require('ripple/utils'),
    ui = require('ripple/ui'),
    helpers = require('ripple/xhr/helpers'),
    XHR = window.XMLHttpRequest;

module.exports = {
    initialize: function (previous, baton) {
        window.XMLHttpRequest = require('ripple/xhr/base');

        if (helpers.proxyEnabled() && !ui.registered("omnibar")) {
            var isFileScheme = utils.location().protocol.match(/^file:/);
            window.XMLHttpRequest = require(isFileScheme ? 'ripple/xhr/jsonp' : 'ripple/xhr/cors');
        }
    }
};

});
define('ripple/widgetConfig', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var exception = require('ripple/exception'),
    event = require('ripple/event'),
    app = require('ripple/app'),
    _console = require('ripple/console'),
    utils = require('ripple/utils'),
    platform = require('ripple/platform'),
    _validationResult = {
        valid: false,
        message: "",
        value: null
    },
    _configValidationResults = null;

function _failNodeValidation(schemaNode, message, value, node) {
    var validationResult = utils.copy(_validationResult);

    if (!schemaNode.validationResult) {
        schemaNode.validationResult = [];
    }
    validationResult.valid = false;
    if (value) {
        validationResult.value = value;
    }
    else {
        delete(validationResult.value);
    }
    validationResult.message = schemaNode.nodeName + message;
    validationResult.node = node;

    schemaNode.validationResult.push(validationResult);
}

function _createEmptyNodeValidation(node) {

    var validationResult = utils.copy(_validationResult),
        attributeValidationResult, attribute;

    if (!node.validationResult) {
        node.validationResult = [];
    }

    validationResult.value = "";
    delete(validationResult.valid);
    delete(validationResult.message);

    if (node.attributes) {
        for (attribute in node.attributes) {
            if (node.attributes.hasOwnProperty(attribute)) {
                if (!validationResult.attributes) {
                    validationResult.attributes = {};
                }

                attributeValidationResult = utils.copy(_validationResult);

                attributeValidationResult.attributeName = node.attributes[attribute].attributeName;
                delete(attributeValidationResult.value);
                delete(attributeValidationResult.valid);
                delete(attributeValidationResult.message);

                validationResult.attributes[attributeValidationResult.attributeName] = attributeValidationResult;
            }
        }
    }

    node.validationResult.push(validationResult);
}

function _validateValue(valueToTest, schemaNode) {
    var failMessage = "",
        nodeValue,
        numbers,
        numberRangeIndex,
        numberRange,
        range1,
        range2;

    switch (schemaNode.type) {
    case "string":
        if (typeof valueToTest !== "string") {
            failMessage = " value was expected to be of type string but was typeof: " + typeof(valueToTest);
        }
        break;
    case "number":
        nodeValue = parseFloat(valueToTest);
        if (isNaN(nodeValue)) {
            failMessage = " value was expected to be of type number but was typeof: " + typeof(valueToTest);
        }
        break;
    case "integer":
        nodeValue = parseInt(valueToTest, 10);
        if (isNaN(nodeValue)) {
            failMessage = " value was expected to be of type number but was typeof: " + typeof(valueToTest);
        }
        break;
    case "boolean":
        if (valueToTest !== "false" && valueToTest !== "true") {
            failMessage = " value was expected to be of type boolean (i.e. 'true' or 'false' but was: " + valueToTest;
        }
        break;
    case "list":
        if (!utils.arrayContains(schemaNode.listValues, valueToTest)) {
            failMessage = " value is not recognized as being valid, it was:<br/><br/><span class=\"ui-text-fail\">" + valueToTest +
                    "</span><br/><br/>Valid values are:<p class=\"ui-text-pass\">" + schemaNode.listValues.join(" <br/> ") + "</p>";
        }
        break;
    case "listBoolean":
    case "listDefault":
        if (!utils.arrayContains(schemaNode.listValues, valueToTest)) {
            failMessage = " value is not recognized as being valid, it was:<br/><br/><span class=\"ui-text-fail\">" + valueToTest +
                    "</span><br/><br/>The framework will assume the value to be:<p class=\"ui-text-pass\">" + schemaNode.defaultValue + "</p>";
        }
        break;
    case "listNumbers":
        numbers = valueToTest.split(",");

        for (numberRangeIndex = 0; numberRangeIndex < numbers.length; numberRangeIndex++) {
            numberRange = valueToTest.split("-");
            if (numberRange.length > 1) {
                range1 = parseInt(numberRange[0], 10);
                range2 = parseInt(numberRange[1], 10);
                if (isNaN(range1) || isNaN(range2)) {
                    failMessage = " range values where not recognized as being valid, they was: " + range1 +
                            " and " + range2 + " :: valid values should be of type 'integer'";
                    break;
                }
            }
            else if (numberRange.length === 1) {
                range1 = parseInt(numberRange[0], 10);
                if (isNaN(range1)) {
                    failMessage = " value was not recognized as being valid, it was: " + range1 +
                            " :: valid values should be of type 'integer'";
                    break;
                }
            }
        }
        break;
    case "regex":
        if (!valueToTest.match(schemaNode.regex)) {
            failMessage = " value does not match expected format. Value should pass this regular expression validation: " + schemaNode.regex;
        }
        break;
    case "iso-language":
        break;
    default:
        exception.raise(exception.types.Application, "Schema node with value type of: " + schemaNode.type + " is not known");
    }

    return failMessage;
}

function _passNodeValidation(schemaNode, value, node) {
    var validationResult = utils.copy(_validationResult);

    if (!schemaNode.validationResult) {
        schemaNode.validationResult = [];
    }
    validationResult.valid = true;
    validationResult.node = node;
    if (value) {
        validationResult.value = value;
    }
    else {
        delete(validationResult.value);
    }
    delete(validationResult.message);

    schemaNode.validationResult.push(validationResult);
}

function _validateNodeValue(schemaNode, node) {
    var failMessage,
        valueToTest = node && node.nodeValue ? node.nodeValue.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : null;

    if (schemaNode.type && valueToTest) {

        failMessage = _validateValue(valueToTest, schemaNode);

        if (failMessage !== "") {
            _failNodeValidation(schemaNode, failMessage, valueToTest, node);
            return;
        }
    }
    _passNodeValidation(schemaNode, valueToTest, node);
}

function _failNodeAttributeValidation(node, attribute, message, value) {
    var nodeValidationResult = node.validationResult ? node.validationResult.pop() : utils.copy(_validationResult),
        attributeValidationResult = utils.copy(_validationResult);

    if (!nodeValidationResult.attributes) {
        nodeValidationResult.attributes = {};
    }

    nodeValidationResult.valid = false;
    nodeValidationResult.message = "One or more attributes failed validation";

    attributeValidationResult.attributeName = attribute.attributeName;
    attributeValidationResult.valid = false;
    if (value) {
        attributeValidationResult.value = value;
    }
    else {
        delete(attributeValidationResult.value);
    }
    attributeValidationResult.message = node.nodeName + "." + attribute.attributeName + message;

    nodeValidationResult.attributes[attribute.attributeName] = attributeValidationResult;
    node.validationResult.push(nodeValidationResult);
}

function _passNodeAttributeValidation(node, attribute, value) {
    var nodeValidationResult = node.validationResult ? node.validationResult.pop() : utils.copy(_validationResult),
        attributeValidationResult = utils.copy(_validationResult);

    if (!nodeValidationResult.attributes) {
        nodeValidationResult.attributes = {};
    }

    attributeValidationResult.attributeName = attribute.attributeName;
    attributeValidationResult.valid = true;
    if (value) {
        attributeValidationResult.value = value;
    }
    else {
        delete(attributeValidationResult.value);
    }
    delete(attributeValidationResult.message);

    nodeValidationResult.attributes[attribute.attributeName] = attributeValidationResult;
    node.validationResult.push(nodeValidationResult);
}

function _validateNodeAttributeValue(schemaNode, schemaNodeAttribute, attribute) {
    var failMessage,
        valueToTest = attribute ? attribute.value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : null;

    if (schemaNodeAttribute.type && valueToTest) {

        failMessage = _validateValue(valueToTest, schemaNodeAttribute);

        if (failMessage !== "") {
            _failNodeAttributeValidation(schemaNode, schemaNodeAttribute, failMessage, valueToTest);
            return;
        }
    }
    _passNodeAttributeValidation(schemaNode, schemaNodeAttribute, valueToTest);
}

function _validateNodeAttributes(schemaNode, node, children) {

    var siblings = utils.filter(children, function (child) {
            return child !== node;
        }),
        attributeConverter = function (attribute) {
            var _self = {
                toValue: function (n) {
                    var obj = _self.toNode(n);
                    return obj ? obj.value : null;
                },
                toNode: function (n) {
                    return n.attributes.getNamedItem(attribute.attributeName);
                }
            };

            return _self;
        };

    utils.forEach(schemaNode.attributes, function (attribute) {

        var convert = attributeConverter(attribute),
            dupe = false;

        if (attribute.unique) {
            // this means we need to check and see if there are other node with the same name
            // and ensure that they have a different value for this attributes, if not... fail

            dupe = siblings.some(function (sibling) {
                return convert.toValue(sibling) === convert.toValue(node);
            });

            if (dupe) {
                _failNodeAttributeValidation(schemaNode,
                        attribute,
                        " node is allowed to appear multiple times, however it must be unique based on this attribute and in this case another node with an identical attribute vale was found",
                        convert.toValue(node));
                return;
            }
        }

        if (attribute.required && !convert.toValue(node)) {
            _failNodeAttributeValidation(schemaNode, attribute, " attribute was expected but not found", null);
        }
        else {
            _validateNodeAttributeValue(schemaNode, attribute, convert.toNode(node));
        }
    });
}


function _validateNode(schemaNode, parentNode) {
    var children = utils.filter(parentNode.childNodes, function (child) {
        return child && child.nodeName === schemaNode.nodeName;
    });

    if (children.length === 0) {
        if (schemaNode.required) {
            _failNodeValidation(schemaNode, " node expected, but not found", null, null);
        }
    }

    utils.forEach(children, function (child) {
        if (schemaNode.occurrence !== 0 && schemaNode.occurrence < children.length) {
            _failNodeValidation(schemaNode, " node: more then " + schemaNode.occurrence + " node(s) found", null, child);
        }
        else {
            _validateNodeValue(schemaNode, child.childNodes[0] || child);

            _validateNodeAttributes(schemaNode, child, children);
        }

        utils.forEach(schemaNode.children, function (schema) {
            _validateNode(schema, child);
        });
    });
}

function _validateAgainstSchemaNode(configSchema, configXML) {
    var results = utils.copy(configSchema);
    try {
        _validateNode(results[configSchema.rootElement], configXML);
    }
    catch (e) {
        exception.handle(e, true);
    }

    return results;
}

function _validate(configXML) {
    // traverse the config schema JSON object
    // TODO: update to get platform.getPlatformConfigSpec().schema
    return _validateAgainstSchemaNode(platform.current().config.schema, configXML);
}

function _process(results) {
    // Check to make sure that widget is the correct version (i.e. config.xml needs to match selected platform)
    var validVersion = app.validateVersion(results);

    if (!validVersion) {
        _console.warn("Your application does not appear to match" +
                " the platform you have selected. The version number in your configuration might not " +
                "match the selected platform version or your configuration file has errors in it.");
    }

    // save widget info
    app.saveInfo(results);
    event.trigger("WidgetInformationUpdated");

    // Check for readonly preferences (WAC only?)

    if (app.getInfo().preferences !== {}) {
        event.trigger("StorageUpdatedEvent");
    }
}

function _xmlToJson(xml) {
    var obj = {};

    if (xml.nodeType === 1) { // element
        if (xml.attributes.length > 0) {
            obj["@attributes"] = {};
            utils.forEach(xml.attributes, function (attribute) {
                obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
            });
        }
    } 
    else if (xml.nodeType === 3) { // text node
        obj = xml.nodeValue;
    }

    if (xml.hasChildNodes && xml.hasChildNodes()) {
        utils.forEach(xml.childNodes, function (child) {
            if (!child.nodeName) {
                return;
            }
            if (!obj[child.nodeName]) {
                obj[child.nodeName] = [];
            }
            obj[child.nodeName].push(_xmlToJson(child));
        });
    }

    return obj;
}

module.exports = {

    validate: function (configXML) {
        utils.validateNumberOfArguments(1, 1, arguments.length);
        return _validate(configXML);
    },

    initialize: function (previous, baton) {
        var xmlHttp = new XMLHttpRequest(),
            config = platform.current().config,
            fileName = config ? config.fileName : null,
            results;

        if (!fileName) {
            return;
        }

        try {
            xmlHttp.open("GET", utils.appLocation() + fileName, false);
            xmlHttp.send();
            if (xmlHttp.responseXML) {
                results = _validate(xmlHttp.responseXML);
                results.rawJSON = _xmlToJson(xmlHttp.responseXML);
                _process(results);
                _configValidationResults = results;
            }
            else {
                _process();
                _configValidationResults = null;
                require('ripple/ui/plugins/widgetConfig').initialize();
            }
        }
        catch (e) {
            exception.handle(e);
        }
    },

    getValidationResults: function () {
        return _configValidationResults;
    }
};

});
define('ripple/app', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _data = {},
    utils = require('ripple/utils'),
    _self;

_self = {
    setInfo: function (info) {
        if (!info) {
            _data = {};
        }
        _data = info;
    },

    getInfo: function () {
        return utils.copy(_data);
    },

    isPreferenceReadOnly: function (key) {
        return (_data.preferences &&
                _data.preferences[key] &&
                _data.preferences[key].readonly &&
                _data.preferences[key].readonly === true);
    },

    validateVersion: function (configValidationObject) {
        // TODO: WTF figure this out, platform is empty object when require at require time
        // could be that the new platform _getBuilder code dies when called, beforre it is initialized
        var spec = require('ripple/platform').current();
        if (typeof spec.config.validateVersion === "function" && configValidationObject) {
            return spec.config.validateVersion(configValidationObject);
        }

        return true;
    },

    saveInfo: function (configValidationObject) {
        var spec = require('ripple/platform').current(),
            info = null;
        if (typeof spec.config.extractInfo === "function") {
            info = spec.config.extractInfo(configValidationObject);
        }

        if (info) {
            _self.setInfo(info);
        }
    }

};

module.exports = _self;

});
define('ripple/documentEventListener', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    constants = require('ripple/constants'),
    deviceSettings = require('ripple/deviceSettings'),
    ui = require('ripple/ui'),
    _self;

function _bind(name, win) {
    var _listeners = [];

    return {
        add: function (callback, useCapture) {
            // ignore non-function
            if (typeof callback === "function") {
                // ignore useCapture as we could not handle it
                if (!useCapture) {
                    if (!_listeners.some(function (listener) {
                        return (listener === callback);
                    })) {
                        _listeners.push(callback);
                    }
                }
            }
        },
        exec: function (arg) {
            _listeners.forEach(function (listener) {
                listener.apply(win, arg);
            });
        },
        remove: function (callback, useCapture) {
            // ignore non-function
            if (typeof callback === "function") {
                // ignore useCapture as we do not add them into _listeners
                if (!useCapture) {
                    _listeners = _listeners.filter(function (listener) {
                        return (listener !== callback);
                    });
                }
            }
        }
    };
}

_self = {
    mask: function (frame) {
        /* 
         * The current issue is that "document.addEventListener(visibilitychange, function(){...})" 
         * does not work if it is invoked in the document.DOMContentLoaded listeners, for example, at 
         * JQuery(document).ready function.

         * The reason is that window.DOMContentLoaded is fired after the document.DOMContentLoaded. 
         * Currently we have not found a proper event to override the document.addEventListener. 
         * The beforeload is fine for window.addEventListener, while does not work for document.addEventListener 
         * because the contentDocument will be reset after loading. 
         */
        frame.addEventListener("DOMContentLoaded", function () {
            /*
            var widgetDocument = frame.contentDocument,
                _pageVisibility,
                add = widgetDocument.addEventListener,
                remove = widgetDocument.removeEventListener;

            widgetDocument.PAGE_HIDDEN  = "hidden";
            widgetDocument.PAGE_VISIBLE = "visible";
            widgetDocument.PAGE_PREVIEW = "preview";

            function _lockScreen(on) {
                var hidden = on;

                if (on) {
                    ui.showOverlay("lock-screen-window", function (background) {});
                } else {
                    ui.hideOverlay("lock-screen-window", function (background) {});
                }

                event.trigger("visibilitychange", [hidden]);
            }

            function _isLockScreenOn() {
                return deviceSettings.retrieve("Config.lockScreen");
            }

            _lockScreen(_isLockScreenOn());

            _pageVisibility = _bind("visibilitychange", frame.contentWindow);

            widgetDocument.addEventListener = function (event, callback, useCapture) {
                switch (event) {
                case "visibilitychange":
                    _pageVisibility.add(callback, useCapture);
                    break;

                default:
                    add.apply(widgetDocument, arguments);
                    break;
                }
            };

            widgetDocument.removeEventListener = function (event, callback, useCapture) {
                _pageVisibility.remove(callback, useCapture);
                remove.apply(widgetDocument, arguments);
            };

            event.on("LockScreenChanged", function (on) {
                _lockScreen(on);
            });

            event.on("visibilitychange", function (hidden) {
                widgetDocument.hidden = hidden;
                widgetDocument.visibilityState = hidden ? widgetDocument.PAGE_HIDDEN : widgetDocument.PAGE_VISIBLE;
                _pageVisibility.exec();
            });
            */
        });
    }
};

module.exports = _self;

});
define('ripple/event', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    _listeners = {};

function _on(eventType, listener, scope, once) {
    if (!eventType) {
        throw "eventType must be truthy";
    }
    _listeners[eventType] = _listeners[eventType] || [];
    _listeners[eventType].push({
        func: listener,
        scope: scope,
        once: !!once
    });
}

function _deleteEventHandler(eventType, listener, scope) {
    if (!eventType) {
        throw "eventType must be truthy";
    }

    var listeners = _listeners[eventType];

    if (listeners && listeners.length === 1) {
        delete _listeners[eventType];
    }
    else {
        _listeners[eventType] = listeners.filter(function (listener) {
            return (listener.func !== listener);
        });
    }
}

function _trigger(listener, args, sync) {
    try {
        if (sync) {
            listener.func.apply(listener.scope, args);
        }
        else {
            setTimeout(function () {
                listener.func.apply(listener.scope, args);
            }, 1);
        }
    }
    catch (e) {
        exception.handle(e);
    }
}

module.exports = {
    on: function (eventType, listener, scope) {
        _on(eventType, listener, scope, false);
    },

    once: function (eventType, listener, scope) {
        _on(eventType, listener, scope, true);
    },

    trigger: function (eventType, args, sync) {
        args = args || [];
        sync = sync || false;

        var listeners = _listeners[eventType];

        if (listeners) {
            listeners.forEach(function (listener) {
                _trigger(listener, args, sync);
            });

            _listeners[eventType] = listeners.filter(function (listener) {
                return !listener.once;
            });
        }
    },

    eventHasSubscriber: function (eventType) {
        return !!_listeners[eventType];
    },

    getEventSubscribers: function (eventType) {
        return utils.copy(_listeners[eventType]) || [];
    },

    clear: function (eventType) {
        if (eventType) {
            delete _listeners[eventType];
        }
    },

    deleteEventHandler: function (eventType, listener, scope) {
        if (eventType) {
            _deleteEventHandler(eventType, listener, scope, false);
        }
    }
};

});
define('ripple/sensorSettings', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _PERSISTENCE_KEY = "sensorsettings",
    db = require('ripple/db'),
    platform = require('ripple/platform'),
    _currentSensorSettings = {},
    _self;

function _default(key) {
    var keys = key.split("."),
        defaults = platform.current().sensor;

    if (keys.length === 1)
        return defaults[key];

    return keys.length === 2 &&
           defaults[keys[0]] &&
           defaults[keys[0]][keys[1]] &&
           defaults[keys[0]][keys[1]].control ?
           defaults[keys[0]][keys[1]].control.value : undefined;
}

_self = {
    initialize: function () {
        _currentSensorSettings = db.retrieveObject(_PERSISTENCE_KEY) || {};
    },
    register: function (key, obj) {
        _currentSensorSettings[key] = obj;
    },

    persist: function (key, obj) {
        if (key) {
            _currentSensorSettings[key] = obj;
        }

        db.saveObject(_PERSISTENCE_KEY, _currentSensorSettings);
    },

    retrieve: function (key) {
        return _currentSensorSettings.hasOwnProperty(key) ?
               _currentSensorSettings[key] : _default(key);
    },

    retrieveAsInt: function (key) {
        return parseInt(_self.retrieve(key), 10);
    },

    retrieveAsBoolean: function (key) {
        return !!_self.retrieve(key);
    }
};

module.exports = _self;

});
define('ripple/fs', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    _console = require('ripple/console'),
    _self, _fs;

function _map(array, callback) {
    var map = [], i;
    for (i = 0; i < array.length; i++) {
        map[i] = callback(array[i], i);
    }
    return map;
}

function _resolveLocalFileSystemURL(path, success, error) {
    return (window.resolveLocalFileSystemURL || window.webkitResolveLocalFileSystemURL)(path, success, error);
}

function _blobBuilder() {
    var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder;
    return new BlobBuilder();
}

function _error(e) {
    var msg = '';

    switch (e.code) {
    case FileError.QUOTA_EXCEEDED_ERR:
        msg = 'QUOTA_EXCEEDED_ERR';
        break;
    case FileError.NOT_FOUND_ERR:
        msg = 'NOT_FOUND_ERR';
        break;
    case FileError.SECURITY_ERR:
        msg = 'SECURITY_ERR';
        break;
    case FileError.INVALID_MODIFICATION_ERR:
        msg = 'INVALID_MODIFICATION_ERR';
        break;
    case FileError.INVALID_STATE_ERR:
        msg = 'INVALID_STATE_ERR';
        break;
    default:
        msg = 'Unknown Error';
        break;
    }

    _console.log('FileSystem error: ' + msg);
}

_self = {
    initialize: function (prev, baton) {
        try {
            var requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

            if (requestFileSystem) {
                baton.take();
            }

            requestFileSystem(window.TEMPORARY, constants.FS_SIZE, function (fs) {
                _fs = fs;
                event.trigger("FileSystemInitialized", null, true);
                baton.pass();
            }, _error);
        }
        catch (e) {
            console.log("File System Not Available");
        }
    },

    ls: function (path, success, error) {
        path = path || "/";

        _fs.root.getDirectory(path, {}, function (dirEntry) {
            var dirReader = dirEntry.createReader();
            dirReader.readEntries(function (entries) {
                success(_map(entries, function (entry, index) {
                    return entry;
                }));
            }, error);
        }, error);
    },

    rm: function (path, success, error, options) {
        options = options || {};

        _fs.root[options.recursive ? "getDirectory" : "getFile"](path, {create: false}, function (entry) {
            entry[options.recursive ? "removeRecursively" : "remove"](function () {
                success();
            }, error);
        }, error);
    },

    rmdir: function (path, success, error, options) {
        options = options || {};

        _fs.root.getDirectory(path, {create: false}, function (entry) {
            entry.remove(function () {
                success();
            }, error);
        }, error);
    },

    mkdir: function (path, success, error) {
        _fs.root.getDirectory(path, {create: true}, function (dirEntry) {
            success(dirEntry);
        }, error);
    },

    mv: function (from, to, success, error) {
        var path = to.replace(/^\//, "").split("/"),
            fileName = path.splice(path.length - 1, 1).toString();

        _self.stat(from, function (entry) {
            _self.stat(path.length > 0 ? path.join("/") : "/", function (dest) {
                entry.moveTo(dest, fileName, function (finalDestination) {
                    success(finalDestination);
                }, error);
            }, error);
        }, error);
    },

    touch: function (path, success, error) {
        _fs.root.getFile(path, {create: true}, function (fileEntry) {
            success(fileEntry);
        }, error);
    },

    cp: function (from, to, success, error) {
        var path = to.replace(/^\//, "").split("/"),
            fileName = path.splice(path.length - 1, 1).toString();

        _self.stat(from, function (entry) {
            _self.stat(path.length > 0 ? path.join("/") : "/", function (dest) {
                entry.copyTo(dest, fileName, function (finalDestination) {
                    success(finalDestination);
                }, error);
            }, error);
        }, error);
    },

    stat: function (path, success, error) {
        var url = "filesystem:" + utils.location().origin + "/temporary/" + path;
        _resolveLocalFileSystemURL(url, function (entry) {
            success(entry);
        }, error);
    },

    write: function (path, contents, success, error, options) {
        options = options || {};

        function write(entry) {
            entry.createWriter(function (fileWriter) {
                var bb = _blobBuilder();

                fileWriter.onwriteend = function (progressEvent) {
                    success(entry);
                };
                fileWriter.onerror = error;

                if (options.mode === "append") {
                    fileWriter.seek(fileWriter.length);
                }

                bb.append(contents);
                fileWriter.write(bb.getBlob('text/plain'));
            }, error);
        }

        _self.stat(path, function (entry) {
            if (options.mode === "append") {
                write(entry);
            } else {
                _self.rm(path, function () {
                    _self.touch(path, write, error);
                }, error);
            }
        }, function (e) {
            if (e.code === FileError.NOT_FOUND_ERR) {
                _self.touch(path, write, error);
            } else {
                error(e);
            }
        });
    },

    read: function (path, success, error) {
        _self.stat(path, function (entry) {
            entry.file(function (file) {
                var reader = new FileReader();

                reader.onloadend = function (progressEvent) {
                    success(progressEvent.target.result);
                };
                reader.onerror = error;

                reader.readAsText(file);
            }, error);
        }, error);
    }
};

module.exports = _self;

});
define('ripple/touchEventEmulator', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var emulatorBridge = require('ripple/emulatorBridge'),
    utils = require('ripple/utils'),
    _isMouseDown, self;

// NOTE: missing view, detail, touches, targetTouches, scale and rotation
function _initTouchEvent(type, canBubble, cancelable, eventData) {
    var touchEvent = emulatorBridge.document().createEvent("Event");
    touchEvent.initEvent(type, canBubble, cancelable);
    utils.mixin(eventData, touchEvent);
    return touchEvent;
}

function _raiseTouchEvent(mouseEvent) {
    var type = "",
        simulatedEvent,
        touchObj,
        eventData;

    switch (mouseEvent.type) {
    case "mousedown":
        type = "touchstart";
        _isMouseDown = true;
        break;
    case "mousemove":
        if (!_isMouseDown) {
            return;
        }
        type = "touchmove";
        break;
    case "mouseup":
        type = "touchend";
        _isMouseDown = false;
        break;
    default:
        return;
    }

    touchObj = {
        clientX: mouseEvent.pageX,
        clientY: mouseEvent.pageY,
        identifier: "",
        pageX: mouseEvent.pageX,
        pageY: mouseEvent.pageY,
        screenX: mouseEvent.pageX,
        screenY: mouseEvent.pageY,
        target: mouseEvent.target
    };

    eventData = {
        altKey: mouseEvent.altKey,
        ctrlKey: mouseEvent.ctrlKey,
        shiftKey: mouseEvent.shiftKey,
        metaKey: mouseEvent.metaKey,
        changedTouches: [touchObj],
        targetTouches: [touchObj],
        touches: [touchObj]
    };

    utils.mixin(touchObj, eventData);

    simulatedEvent = _initTouchEvent(type, true, true, eventData);

    mouseEvent.target.dispatchEvent(simulatedEvent);

    if (typeof mouseEvent.target["on" + type] === "function") {
        mouseEvent.target["on" + type].apply(mouseEvent.target, [simulatedEvent]);
    }
}

function _marshalEvents(win, doc) {
    utils.forEach(["mousedown", "mousemove", "mouseup"],
        function (event) {
            doc.addEventListener(event, _raiseTouchEvent, true);
        });

    win.Node.prototype.ontouchstart = null;
    win.Node.prototype.ontouchend = null;
    win.Node.prototype.ontouchmove = null;
}

self = module.exports = {
    mask: function (win, doc) {
        _marshalEvents(win, doc);
    }
};

});
define('ripple/emulatorBridge', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _isMouseDown = false,
    platform = require('ripple/platform'),
    builder = require('ripple/platform/builder'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    _xhr, _win, _doc;

function _getEmulatedViewportStyle(attr) {
    var vp = document.getElementById("viewport-container");
    return vp["client" + attr];
}

function _screenAvailWidth() {
    return _getEmulatedViewportStyle("Width");
}

function _screenAvailHeight() {
    return _getEmulatedViewportStyle("Height");
}

function _screenWidth() {
    return _getEmulatedViewportStyle("Width");
}

function _screenHeight() {
    return _getEmulatedViewportStyle("Height");
}

function _window_innerWidth() {
    return _getEmulatedViewportStyle("Width");
}

function _window_innerHeight() {
    return _getEmulatedViewportStyle("Height");
}

function _marshalScreen(win) {
    utils.forEach({
        "availWidth": _screenAvailWidth,
        "availHeight": _screenAvailHeight,
        "width": _screenWidth,
        "height": _screenHeight
    }, function (mappedFunc, prop) {
        win.screen.__defineGetter__(prop, mappedFunc);
    });

    utils.forEach({
        "innerWidth": _window_innerWidth,
        "innerHeight": _window_innerHeight
    }, function (mappedFunc, prop) {
        win.__defineGetter__(prop, mappedFunc);
    });
}

module.exports = {
    link: function  (win, doc) {
        _win = win;
        _doc = doc;
        _xhr = win.XMLHttpRequest;

        require('ripple/widgetConfig').initialize();

        var marshal = function (obj, key) {
                window[key] = win[key] = obj;
            },
            currentPlatform = platform.current(),
            sandbox = {};

        marshal(window.tinyHippos, "tinyHippos");
        marshal(window.XMLHttpRequest, "XMLHttpRequest");
        window.onmessage = function (e) {
            if (typeof _frame.contentWindow.onmessage === 'function') {
                _frame.contentWindow.onmessage(e);
            }
        };

        if (currentPlatform.initialize) {
            currentPlatform.initialize(win);
        }

        builder.build(platform.current().objects).into(sandbox);
        utils.forEach(sandbox, marshal);

        _marshalScreen(win);
        _marshalScreen(window);
    },

    document: function () {
        return _doc;
    },

    window: function () {
        return _win;
    },

    xhr: function () {
        return _xhr;
    }
};

});
define('ripple/honeypot', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var noop = function () {};

module.exports = {
    monitor: function (context, target) {

        var setup = function (get, set) {
            set = set || noop;

            context.__defineGetter__(target, noop);
            context.__defineSetter__(target, function (value) {
                context.__defineGetter__(target, get);
                set(value);
            });
        };

        return {
            andReturn: function (value) {
                setup(function () {
                    return value;
                });
            },
            andRun: function (get, set) {
                setup(get, set);
            }
        };
    }
};

});
define('ripple/exception', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _console = require('ripple/console');

function _getStack(depth) {
    var caller,
        stack = "",
        count = 0;

    try {
        caller = arguments.callee.caller.arguments.callee.caller;

        while (count <= depth && caller) {
            stack += "function: " + caller.toString().match(/function\s?(.*)\{/)[1] + "\n";
            caller = caller.arguments.callee.caller;
            count++;
        }
    } catch (e) {
        stack = "failed to determine stack trace (" + (e.name || e.type) + " :: " + e.message + ")";
    }

    return stack;
}

module.exports = {

    types: {
        Application: "Application",
        ArgumentLength: "ArgumentLength",
        ArgumentType: "ArgumentType",
        Argument: "Argument",
        NotificationType: "NotificationType",
        NotificationStateType: "NotificationStateType",
        DomObjectNotFound: "DomObjectNotFound",
        LayoutType: "LayoutType",
        DeviceNotFound: "DeviceNotFound",
        tinyHipposMaskedException: "tinyHipposMaskedException",
        Geo: "Geo",
        Accelerometer: "Accelerometer",
        MethodNotImplemented: "MethodNotImplemented",
        InvalidState: "InvalidState",
        ApplicationState: "ApplicationState"
    },

    handle: function handle(exception, reThrow) {
        reThrow = reThrow || false;

        var eMsg = exception.message || "exception caught!",
        msg = eMsg + "\n\n" + (exception.stack || "*no stack provided*") + "\n\n";

        _console.error(msg);

        if (reThrow) {
            throw exception;
        }
    },

    raise: function raise(exceptionType, message, customExceptionObject) {
        var obj = customExceptionObject || {
                type: "",
                message: "",

                toString: function () {
                    var result = this.name + ': "' + this.message + '"';

                    if (this.stack) {
                        result += "\n" + this.stack;
                    }
                    return result;
                }
            };

        message = message || "";

        obj.name = exceptionType;
        obj.type = exceptionType;
        // TODO: include the exception objects original message if exists
        obj.message = message;
        obj.stack = _getStack(5);

        throw obj;
    },

    throwMaskedException: function throwMaskedException(exceptionType, message, customExceptionObject) {
        try {
            this.raise.apply(this, arguments);
        } catch (e) {
            this.handle(e);
        }
        this.raise(this.types.tinyHipposMaskedException, "tinyhippos terminated your script due to exception");
    }

};

});
define('ripple/bootstrap', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _bound,
    _console = require('ripple/console'),
    ui = require('ripple/ui'),
    db = require('ripple/db'),
    _CURRENT_URL = "current-url";

function _bindObjects(win, doc) {
    if (!win.tinyHippos) {
        require('ripple/emulatorBridge').link(win, doc);
        /// require('ripple/platform/tizen/2.0/touchEvent').mask(win, doc);
        require('ripple/touchEventEmulator').mask(win, doc);
        /// require('ripple/documentEventListener').mask(win, doc);
        require('ripple/deviceMotionEmulator').init(win, doc);
        require('ripple/resizer').init(win, doc);
        _bound = true;
    }
}

function _createFrame(src) {
    var frame = document.createElement("iframe");
    frame.setAttribute("id", "document");
    frame.src = src;

    if (ui.registered("omnibar")) {
        frame.addEventListener("beforeload", function () {
            _bound = false;
            _bindObjects(frame.contentWindow, frame.contentDocument);
            var id = window.setInterval(function () {
                if (_bound) {
                    window.clearInterval(id);
                } else {
                    _bindObjects(frame.contentWindow, frame.contentDocument);
                }
            }, 1);
        });
    }

    return frame;
}

function _cleanBody() {
    require('ripple/utils').forEach(document.body.children, function (child) {
        if (child && child.id && !child.id.match(/ui|tooltip|bus/)) {
            document.body.removeChild(child);
        }

        document.body.removeAttribute("style");
        document.body.removeAttribute("id");
        document.body.removeAttribute("class");
    });
}

function _post(src) {
    var event = require('ripple/event'),
        frame = _createFrame(src);

    _console.log("Initialization Finished (Make it so.)");

    frame.onload = function () {
        var bootLoader = document.querySelector("#emulator-booting"),
            id;
        if (bootLoader) {
            document.querySelector("#ui").removeChild(bootLoader);
        }

        event.trigger("TinyHipposLoaded");

        _cleanBody();
        id = window.setInterval(_cleanBody, 20);

        window.setTimeout(function () {
            window.clearInterval(id);
        }, 1200);

        if (ui.registered("omnibar")) {
            //reset the onload function so that when navigating we can destroy
            //the iframe and create a new one so we can reinject the platform by
            //calling post again.
            frame.onload = function () {
                var url = frame.contentWindow.location.href;
                document.getElementById("viewport-container").removeChild(frame);
                event.trigger("FrameHistoryChange", [url]);
                _console.log("-----------------------------------------------------------");
                _console.log("Pay no attention to that man behind the curtain.");
                _console.log("Environment Warning up again (Set main batteries to auto-fire cycle)");
                _post(url);
            };
        }
    };

    // append frame
    document.getElementById("viewport-container").appendChild(frame);

    delete tinyHippos.boot;
}

function _bootstrap() {
    // TODO: figure this out for web and ext
    //_console.log("-----------------------------------------------------------");
    //_console.log("There be dragons above here!");
    _console.log("Ripple :: Environment Warming Up (Tea. Earl Gray. Hot.)");

    window.tinyHippos = require('ripple');

    tinyHippos.boot(function () {
        var uri = ui.registered('omnibar') ?
                db.retrieve(_CURRENT_URL) || "about:blank" :
                document.documentURI.replace(/enableripple=[^&]*[&]?/i, "").replace(/[\?&]*$/, "");

        _post(uri);
        delete tinyHippos.boot;
    });
}

module.exports = {
    bootstrap: _bootstrap,
    inject: function (frameWindow, frameDocument) {
        _bindObjects(frameWindow, frameDocument);
    }
};

});
define('ripple/constants', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = {
    "API_URL": "http://api.tinyhippos.com",

    "RELEASE_VERSION": "simulator-release-version",

    "SERVICES": {
        "GOOGLE_MAPS_URI": "http://maps.google.com/maps/api/staticmap?size=476x476&maptype=roadmap",
        "GOOGLE_MAPS_API_KEY": "ABQIAAAA-CaPZHXR-0Tzhui_h6gpjhSE_2rGlnYiB7L-ZGVwgaut5s7OYRSlBAaHCzBuZf2_23_vrCOfPxXHjA"
    },

    "FS_SIZE": 1024 * 1024 * 10,

    "COMMON":  {
        "APPLICATION_STATE": "ui-application-state-",
        "PREFIX": "tinyhippos-",
        "MENU_BUTTON" : "menu-button",
        "BACK_BUTTON" : "back-button",
        "HTML_CONTAINER" : "document",
        "INFO_SECTION": "information-sub-container",
        "ORIENTATION_SELECT_PORTRAIT_ID" : "layout-portrait",
        "ORIENTATION_SELECT_LANDSCAPE_ID" : "layout-landscape",
        "PLATFORM_SELECT_ID": "platform-select",
        "DEVICE_SELECT_ID": "device-select",
        "STORAGE_TABLE_BODY_CLASS": "preferences-list-body",
        "STORAGE_COUNT_CONTAINER_ID": "preferences-count",
        "GEO_MAP_CONTAINER_ID": "geo-map",
        "FILESYSTEM_UPDATE_BUTTON_ID_WITH_HASH": "#update-filesystem-button",
        "USER_AGENT_DEFAULT": "default",
        "APPLICATIONS_CONTAINER_ID": "widget-applications-content",
        "STORAGE_CLEAR_BUTTON_ID": "preferences-clear-button",
        "AJAX_LOADER_CONTAINER_CLASS": ".loader",
        "IRRELEVANT_CLASS": "irrelevant",
        "MULTIMEDIA_VOLUME_SLIDER_ID": "media-volume",
        "MULTIMEDIA_VOLUME_FIELD_ID": "media-volume-value",
        "MULTIMEDIA_AUDIO_STATE_FIELD_ID": "media-audio-state",
        "MULTIMEDIA_AUDIO_PLAYING_FIELD_ID": "multimedia-isaudioplaying",
        "MULTIMEDIA_AUDIO_PROGRESS_ID": "media-audio-progress",
        "MULTIMEDIA_AUDIO_FILE_FIELD_ID": "media-audio-file",
        "MULTIMEDIA_VIDEO_STATE_FIELD_ID": "media-video-state",
        "MULTIMEDIA_VIDEO_PLAYING_FIELD_ID": "multimedia-isvideoplaying",
        "MULTIMEDIA_VIDEO_PROGRESS_ID": "media-video-progress",
        "MULTIMEDIA_VIDEO_FILE_FIELD_ID": "media-video-file",
        "EXTENSION_URL_CONTAINER": "extension-url",
        "SECURITY_LEVEL": "security-level"
    },
    "LAUNCHING_HISTORY": "application-launching-history",

    "FILESYSTEM": {
        "PERSISTENCE_KEY": "filesystem",
        "INPUT_PREFIX_ID": "#panel-filesystem-"
    },

    "PLATFORM":  {
        "DEFAULT": {
            "name": "tizen",
            "version": "1.0"
        }
    },

    "DEVICE":  {
        "SAVED_KEY": "device-key"
    },

    "BATTERY":  {
        "TIME": "charging-time",
        "VOLUME": "battery-volume",
        "CHARGING": "is-charging"
    },

    "TOUCHEVENT":  {
        "OPTION": "touch_option",
        "ALTKEY": "touch_altKey",
        "METAKEY": "touch_metaKey",
        "CTRLKEY": "touch_ctrlKey",
        "SHIFTKEY": "touch_shiftKey",
        "CANVAS": "touch_canvas"
    },

    "ENCAPSULATOR":  {
        "DEFAULT_HEIGHT": 684,
        "DEFAULT_WIDTH": 480,
        "LAYOUT": "layout",
        "DISPLAY_LAYOUT": {
            "LANDSCAPE": "landscape",
            "PORTRAIT": "portrait"
        },
        "ZOOMING": "screen-zooming"
    },

    "GEO":  {
        "OPTIONS" : {
            "LATITUDE" : "geo-latitude",
            "LONGITUDE" : "geo-longitude",
            "ALTITUDE" : "geo-altitude",
            "CELL_ID" : "geo-cellid",
            "ACCURACY" : "geo-accuracy",
            "ALTITUDE_ACCURACY" : "geo-altitudeaccuracy",
            "HEADING" : "geo-heading",
            "SPEED" : "geo-speed",
            "TIME_STAMP" : "geo-timestamp",
            "DELAY" : "geo-delay",
            "DELAY_LABEL" : "geo-delay-label",
            "HEADING_LABEL" : "geo-heading-label",
            "HEADING_MAP_LABEL" : "geo-map-direction-label",
            "IMAGE" : "geo-map-img",
            "MAP_CONTAINER" : "geo-map-container",
            "TIMEOUT" : "geo-timeout",
            "GPXFILE": "geo-gpxfile",
            "GPXGO": "geo-gpx-go",
            "GPXMULTIPLIER": "geo-gpxmultiplier-select",
            "GPXREPLAYSTATUS": "geo-gpxreplaystatus"
        },
        "MAP_ZOOM_MAX": 18,
        "MAP_ZOOM_MIN": 0,
        "MAP_ZOOM_LEVEL_CONTAINER": "geo-map-zoomlevel-value",
        "MAP_ZOOM_KEY": "geo-map-zoom-key",
        "GPXGO_LABELS": {

            "GO": "Go",
            "STOP": "Stop"
        }
    },

    "PUSH": {
        "OPTIONS" : {
            "PAYLOAD" : "push-text"
        }
    },

    "TELEPHONY": {
        "CALL_LIST_KEY": "telephony-call-list-key"
    },

    "PIM": {
        "ADDRESS_LIST_KEY": "pim-address-list-key",
        "CALENDAR_LIST_KEY": "pim-calendar-list-key"
    },

    "CAMERA": {
        "WINDOW_ANIMATION": "images/tizen-wave.gif",
        "WARNING_TEXT": "The runtime simulated saving the camera file to {file}. If you need to access this file in your application, please copy a file to the saved location"
    },

    "AUDIOPLAYER" : {
        "WARNING_TEXT": "The runtime simulated saving the audio file to {file}. If you need to access this file in your application, please copy a file to the saved location"
    },

    "API_APPLICATION": {
        "NO_APPLICATIONS_MESSAGE": "No applications available for your platform"
    },

    "NOTIFICATIONS":  {
        "MESSAGE_CONTAINER_CLASS": "notification-message-div",
        "MAIN_CONTAINER_CLASS": "panel-notification",
        "CLOSE_BUTTON_CLASS": "panel-notification-closebtn",
        "MESSAGE_TEXT_CONTAINER_CLASS": "panel-notification-text",
        "CSS_PREFIX": "panel-notification-",
        "STATE_TYPES": {
            "OPEN": 1,
            "CLOSE": 2
        }
    },

    "CSS_PREFIX":  {
        "IRRELEVANT" : "irrelevant"
    },

    "STORAGE":  {
        "PAIR_DELIMETER" : ",",
        "KEY_VALUE_DELIMETER" : "|"
    },

    "REGEX":  {
        "GEO" : /^geo-/,
        "URL": /^((https?|ftp|gopher|telnet|file|notes|ms-help):((\/\/)|(\\\\))+[\w\d:#@%\/;$()~_?\+-=\\\.&]*)$/,
        //"Email": /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/
        "EMAIL": /^([^@\s]+)@((?:[\-a-z0-9]+\.)+[a-z]{2,})$/,
        "WC3_DTF": /^((\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)|(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)|(\d{4})-(\d\d)-(\d\d)|(\d{4})-(\d\d)|(\d\d\d\d))$/,
        "LOCAL_URI": /^https?:\/\/(127\.0\.0\.1|localhost)|^file:\/\//,
        "EXTERNAL_URI": /(?:(?:[a-zA-Z0-9\/;\?&=:\-_\$\+!\*'\(\|\\~\[\]#%\.](?!www))+(?:\.[Cc]om|\.[Ee]du|\.[gG]ov|\.[Ii]nt|\.[Mm]il|\.[Nn]et|\.[Oo]rg|\.[Bb]iz|\.[Ii]nfo|\.[Nn]ame|\.[Pp]ro|\.[Aa]ero|\.[cC]oop|\.[mM]useum|\.[Cc]at|\.[Jj]obs|\.[Tt]ravel|\.[Aa]rpa|\.[Mm]obi|\.[Aa]c|\.[Aa]d|\.[aA]e|\.[aA]f|\.[aA]g|\.[aA]i|\.[aA]l|\.[aA]m|\.[aA]n|\.[aA]o|\.[aA]q|\.[aA]r|\.[aA]s|\.[aA]t|\.[aA]u|\.[aA]w|\.[aA]z|\.[aA]x|\.[bB]a|\.[bB]b|\.[bB]d|\.[bB]e|\.[bB]f|\.[bB]g|\.[bB]h|\.[bB]i|\.[bB]j|\.[bB]m|\.[bB]n|\.[bB]o|\.[bB]r|\.[bB]s|\.[bB]t|\.[bB]v|\.[bB]w|\.[bB]y|\.[bB]z|\.[cC]a|\.[cC]c|\.[cC]d|\.[cC]f|\.[cC]g|\.[cC]h|\.[cC]i|\.[cC]k|\.[cC]l|\.[cC]m|\.[cC]n|\.[cC]o|\.[cC]r|\.[cC]s|\.[cC]u|\.[cC]v|\.[cC]x|\.[cC]y|\.[cC]z|\.[dD]e|\.[dD]j|\.[dD]k|\.[dD]m|\.[dD]o|\.[dD]z|\.[eE]c|\.[eE]e|\.[eE]g|\.[eE]h|\.[eE]r|\.[eE]s|\.[eE]t|\.[eE]u|\.[fF]i|\.[fF]j|\.[fF]k|\.[fF]m|\.[fF]o|\.[fF]r|\.[gG]a|\.[gG]b|\.[gG]d|\.[gG]e|\.[gG]f|\.[gG]g|\.[gG]h|\.[gG]i|\.[gG]l|\.[gG]m|\.[gG]n|\.[gG]p|\.[gG]q|\.[gG]r|\.[gG]s|\.[gG]t|\.[gG]u|\.[gG]w|\.[gG]y|\.[hH]k|\.[hH]m|\.[hH]n|\.[hH]r|\.[hH]t^[ml]?|\.[hH]u|\.[iI]d|\.[iI]e|\.[iI]l|\.[iI]m|\.[iI]n|\.[iI]o|\.[iI]q|\.[iI]r|\.[iI]s|\.[iI]t|\.[jJ]e|\.[jJ]m|\.[jJ]o|\.[jJ]p|\.[kK]e|\.[kK]g|\.[kK]h|\.[kK]i|\.[kK]m|\.[kK]n|\.[kK]p|\.[kK]r|\.[kK]w|\.[kK]y|\.[kK]z|\.[lL]a|\.[lL]b|\.[lL]c|\.[lL]i|\.[lL]k|\.[lL]r|\.[lL]s|\.[lL]t|\.[lL]u|\.[lL]v|\.[lL]y|\.[mM]a|\.[mM]c|\.[mM]d|\.[mM]g|\.[mM]h|\.[mM]k|\.[mM]l|\.[mM]m|\.[mM]n|\.[mM]o|\.[mM]p|\.[mM]q|\.[mM]r|\.[mM]s|\.[mM]t|\.[mM]u|\.[mM]v|\.[mM]w|\.[mM]x|\.[mM]y|\.[mM]z|\.[nN]a|\.[nN]c|\.[nN]e|\.[nN]f|\.[nN]g|\.[nN]i|\.[nN]l|\.[nN]o|\.[nN]p|\.[nN]r|\.[nN]u|\.[nN]z|\.[oO]m|\.[pP]a|\.[pP]e|\.[pP]f|\.[pP]g|\.[pP]h|\.[pP]k|\.[pP]l|\.[pP]m|\.[pP]n|\.[pP]r|\.[pP]s|\.[pP]t|\.[pP]w|\.[pP]y|\.[qP]a|\.[rR]e|\.[rR]o|\.[rR]u|\.[rR]w|\.[sS]a|\.[sS]b|\.[sS]c|\.[sS]d|\.[sS]e|\.[sS]g|\.[sS]h|\.[Ss]i|\.[sS]j|\.[sS]k|\.[sS]l|\.[sS]m|\.[sS]n|\.[sS]o|\.[sS]r|\.[sS]t|\.[sS]v[^c]|\.[sS]y|\.[sS]z|\.[tT]c|\.[tT]d|\.[tT]f|\.[tT]g|\.[tT]h|\.[tT]j|\.[tT]k|\.[tT]l|\.[tT]m|\.[tT]n|\.[tT]o|\.[tT]p|\.[tT]r|\.[tT]t|\.[tT]v|\.[tT]w|\.[tT]z|\.[uU]a|\.[uU]g|\.[uU]k|\.[uU]m|\.[uU]s|\.[uU]y|\.[uU]z|\.[vV]a|\.[vV]c|\.[vV]e|\.[vV]g|\.[vV]i|\.[vV]n|\.[vV]u|\.[wW]f|\.[wW]s|\.[yY]e|\.[yY]t|\.[yY]u|\.[zZ]a|\.[zZ]m|\.[zZ]w))/
    },

    "CONFIG": {
        "SUCCESS_CSS": {
            "true": "ui-text-pass",
            "false": "ui-text-fail",
            "missing": "ui-text-missing"
        }
    },

    "SETTINGS": {
        "TOOLTIPS_TOGGLE_DIV": "#settings-toggletooltips",
        "TOOLTIPS_KEY": "tool-tips-key"
    },

    "PANEL": {
        "PANEL_CONFIG_ENABLE": "panel-config-enable"
    },

    "UI": {
        "JQUERY_UI_BUTTON_CLASSES": "ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only",
        "JQUERY_UI_INPUT_CLASSES": "ui-state-default ui-corner-all",
        "PANEL_TABLE_CLASS": "panel-table",
        "RIGHT_RANGE_LABEL_CLASS": "range-label",
        "LEFT_RANGE_LABEL_CLASS": "range-label-left",
        "TEXT_LABEL_CLASS": "ui-text-label",
        "SCREEN_PPI": 96
    },

    "MULTIMEDIA": {
        "AUDIO_STATES": {
            "OPENED": "opened",
            "STOPPED": "stopped",
            "PAUSED": "paused",
            "PLAYING": "playing",
            "COMPLETED": "completed"
        }
    },

    "LANG": {
        "ISO6392_LIST": ["abk", "ace", "ach", "ada", "ady", "aar", "afh", "afr", "afa", "ain", "aka", "akk", "alb/sqi", "gsw", "ale", "alg", "tut", "amh", "anp", "apa", "ara", "arg", "arp", "arw", "arm/hye", "rup", "art", "asm", "ast", "ath", "aus", "map", "ava", "ave", "awa", "aym", "aze", "ban", "bat", "bal", "bam", "bai", "bad", "bnt", "bas", "bak", "baq/eus", "btk", "bej", "bel", "bem", "ben", "ber", "bho", "bih", "bik", "byn", "bin", "bis", "zbl", "nob", "bos", "bra", "bre", "bug", "bul", "bua", "bur/mya", "cad", "spa", "cat", "cau", "ceb", "cel", "cai", "khm", "chg", "cmc", "cha", "che", "chr", "nya", "chy", "chb", "chi/zho", "chn", "chp", "cho", "zha", "chu", "chk", "chv", "nwc", "syc", "rar", "cop", "cor", "cos", "cre", "mus", "crp", "cpe", "cpf", "cpp", "crh", "hrv", "cus", "cze/ces", "dak", "dan", "dar", "del", "div", "zza", "din", "doi", "dgr", "dra", "dua", "dut/nld", "dum", "dyu", "dzo", "frs", "efi", "egy", "eka", "elx", "eng", "enm", "ang", "myv", "epo", "est", "ewe", "ewo", "fan", "fat", "fao", "fij", "fil", "fin", "fiu", "fon", "fre/fra", "frm", "fro", "fur", "ful", "gaa", "gla", "car", "glg", "lug", "gay", "gba", "gez", "geo/kat", "ger/deu", "nds", "gmh", "goh", "gem", "kik", "gil", "gon", "gor", "got", "grb", "grc", "gre/ell", "kal", "grn", "guj", "gwi", "hai", "hat", "hau", "haw", "heb", "her", "hil", "him", "hin", "hmo", "hit", "hmn", "hun", "hup", "iba", "ice/isl", "ido", "ibo", "ijo", "ilo", "arc", "smn", "inc", "ine", "ind", "inh", "ina", "ile", "iku", "ipk", "ira", "gle", "mga", "sga", "iro", "ita", "jpn", "jav", "kac", "jrb", "jpr", "kbd", "kab", "xal", "kam", "kan", "kau", "pam", "kaa", "krc", "krl", "kar", "kas", "csb", "kaw", "kaz", "kha", "khi", "kho", "kmb", "kin", "kir", "tlh", "kom", "kon", "kok", "kor", "kos", "kpe", "kro", "kua", "kum", "kur", "kru", "kut", "lad", "lah", "lam", "day", "lao", "lat", "lav", "ltz", "lez", "lim", "lin", "lit", "jbo", "dsb", "loz", "lub", "lua", "lui", "smj", "lun", "luo", "lus", "mac/mkd", "mad", "mag", "mai", "mak", "mlg", "may/msa", "mal", "mlt", "mnc", "mdr", "man", "mni", "mno", "glv", "mao/mri", "arn", "mar", "chm", "mah", "mwr", "mas", "myn", "men", "mic", "min", "mwl", "moh", "mdf", "rum/ron", "mkh", "lol", "mon", "mos", "mul", "mun", "nqo", "nah", "nau", "nav", "nde", "nbl", "ndo", "nap", "new", "nep", "nia", "nic", "ssa", "niu", "zxx", "nog", "non", "nai", "frr", "sme", "nso", "nor", "nno", "nub", "iii", "nym", "nyn", "nyo", "nzi", "oci", "pro", "oji", "ori", "orm", "osa", "oss", "oto", "pal", "pau", "pli", "pag", "pan", "pap", "paa", "pus", "per/fas", "peo", "phi", "phn", "pon", "pol", "por", "pra", "que", "raj", "rap", "qaa-qtz", "roa", "roh", "rom", "run", "rus", "sal", "sam", "smi", "smo", "sad", "sag", "san", "sat", "srd", "sas", "sco", "sel", "sem", "srp", "srr", "shn", "sna", "scn", "sid", "sgn", "bla", "snd", "sin", "sit", "sio", "sms", "den", "sla", "slo/slk", "slv", "sog", "som", "son", "snk", "wen", "sot", "sai", "alt", "sma", "srn", "suk", "sux", "sun", "sus", "swa", "ssw", "swe", "syr", "tgl", "tah", "tai", "tgk", "tmh", "tam", "tat", "tel", "ter", "tet", "tha", "tib/bod", "tig", "tir", "tem", "tiv", "tli", "tpi", "tkl", "tog", "ton", "tsi", "tso", "tsn", "tum", "tup", "tur", "ota", "tuk", "tvl", "tyv", "twi", "udm", "uga", "uig", "ukr", "umb", "mis", "und", "hsb", "urd", "uzb", "vai", "ven", "vie", "vol", "vot", "wak", "wln", "war", "was", "wel/cym", "fry", "wal", "wol", "xho", "sah", "yao", "yap", "yid", "yor", "ypk", "znd", "zap", "zen", "zul", "zun"]
    },

    "XHR": {
        "PROXY_DISABLED_BUTTON": "settings-xhrproxy-disabled"
    },

    "PLATFORMS": {
        "WAC": {
            "APPLICATIONS": [
                "ALARM",
                "BROWSER",
                "CALCULATOR",
                "CALENDAR",
                "CAMERA",
                "CONTACTS",
                "FILES",
                "GAMES",
                "MAIL",
                "MEDIAPLAYER",
                "MESSAGING",
                "PHONECALL",
                "PICTURES",
                "PROG_MANAGER",
                "SETTINGS",
                "TASKS",
                "WIDGET_MANAGER"
            ],
            "DEVICE": {
                "WIDGET_ENGINE_NAME": "Generic",
                "WIDGET_ENGINE_PROVIDER": "tinyHippos",
                "WIDGET_ENGINE_VERSION": "x.x"
            }
        }
    },

    "POWER_RESOURCE": {
        "CPU": {
            "NAME": "CPU",
            "STATE": {
                "LOW": {
                    "NAME": "LOW",
                    "MIN": 0,
                    "MAX": 0.5,
                    "VALUE": 0.3
                },
                "HIGH": {
                    "NAME": "HIGH",
                    "MIN": 0.5,
                    "MAX": 1,
                    "VALUE": 0.7
                }
            }
            
        },
        "DISPLAY": {
            "NAME": "DISPLAY",
            "STATE": {
                "OFF": {
                    "NAME": "OFF",
                    "MIN": 0,
                    "MAX": 0,
                    "VALUE": 0
                },
                "DIM": {
                    "NAME": "DIM",
                    "MIN": 0,
                    "MAX": 0.5,
                    "VALUE": 0.3
                },
                "NORMAL": {
                    "NAME": "NORMAL",
                    "MIN": 0.5,
                    "MAX": 0.7,
                    "VALUE": 0.6
                },
                "BRIGHT": {
                    "NAME": "BRIGHT",
                    "MIN": 0.7,
                    "MAX": 1,
                    "VALUE": 0.9
                }
            }
            
        }
    },
    
    "POWER_RULES": {
        "LOW": true,
        "HIGH": true,
        "OFF": true,
        "DIM": true,
        "NORMAL": true,
        "BRIGHT": true
    }
};

});
define('ripple/deviceMotionEmulator', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    platform = require('ripple/platform'),
    INTERVAL = 60000,
    _self;

function _bind(name, win) {
    var callback = null;

    win.__defineGetter__(name, function () {
        return callback;
    });

    win.__defineSetter__(name, function (cb) {
        callback = cb;
    });

    return {
        get: function () {
            return callback;
        },
        set: function (value) {
            callback = value;
        },
        exec: function (arg) {
            return callback && callback(arg);
        },
        unbind: function (cb) {
            callback = cb === callback ? null : callback;
        }
    };
}

_self = {
    init: function (win, doc) {
        var widgetWindow = win,
            _motion,
            _orientation,
            _calibration,
            add = widgetWindow.addEventListener,
            remove = widgetWindow.removeEventListener;

        //Hang events off window (these are used to check for API existence by developer)
        widgetWindow.DeviceMotionEvent = function DeviceMotionEvent() {};
        widgetWindow.DeviceOrientationEvent = function DeviceOrientationEvent() {};

        _motion = _bind("ondevicemotion", widgetWindow);
        _orientation = _bind("ondeviceorientation", widgetWindow);
        _calibration = _bind("oncompassneedscalibration", widgetWindow);

        widgetWindow.addEventListener = function (event, callback, useCapture) {
            switch (event) {
            case "deviceorientation":
                _orientation.set(callback);
                break;

            case "devicemotion":
                _motion.set(callback);
                break;

            case "compassneedscalibration":
                _calibration.set(callback);
                break;

            default:
                add.apply(widgetWindow, arguments);
                break;
            }
        };

        widgetWindow.removeEventListener = function (event, callback) {
            _motion.unbind(callback);
            _orientation.unbind(callback);
            _calibration.unbind(callback);
            remove.apply(widgetWindow, arguments);
        };

        event.on("DeviceMotionEvent", function (motion) {
            var _motionEvent, DeviceMotionEvent;

            if (platform.current().DeviceMotionEvent) {
                DeviceMotionEvent = platform.current().DeviceMotionEvent;
                if (typeof DeviceMotionEvent !== "function")
                    return;

                _motionEvent = new DeviceMotionEvent();
                _motionEvent.initAccelerometerEvent("devicemotion", true, false, motion.acceleration, motion.accelerationIncludingGravity, 
                                                    motion.rotationRate, INTERVAL);    
            }
            else {
                _motionEvent = {
                    acceleration: motion.acceleration,
                    accelerationIncludingGravity: motion.accelerationIncludingGravity,
                    rotationRate: motion.rotationRate
                };
            }

            _motion.exec(_motionEvent);
        });

        event.on("DeviceOrientationEvent", function (motion) {
            var _orientationEvent, DeviceOrientationEvent;

            if (platform.current().DeviceOrientationEvent) {
                DeviceOrientationEvent = platform.current().DeviceOrientationEvent;
                if (typeof DeviceOrientationEvent !== "function")
                    return;

                _orientationEvent = new DeviceOrientationEvent();        
                _orientationEvent.initDeviceOrientationEvent("deviceorientation", true, false, motion.orientation.alpha, 
                                                              motion.orientation.beta, motion.orientation.gamma, true);
            }
            else {
                _orientationEvent = motion.orientation;
            }

            _orientation.exec(_orientationEvent);
        });
    }
};

module.exports = _self;

});
define('ripple/console', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self;

function _log(msg, method) {
    try {
        console[method](_self.prefix ? _self.prefix + " :: " + msg : msg);
    } catch (e) {
        // silent
    }
}

_self = {
    log: function (msg) {
        _log(msg, "log");
    },

    warn: function (msg) {
        _log(msg, "warn");
    },

    error: function (msg) {
        _log(msg, "error");
    }
};

module.exports = _self;

});
define('ripple/geo', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    exception = require('ripple/exception'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    _positionInfo = {
        "latitude": 39.968362,
        "longitude": 116.410186,
        "altitude": 50,
        "accuracy": 150,
        "altitudeAccuracy": 80,
        "heading": 0,
        "speed": 0,
        "cellID": 1130433
    },
    self;

function _serialize(settings) {
    var tempSettings = utils.copy(settings);
    tempSettings.position.timeStamp = "new Date(" + tempSettings.position.timeStamp.getTime() + ")";
    return tempSettings;
}

function _validatePositionInfo(pInfo) {
    return (pInfo &&
        !(isNaN(pInfo.latitude) ||
        isNaN(pInfo.longitude) ||
        isNaN(pInfo.altitude) ||
        isNaN(pInfo.accuracy) ||
        isNaN(pInfo.altitudeAccuracy) ||
        isNaN(pInfo.heading) ||
        isNaN(pInfo.speed) ||
        isNaN(pInfo.cellID))) ? true : false;
}

self = module.exports = {
    initialize: function () {
        var settings = db.retrieveObject("geosettings");
        if (settings) {
            utils.forEach(_positionInfo, function (value, key) {
                _positionInfo[key] = parseFloat(settings.position[key] || value);
            });

            self.timeout = settings.timeout;
            self.delay = settings.delay || 0;

        }
    },

    getPositionInfo: function () {
        var pi = utils.copy(_positionInfo);
        pi.timeStamp = new Date();

        return pi;
    },

    updatePositionInfo: function (newPositionInfo, delay, timeout) {
        if (!_validatePositionInfo(newPositionInfo)) {
            exception.raise(exception.types.Geo, "invalid positionInfo object");
        }

        _positionInfo = utils.copy(newPositionInfo);
        _positionInfo.timeStamp = new Date();

        self.delay = delay || 0;
        self.timeout = timeout;

        db.saveObject("geosettings", _serialize({
            position: _positionInfo,
            delay: self.delay,
            timeout: self.timeout
        }));

        event.trigger("PositionInfoUpdatedEvent", [_positionInfo]);
    },

    timeout: false,
    delay: 0,
    map: {}
};

});
define('ripple/ui', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _self,
    db = require('ripple/db'),
    platform = require('ripple/platform'),
    constants = require('ripple/constants'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    event = require('ripple/event'),
    themes = require('ripple/ui/themes'),
    _applicationStateId,
    _applicationState,
    _availablePanels,
    _applicationStateTmp,
    _systemPlugins = [
        "options",
        "about-dialog",
        "settings-dialog",
        "exec-dialog",
        "firstRunCheck",
        "eulaCheck",
        "devices",
        "goodVibrations",
        "panelCollapse",
        "platform",
        "information",
        "layout",
        "notifications",
        "themeSwitcher",
        "settings-menu",
        "configWindow"
        //"launchingHistory"
    ],
    _overlay = {
        getOrCreate: function (id) {
            var _container = document.getElementById(constants.COMMON.HTML_CONTAINER),
                _overlays = document.getElementById("overlay-views"),
                _overlay = _overlays.children[id],
                _hide = function (node) {
                    node.setAttribute("style", "display: none");
                },
                _show = function (node) {
                    node.setAttribute("style", "display: block");
                },
                _trigger = function (callback) {
                    if (callback) {
                        callback.apply(null, [_overlay]);
                    }
                };


            if (!_overlay) {
                _overlay = utils.createElement("section", {id: id, "class": "overlay"});
                _overlays.appendChild(_overlay);
            }

            return {
                hide: function (callback) {
                    _hide(_overlay);
                    _show(_container);
                    _trigger(callback);
                },
                show: function (callback, showContainer) {
                    _show(_overlay);
                    if (!showContainer) {
                        _hide(_container);
                    }
                    _trigger(callback);
                }
            };
        }
    };

function _addUIPaneItemsToApplicationState(arrayObj, pane) {
    utils.forEach(arrayObj, function (domId) {
        var collapsed = jQuery("#" + domId + " .info")[0];
        collapsed = (collapsed.style && collapsed.style.display === "none") ? true : false;
        utils.forEach(_applicationStateTmp, function (obj) {
            if (obj.domId === domId) {
                _applicationState.push({
                    "domId": domId,
                    "collapsed": collapsed,
                    "pane": pane,
                    "titleName" : obj.titleName,
                    "display" : obj.display
                });
                _applicationStateTmp.splice(_applicationStateTmp.indexOf(obj), 1);
                return;
            }
        }, this);
    }, this);

    utils.forEach(_applicationStateTmp, function (obj) {
        _applicationState.push({
            "domId": obj.domId,
            "collapsed": obj.collapsed,
            "pane": obj.pane,
            "titleName" : obj.titleName,
            "display" : obj.display
        });
    });
}

function _currentlyEnabledTheme() {
    var qsSet = utils.queryString().theme,
        current = db.retrieve("ui-theme") || themes[0];

    function matches(something) {
        return function (item) {
            return something === item;
        };
    }

    if (qsSet && themes.some(matches(qsSet))) {
        current = qsSet;
        db.save("ui-theme", qsSet);
    }

    return current;
}

function _insertStyleSheets() {
    var uiTheme = db.retrieve("ui-theme") || require('ripple/ui/themes')[0],
        extensionURL = jQuery("#extension-url").text(),
        uiThemeURL = extensionURL + "themes/" + uiTheme + "/theme.css",
        head = document.getElementsByTagName('head')[0];

    function stylesheet(src) {
        var scriptElement = document.createElement("link");
        scriptElement.setAttribute("href", src);
        scriptElement.setAttribute("type", "text/css");
        scriptElement.setAttribute("rel", "stylesheet");
        return scriptElement;
    }

    head.appendChild(stylesheet(uiThemeURL));
}

function _collapsePannels(side) {
    var collapseNode = [],
        event = document.createEvent("UIEvent");

    collapseNode = side === "left" ? document.getElementsByClassName("left-panel-collapse") : 
                                     document.getElementsByClassName("right-panel-collapse");
    
    if (collapseNode.length > 0) {
        event.initEvent("click", true, true);
        collapseNode[0].dispatchEvent(event);    
    }
}

function _initializeUI() {
    _applicationStateId = constants.COMMON.APPLICATION_STATE + platform.current().id;
    _applicationState = db.retrieveObject(_applicationStateId) || [];
    _insertStyleSheets();

    var leftPanelSection = jQuery(".left"),
        uiBoxToggleEngaged = false;

    //clean up
    db.remove("ui-application-state");
    utils.forEach(_availablePanels, function (obj) {
        var matchingDomId = function (panel) {
            return panel.domId === obj.domId;
        };
        if (!utils.some(_applicationState, matchingDomId)) {
            _applicationState.push({
                "domId": obj.domId,
                "collapsed": obj.collapsed,
                "pane": obj.pane,
                "titleName" : obj.titleName,
                "display" : obj.display
            });
        }
    });

    utils.forEach(_applicationState, function (obj) {
        var node = jQuery("#" + obj.domId),
            imgNode = node.find(".ui-box-TitleImage");
            matchingDomId = function (panel) {
                return panel.domId === obj.domId;
            };

        if (node.length > 0) {
            if (!utils.some(_availablePanels, matchingDomId)) {
                node.parent()[0].removeChild(node[0]);
            }
            else {
                if (obj.display !== false) {
                    leftPanelSection.append(node.parent()[0].removeChild(node[0]));
                    if (!obj.collapsed) {
                        node.find(".info")
                            .css({
                            "display": "block"
                        })
                        .end()
                        .addClass("ui-box-open");
                        imgNode.addClass("ui-box-TitleImageOpen");
                    }
                }
            }
        }
    });

    db.saveObject(_applicationStateId, _applicationState);

    event.on("ApplicationState", function () {
        try {
            var leftArray = jQuery(".left").sortable('toArray');
            _applicationStateTmp = [];
            _applicationStateTmp = utils.copy(_applicationState);
            _applicationState = [];
            _addUIPaneItemsToApplicationState(leftArray, "left");

            if (leftArray.length === 0) {
                _collapsePannels("left");
            }

            db.saveObject(_applicationStateId, _applicationState);
        }
        catch (e) {
            exception.handle(e);
        }
    });

    jQuery(".left").sortable({
        handle: ".drag-handle",
        revert: true,
        placeholder: 'ui-sortable-highlight ui-corner-all',
        connectWith: [".left"],
        scroll: true,
        update: function (uiEvent, ui) {
            event.trigger("ApplicationState");
        }
    });

    jQuery(".left").sortable({ axis: 'y' });

    jQuery(".collapse-handle").bind("click", function () {
        if (!uiBoxToggleEngaged) {

            uiBoxToggleEngaged = true;

            var jNode = jQuery(this).parentsUntil(".ui-box"),
                    pNode = jNode.parent(),
                    isOpen = pNode.hasClass("ui-box-open"),
                    imgNode = jQuery(this).find(".ui-box-TitleImage");

            if (!isOpen) {
                pNode.addClass("ui-box-open");
                imgNode.removeClass("ui-box-TitleImageClosed");
                imgNode.addClass("ui-box-TitleImageOpen");
            }

            jQuery(this).parent().next().toggle("blind", {}, 300, function () {
                if (isOpen) {
                    pNode.removeClass("ui-box-open");
                    imgNode.removeClass("ui-box-TitleImageOpen");
                    imgNode.addClass("ui-box-TitleImageClosed");
                }
                event.trigger("ApplicationState", [pNode]);
                uiBoxToggleEngaged = false;
            });
        }
    });
}

function _db_upgrade_for_release() {
    var version = db.retrieve(constants.RELEASE_VERSION);

    // version: 20121115 is the first release version
    if (version === null || version === undefined || Number(version) < 20121115) {
        db.remove(constants.COMMON.APPLICATION_STATE + "tizen");
        db.remove(constants.COMMON.APPLICATION_STATE + "cordova");
        version = 20121115;
        db.save(constants.RELEASE_VERSION, version);
    }
}

_self = module.exports = {
    initialize: function () {
        var plugins = _systemPlugins.concat(platform.current().ui.plugins || []).map(function (name) {
                return require('ripple/ui/plugins/' + name);
            }),
            boot = jWorkflow.order(_initializeUI);

        _db_upgrade_for_release();
        _availablePanels = [];

        plugins.forEach(function (plugin) {
            if (plugin.initialize) {
                boot.andThen(plugin.initialize);
            }

            if (plugin.panel) {
                _availablePanels.push(plugin.panel);
            }
        });

        boot.start();
    },

    getSystemPlugins: function () {
        return utils.copy(_systemPlugins);
    },

    register: function (plugin) {
        _systemPlugins.push(plugin);
    },

    registered: function (plugin) {
        return _systemPlugins.indexOf(plugin) >= 0;
    },

    getExtensionURL: function () {
        return jQuery("#" + constants.COMMON.EXTENSION_URL_CONTAINER).text();
    },

    showOverlay: function (id, callback, showContainer) {
        _overlay.getOrCreate(id).show(callback, showContainer);
    },

    hideOverlay: function (id, callback) {
        _overlay.getOrCreate(id).hide(callback);
    }
};

});
define('ripple/utils', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var self,
    exception = require('ripple/exception'),
    constants = require('ripple/constants'),
    _HtmlElements = ['header', 'footer', 'section', 'aside', 'nav', 'article'];

self = module.exports = {
    validateNumberOfArguments: function (lowerBound, upperBound, numberOfArguments, customExceptionType, customExceptionMessage, customExceptionObject) {

        customExceptionMessage = customExceptionMessage || "";

        if (arguments.length < 3 || arguments.length > 6) {
            exception.raise(exception.types.Argument, "Wrong number of arguments when calling: validateNumberOfArguments()");
        }

        if (isNaN(lowerBound) && isNaN(upperBound) && isNaN(numberOfArguments)) {
            exception.raise(exception.types.ArgumentType, "(validateNumberOfArguments) Arguments are not numbers");
        }

        lowerBound = parseInt(lowerBound, 10);
        upperBound = parseInt(upperBound, 10);
        numberOfArguments = parseInt(numberOfArguments, 10);

        if (numberOfArguments < lowerBound || numberOfArguments > upperBound) {
            exception.raise((customExceptionType || exception.types.ArgumentLength), (customExceptionMessage + "\n\nWrong number of arguments"), customExceptionObject);
        }

    },

    validateArgumentType: function (arg, argType, customExceptionType, customExceptionMessage, customExceptionObject) {
        var invalidArg = false,
            msg;

        switch (argType) {
        case "array":
            if (!arg instanceof Array) {
                invalidArg = true;
            }
            break;
        case "date":
            if (!arg instanceof Date) {
                invalidArg = true;
            }
            break;
        case "integer":
            if (typeof arg === "number") {
                if (arg !== Math.floor(arg)) {
                    invalidArg = true;
                }
            }
            else {
                invalidArg = true;
            }
            break;
        default:
            if (typeof arg !== argType) {
                invalidArg = true;
            }
            break;
        }

        if (invalidArg) {
            msg = customExceptionMessage +  ("\n\nInvalid Argument type. argument: " + arg + " ==> was expected to be of type: " + argType);
            exception.raise((customExceptionType || exception.types.ArgumentType), msg, customExceptionObject);
        }
    },

    validateMultipleArgumentTypes: function (argArray, argTypeArray, customExceptionType, customExceptionMessage, customExceptionObject) {
        for (var i = 0; i < argArray.length; i++) {
            this.validateArgumentType(argArray[i], argTypeArray[i], customExceptionType, customExceptionMessage, customExceptionObject);
        }
    },

    createElement: function (elementType, attributes) {
        var d = document.createElement(elementType);

        if (attributes) {
            this.forEach(attributes, function (attributeValue, attributeName) {

                switch (attributeName.toLowerCase()) {

                case "innerhtml":
                    d.innerHTML = attributeValue;
                    break;

                case "innertext":
                    d.innerText = attributeValue;
                    break;

                default:
                    d.setAttribute(attributeName, attributeValue);
                }

            });
        }

        return d;
    },


    loadHTMLElements: function () {
        for (var i = 0; i < _HtmlElements.length; i += 1) {
            document.createElement(_HtmlElements[i]);
        }
    },

    getAllStylesheetRules: function getAllStylesheetRules(title) {
        this.validateNumberOfArguments(1, 1, arguments.length);

        var i, x, sheet, rules, styles_array = [];

        // get style sheet according to title
        for (i = 0; i < document.styleSheets.length; i += 1) {

            sheet = document.styleSheets[i];
            rules = sheet.cssRules;

            if (rules) {
                for (x = 0; x < rules.length; x += 1) {
                    if (rules[x].selectorText && rules[x].selectorText === (title.toString())) {
                        styles_array.push(rules[x]);
                    }
                }
            }
        }

        return (styles_array);
    },

    location: function () {
        return window.location;
    },

    queryString: function () {
        // trim the leading ? and split each name=value
        var args = this.location().search.replace(/^\?/, '').split('&');

        return args.reduce(function (obj, value) {
            if (value) {
                value = value.toLowerCase().split("=");
                obj[value[0]] = value[1];
            }
            return obj;
        }, {});
    },

    extensionUrl: function () {
        return document.getElementById("extension-url").innerText;
    },

    appLocation: function () {
        if (require('ripple/ui').registered("omnibar")) {
            /* rootURL can only get url saved from 'FrameHistoryChange' event
               it causes trouble when navigating directory through online 
               version as index.html is automatically loaded.
               Need a way to get more updated URL */

            var path = require('ripple/ui/plugins/omnibar').rootURL(),
                parts;

            if ((parts = path.match(/^((http[s]?|ftp|file):\/\/)(.+\/)?([^\/].+)$/i)) !== null && parts.length === 5) {
                // this is a path already.
                if (path.search(/\/$/, "") !== -1) {
                    return path;
                }
                if (parts[4] === "about:blank") {
                    path = "";
                }
                else if (parts[3]) {
                    path = parts[1] + parts[3];
                    if (parts[4].indexOf(".") === -1) {
                        path += parts[4] + "/";
                    }
                }
                else {
                    path = parts[1] + parts[4] + "/";
                }
            }
            else {
                path = "";
            }
            return path;
        }
        return self.rippleLocation();
    },

    rippleLocation: function () {
        var loc = self.location(),
            parts = loc.pathname.replace(/\/$/, "").split("/"),
            base = "",
            port = loc.port ? ":" + loc.port : "";

        if (parts[parts.length - 1].indexOf(".") !== -1) {
            parts = parts.splice(0, parts.length - 1);
        }
        base = parts.join("/");

        return loc.protocol + "//" + loc.hostname + port + base + "/";
    },

    arrayContains: function (array, obj) {
        var i = array.length;
        while (i--) {
            if (array[i] === obj) {
                return true;
            }
        }
        return false;
    },

    some: function (obj, predicate, scope) {
        if (obj instanceof Array) {
            return obj.some(predicate, scope);
        }
        else {
            var values = self.map(obj, predicate, scope);

            return self.reduce(values, function (some, value) {
                return value ? value : some;
            }, false);
        }
    },

    count: function (obj) {
        return self.sum(obj, function (total) {
            return 1;
        });
    },

    sum: function (obj, selector, scope) {
        var values = self.map(obj, selector, scope);
        return self.reduce(values, function (total, value) {
            return total + value;
        });
    },

    max: function (obj, selector, scope) {
        var values = self.map(obj, selector, scope);
        return self.reduce(values, function (max, value) {
            return max < value ? value : max;
        }, Number.MIN_VALUE);
    },

    min: function (obj, selector, scope) {
        var values = self.map(obj, selector, scope);
        return self.reduce(values, function (min, value) {
            return min > value ? value : min;
        }, Number.MAX_VALUE);
    },

    forEach: function (obj, action, scope) {
        if (obj instanceof Array) {
            return obj.forEach(action, scope);
        }
        else {
            self.map(obj, action, scope);
        }
    },

    filter: function (obj, predicate, scope) {
        if (obj instanceof Array) {
            return obj.filter(predicate, scope);
        }
        else {
            var result = [];
            self.forEach(obj, function (value, index) {
                if (predicate.apply(scope, [value, index])) {
                    result.push(value);
                }

            }, scope);

            return result;
        }
    },

    reduce: function (obj, func, init, scope) {
        var i,
            initial = init === undefined ? 0 : init,
            result = initial;


        if (obj instanceof Array) {
            return obj.reduce(func, initial);
        }
        else if (obj instanceof NamedNodeMap) {
            for (i = 0; i < obj.length; i++) {
                result = func.apply(scope, [result, obj[i], i]);
            }
        }
        else {
            for (i in obj) {
                if (obj.hasOwnProperty(i)) {
                    result = func.apply(scope, [result, obj[i], i]);
                }
            }
        }

        return result;

    },

    map: function (obj, func, scope) {
        var i,
            returnVal = null,
            result = [];

        if (obj instanceof Array) {
            return obj.map(func, scope);
        }
        else if (obj instanceof NamedNodeMap) {
            for (i = 0; i < obj.length; i++) {
                returnVal = func.apply(scope, [obj[i], i]);
                result.push(returnVal);
            }
        }
        else {
            for (i in obj) {
                if (obj.hasOwnProperty(i)) {
                    returnVal = func.apply(scope, [obj[i], i]);
                    result.push(returnVal);
                }
            }
        }

        return result;
    },

    regexSanitize: function (regexString) {
        return regexString.replace("^", "\\^")
                    .replace("$", "\\$")
                    .replace("(", "\\(")
                    .replace(")", "\\)")
                    .replace("<", "\\<")
                    .replace("[", "\\[")
                    .replace("{", "\\{")
                    .replace(/\\/, "\\\\")
                    .replace("|", "\\|")
                    .replace(">", "\\>")
                    .replace(".", "\\.")
                    .replace("*", "\\*")
                    .replace("+", "\\+")
                    .replace("?", "\\?");
    },

    bindAutoSaveEvent: function (node, saveCallback) {
        var oldSetTimeoutId,
            jNode = jQuery(node);

        jNode.bind("keyup", function (event) {
            if (event.keyCode !== 9) {
                clearTimeout(oldSetTimeoutId);
                oldSetTimeoutId = window.setTimeout(function () {
                    saveCallback();
                }, 500);
            }
        });
    },

    find: function (comparison, collection, startInx, endInx, callback) {
        var results = [],
            compare = function (s, pattern) {

                if (typeof(s) !== "string" || pattern === null) {
                    return s === pattern;
                }

                var regex = pattern.replace(/\./g, "\\.")
                                   .replace(/\^/g, "\\^")
                                   .replace(/\*/g, ".*")
                                   .replace(/\\\.\*/g, "\\*");

                regex = "^".concat(regex, "$");

                return !!s.match(new RegExp(regex, "i"));
            };

        self.forEach(collection, function (c) {
            var match,
                fail = false;

            self.forEach(comparison, function (value, key) {
                if (!fail && value !== undefined) {

                    if (compare(c[key], value)) {
                        match = c;
                    }
                    else {
                        fail = true;
                        match = null;
                    }
                }
            });

            if (match) {
                results.push(match);
            }
        });

        if (callback) {
            if (startInx === undefined) {
                startInx = 0;
            }
            if (endInx === undefined) {
                endInx = results.length;
            }
            if (startInx === endInx) {
                endInx = startInx + 1;
            }

            callback.apply(null, [results.slice(startInx, endInx)]);
        }
    },

    mixin: function (mixin, to) {
        for (var prop in mixin) {
            if (Object.hasOwnProperty.call(mixin, prop)) {
                to[prop] = mixin[prop];
            }
        }
        return to;
    },

    copy: function (obj) {
        var i,
            newObj = jQuery.isArray(obj) ? [] : {};

        if (typeof obj === 'number' ||
            typeof obj === 'string' ||
            typeof obj === 'boolean' ||
            obj === null ||
            obj === undefined) {
            return obj;
        }

        if (obj instanceof Date) {
            return new Date(obj);
        }

        if (obj instanceof RegExp) {
            return new RegExp(obj);
        }

        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                if (obj[i] && typeof obj[i] === "object") {
                    if (obj[i] instanceof Date) {
                        newObj[i] = obj[i];
                    }
                    else {
                        newObj[i] = self.copy(obj[i]);
                    }
                }
                else {
                    newObj[i] = obj[i];
                }
            }
        }

        return newObj;
    },

    navHelper: function () {
        return {
            getHeading: function (lat1, lon1, lat2, lon2) {
                var dLon = this.rad(lon2 - lon1),
                    llat1 = this.rad(lat1),
                    llat2 = this.rad(lat2),
                    y = Math.sin(dLon) * Math.cos(llat2),
                    x = Math.cos(llat1) * Math.sin(llat2) - Math.sin(llat1) * Math.cos(llat2) * Math.cos(dLon);
                return (this.deg(Math.atan2(y, x)) + 360) % 360;
            },

            getDistance: function (lat1, lon1, lat2, lon2) {
                var dLat = this.rad(lat2 - lat1),
                    dLon = this.rad(lon2 - lon1),
                    a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this.rad(lat1)) * Math.cos(this.rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2),
                    c = 2 * Math.asin(Math.sqrt(a)),
                    d = 6378100 * c;
                return d;
            },

            simulateTravel: function (lat, lon, hdg, dist) {
                var lat1 = this.rad(lat),
                    lon1 = this.rad(lon),
                    brng = this.rad(hdg),
                    angularDistance = dist / 6378100,
                    lat2 = Math.asin(Math.sin(lat1) * Math.cos(angularDistance) + Math.cos(lat1) * Math.sin(angularDistance) * Math.cos(brng)),
                    lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angularDistance) * Math.cos(lat1), Math.cos(angularDistance) - Math.sin(lat1) * Math.sin(lat2));
                lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // Normalise to -180..+180

                return {
                    latitude: this.deg(lat2),
                    longitude: this.deg(lon2)
                };
            },

            deg: function (num) {
                return num * 180 / Math.PI;
            },

            rad: function (num) {
                return num * Math.PI / 180;
            }
        };
    }
};

});
define('ripple/dbfs', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    _cache = {},
    _self;

function _get(path) {
    return path.replace(/^\//, '').split("/").reduce(function (obj, token) {
        return token === "" ? obj : (obj.children ? obj.children[token] || null : null);
    }, _cache);
}

function _getInfo(path) {
    var parent = ("/" + path.replace(/^\//, '').replace(/\/$/, '')).split("/"),
        name = parent.splice(parent.length - 1, 1).join(""),
        ext = name.split(".");

    return {
        name: name,
        extension: ext.length > 1 ? ext[ext.length - 1] : "",
        hidden: (name.length > 0 && name[0] === ".") || false,
        parent: parent.join("/") || "/"
    };
}

function _set(path, obj) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').replace(/\/$/, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    parent.children = parent.children || {};
    obj.properties = obj.properties || {};
    parent.children[child] = obj;
}

function _delete(path) {
    var parent = _cache,
        tokens = path.replace(/^\//, '').split("/"),
        child = tokens.splice(tokens.length - 1, 1).join("");

    tokens.forEach(function (token) {
        parent = parent.children[token];
    });

    delete parent.children[child];
}

function _save() {
    db.saveObject("db-filesystem", _cache);
}

_self = {

    initialize: function (prev, baton) {
        _cache = db.retrieveObject("db-filesystem") || {};
        event.trigger("FileSystemInitialized", null, true);
    },

    ls: function (path, success, error) {
        try {
            var dir = _get(path),
                items = [];

            if (dir) {
                utils.forEach(dir.children, function (item) {
                    if (!item.isDirectory) {
                        item.file = function (callback) {
                            callback({});
                        };
                    }
                    items.push(item);
                });
            }
            else {
                items = {};
            }

            success(utils.copy(items));
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },

    rm: function (path, success, error, options) {
        _delete(path);
        _save();
        success();
    },

    rmdir: function (path, success, error, options) {
        _delete(path);
        _save();
        success();
    },

    mkdir: function (path, success, error) {
        var entry = _get(path),
            info = _getInfo(path);

        if (!entry) {
            _set(path, {
                name: info.name,
                isDirectory: true,
                fullPath: path
            });
            entry = _get(path);
        }
        
        _save();
        if (entry) {
            success(utils.copy(entry));
        }
        else {
            error({code: 1});
        }
    },

    mv: function (from, to, success, error) {
        try {
            var fromEntry = _get(from),
                toInfo = _getInfo(to);

            fromEntry.fullPath = to;
            fromEntry.name = toInfo.name;

            _set(to, fromEntry);
            _delete(from);
            _save();
            success(utils.copy(_get(to)));
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },

    touch: function (path, success, error) {
        if (!_get(path)) {
            _set(path, {
                fullPath: path
            });
        }
        _save();
        success(utils.copy(_get(path)));
    },

    cp: function (from, to, success, error) {
        try {
            var fromEntry = _get(from);
            fromEntry.fullPath = to;
            _set(to, fromEntry);
            _save();
            success(utils.copy(_get(to)));
        }
        catch (e) {
            e.code = 1;
            error(e);
        }
    },

    stat: function (path, success, error) {
        var entry = _get(path);
        success(utils.copy(entry));
    },

    write: function (path, contents, success, error, options) {
        var info = _getInfo(path);

        _set(path, {
            lastModifiedDate: new Date(),
            name: info.name,
            fullPath: path,
            isDirectory: false,
            properties: {
                type: "",
                size: contents.size
            },
            data: contents,
            file: function (callback) {
                callback({});
            }
        });

        success(utils.copy(_get(path)));
    },

    read: function (path, success, error) {
        var entry = _get(path);

        if (entry) {
            success(utils.copy(entry.data));
        }
        else {
            error({code: 1});
        }
    }
};

module.exports = _self;

});
define('ripple/platform', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _current,
    db = require('ripple/db'),
    utils = require('ripple/utils'),
    _console = require('ripple/console'),
    app = require('ripple/app'),
    event = require('ripple/event'),
    spec = require('ripple/platform/spec'),
    _self;

function _getRequestedPlatform() {
    var requestedPlatform = null,
        enableRippleArg = utils.queryString().enableripple,
        platform;

    if (enableRippleArg) {
        enableRippleArg = enableRippleArg.split('-');
        platform = spec.get(enableRippleArg[0], enableRippleArg[1]);
        if (platform) {
            requestedPlatform = { name: platform.id, version: platform.version };
        }
    }

    return requestedPlatform;
}

function _validatePlatform(platform, defaultPlatform) {
    if (!platform ||
        !spec[platform.name] ||
        !spec[platform.name][platform.version] ||
        (spec[platform.name][platform.version] && !spec[platform.name][platform.version].objects)) {
        return defaultPlatform;
    }
    return platform;
}

function _getPlatform() {
    return require('ripple/platform/' + _current.name + "/" + _current.version + "/spec");
}

_self = {
    initialize: function () {
        var firstAvailablePlatform = utils.map(this.getList(), function (platform) {
            return utils.map(platform, function (details, version) {
                return {name: details.id, version: version};
            })[0];
        })[0];

        _current = _getRequestedPlatform() || db.retrieveObject("api-key") || firstAvailablePlatform;
        _current = _validatePlatform(_current, firstAvailablePlatform);
        db.saveObject("api-key", _current);

        _console.prefix = _current.name;
    },

    getList: function () {
        var platformList = {};

        utils.forEach(spec, function (platform, platformKey) {
            utils.forEach(platform, function (version, versionKey) {
                platformList[platformKey] = platformList[platformKey] || {};
                platformList[platformKey][versionKey] = {
                    "id": version.id,
                    "name": version.name,
                    "type": version.type
                };
            });
        });

        return platformList;
    },

    getPersistencePrefix: function (id) {
        return _getPlatform().persistencePrefix + (id || app.getInfo().id) + "-";
    },

    current: function () {
        return _getPlatform();
    },

    changeEnvironment: function (platform, deviceId, callback) {
        var save = jWorkflow.order(function (prev, baton) {
                baton.take();
                db.saveObject("api-key", platform, null, baton.pass);
            }).andThen(function (prev, baton) {
                baton.take();
                db.save("device-key", deviceId, null, baton.pass);
            }).andThen(function (prev, baton) {
                //remove the persisted value for the layout
                baton.take();
                db.save("layout", null, null, baton.pass);
            }).andThen(function () {
                event.trigger("PlatformChangedEvent", [], true);
                _console.prefix = null;
                _console.log("Emulator :: loading platform " + platform.name);
            });

        save.start(callback);
    }
};

module.exports = _self;

});
define('ripple/resizer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    exception = require('ripple/exception'),
    utils = require('ripple/utils'),
    devices = require('ripple/devices'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    _win, 
    _doc,
    _self;

function _validateLayoutType(layoutType) {
    return (layoutType === "landscape" || layoutType === "portrait");
}

function _getContainers() {
    return {
        device: {
            div: document.getElementById("device-container"),
            containerClass: document.getElementById("device-container").getAttribute("class") || ""
        },
        viewport: {
            div: document.getElementById("viewport-container"),
            containerClass: document.getElementById("viewport-container").getAttribute("class") || ""
        },
        "menu-button": {
            div: document.getElementById(constants.COMMON.MENU_BUTTON),
            containerClass: document.getElementById(constants.COMMON.MENU_BUTTON).getAttribute("class") || ""
        },
        "back-button": {
            div: document.getElementById(constants.COMMON.BACK_BUTTON),
            containerClass: document.getElementById(constants.COMMON.BACK_BUTTON).getAttribute("class") || ""
        }
    };
}

function _setContainers(containers, device, orientation) {
    var suffix = {
            portrait:  "-wrapper" + (device.skin ? "-" + device.skin : ""),
            landscape: "-wrapper-landscape" + (device.skin ? "-" + device.skin : "")
        };

    utils.forEach(containers, function (container, key) {
        container.div.setAttribute("class", container.containerClass.replace(/\s.*$/, "") + " " + key + suffix[orientation]);
    });
}

function _getDimensions(device, orientation) {
    return {
        deviceWidth: orientation === "portrait" ? device.screen.width : device.screen.height,
        deviceHeight: orientation === "portrait" ? device.screen.height : device.screen.width,
        paddingLeft: device.viewPort[orientation].paddingLeft,
        paddingTop: device.viewPort[orientation].paddingTop,
        viewPort: {
            width: device.viewPort[orientation].width,
            height: device.viewPort[orientation].height
        }
    };
}

function _formatSkin(containers, dimensions) {    
    containers.device.div.style.width = (dimensions.deviceWidth + 4) + "px";
    containers.device.div.style.height = (dimensions.deviceHeight + 4) + "px";

    containers.viewport.div.style.width = dimensions.viewPort.width + "px";
    containers.viewport.div.style.height = dimensions.viewPort.height + "px";
    containers.viewport.div.style.padding = dimensions.paddingTop + "px " + (dimensions.deviceWidth - (dimensions.viewPort.width + dimensions.paddingLeft)) + "px " +
        (dimensions.deviceHeight - (dimensions.viewPort.height + dimensions.paddingTop)) + "px " + dimensions.paddingLeft + "px";
}

function _setOrientation(layout) {
    _win.orientation = window.orientation = layout === "portrait" ? 0 : 90;
}

_self = {
    init: function (win, doc) {
        _win = win;
        _doc = doc;

        var layout = db.retrieve("layout") || "portrait";

        _setOrientation(layout);

        _win.onorientationchange = undefined;
    },
    // TODO: redo/refactor this in general, seems bloated, also devices REQUIRE viewport schemas which they shouldnt
    resize: function (device) {
        var layout = db.retrieve("layout"),
            orientation = "portrait",
            containers, dimensions;

        if (layout && layout === "landscape" && device.viewPort.landscape) {
            orientation = "landscape";
        }

        containers = _getContainers();

        _setContainers(containers, device, orientation);

        dimensions = _getDimensions(device, orientation);

        if (!device.skin) {
            _formatSkin(containers, dimensions);
        }

        event.trigger("ScreenChangeDimensions", [dimensions.viewPort.width, dimensions.viewPort.height]);
    },

    changeLayoutType: function (layoutType) {
        if (!_validateLayoutType(layoutType)) {
            exception.raise(exception.types.LayoutType, "unknown layout type requested!");
        }

        db.save("layout", layoutType);
        _self.resize(devices.getCurrentDevice());


        if (!_win) return;

        _setOrientation(layoutType);

        if (_win.onorientationchange) {
            _win.onorientationchange();
        }

        var evt = _doc.createEvent("Event");
        evt.initEvent("orientationchange", true, true);
        _win.dispatchEvent(evt);
    }
};

module.exports = _self;

});
define('ripple/ui/plugins/information', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    devices = require('ripple/devices'),
    event = require('ripple/event'),
    platform = require('ripple/platform'),
    utils = require('ripple/utils'),
    app = require('ripple/app');

function _updateInformationView() {
    var infoPane = document.getElementById(constants.COMMON.INFO_SECTION),
        infoList = [],
        device = devices.getCurrentDevice(),
        tempString = "",
        widgetInfo = app.getInfo();

    //TODO: refactor this stuff to grab info from API, do this in a loop rather then hardcoded. Better DOM injection approach. This is legacy code

    infoList.push('<section id=\"information-banner\" style=\"display:none\"><img id=\"information-banner-icon\" width=\"16px\" height=\"16px\"/> <span id=\"information-banner-count\"></span></section>');

    if (widgetInfo.icon) {
        infoList.push('<section style="position: absolute; left: 260px;"  class="information-widgeticon"><img class="ui-corner-all" width="64" src="' + utils.appLocation() + widgetInfo.icon + '" alt="widget icon"/></section>');
    }
    if (widgetInfo.name) {
        infoList.push('<section class="information-widgetname text-is-selectable">' + widgetInfo.name + '</section>');
        //Update Title
        document.title = "Web Simulator - " + widgetInfo.name;
    }

    infoList.push('<table class="tf_panel-table" style="border-spacing: 0px;">');

    infoList.push("<tr><td><label class=\"ui-text-label\">Platform: </label></td><td>" + platform.current().name + "</td></tr>");
   
    if (widgetInfo.version) {
        infoList.push('<section class="information-widgetversion"><label class=\"ui-text-label\">Version: </label><span class="text-is-selectable">' + widgetInfo.version + '</span></section>');
    }
    infoList.push("<section><label class=\"ui-text-label\">Platform: </label><span class=\"text-is-selectable\">" + platform.current().name + "</span></section>");
    infoList.push("<section><label class=\"ui-text-label\">Device: </label><span class=\"text-is-selectable\">" + device.name + "</span></section>");
    infoList.push("<section><label class=\"ui-text-label\">OS: </label><span class=\"text-is-selectable\">" + device.osName + " " + device.osVersion + "</span></section>");
    infoList.push("<section><label class=\"ui-text-label\">Manufacturer: </label><span class=\"text-is-selectable\">" + device.manufacturer + "</span></section>");
    infoList.push("<section><label class=\"ui-text-label\">Screen: </label><span class=\"text-is-selectable\">" + device.screen.width + "x" + device.screen.height + "</span></section>");

    if (device.screen.height !== device.viewPort.portrait.height) {
        infoList.push("<section><label class=\"ui-text-label\">Viewport: </label><span class=\"text-is-selectable\">" + device.viewPort.portrait.width + "x" + device.viewPort.portrait.height + "</span></section>");
    }

    infoList.push("<section><label class=\"ui-text-label\">Density: </label><span class=\"text-is-selectable\">" + device.ppi + " PPI</span></section>");
    infoList.push("<section><label class=\"ui-text-label\" style=\"float:left; padding-top: 0px; \">User Agent: </label>" +
                    "<div class=\"text-is-selectable\" style=\"padding-left: 80px\">" + device.userAgent + "</div></section>");

    if (device.notes) {
        utils.forEach(device.notes, function (note) {
            tempString += "<li class=\"text-is-selectable\">" + note + "</li>";
        });
        infoList.push("<section><div style=\"clear:both;\"></div><label class=\"ui-text-label\">Notes: </label><ul>" + tempString + "</ul></section>");
    }

    infoPane.innerHTML = infoList.join("");
}

function _updateBanner(icon, count) {
    var bannerSection = document.getElementById("information-banner"),
        iconImg  = document.getElementById("information-banner-icon"),
        countSpan = document.getElementById("information-banner-count");

    if (icon && (count === undefined || count !== 0)) {
        count = count || "";
        jQuery("#" + constants.COMMON.INFO_SECTION).show();
        jQuery(bannerSection).fadeToggle(1000);
        jQuery(bannerSection).fadeIn(1000);
    }
    else {
        jQuery(bannerSection).fadeOut(1000);
    }

    iconImg.src = utils.appLocation() + icon;
    if (icon.indexOf("http") === 0) {
        iconImg.src = icon;
    }

    countSpan.innerHTML = count > 99 ? "99+" : count;
}

module.exports = {
    panel: {
        domId: "information-container",
        collapsed: false,
        pane: "left",
        titleName: "System Summary",
        display: true
    },
    initialize: function () {
        event.on("BannerUpdated", function (icon, count) {
            _updateBanner(icon, count);
        });

        event.on("PlatformChangedEvent", function () {
            _updateInformationView();
        });

        event.on("WidgetInformationUpdated", function () {
            _updateInformationView();
        });

        _updateInformationView();
    }
};

});
define('ripple/ui/plugins/panelCollapse', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// TODO: could use a bit of refactoring sugar
var db = require('ripple/db'),
    constants = require('ripple/constants'),
    _LEFT_PANEL_COLLAPSE = ".left-panel-collapse",
    _RIGHT_PANEL_COLLAPSE = ".right-panel-collapse",
    _LEFT_PANEL = ".left",
    _RIGHT_PANEL = ".right",
    _SAVE_KEY = "panel-collapsed",
    platform = require('ripple/platform'),
    devices = require('ripple/devices'),
    _leftEngaged, _rightEngaged, _store;


$(function () { 
    $(window).resize(function () {
        var windowHeight = $(window).height();
        jQuery(".PanelCollapseBar").css("top", windowHeight - 56);
        jQuery("#left_div").css("height", $(window).height() - 21);
        if (_store["left"] === true) {
            jQuery("#middle_div").css("width", $(window).width());
        } else {
            jQuery("#middle_div").css("width", $(window).width());
        }
    });
});


function _persist() {
    db.saveObject(_SAVE_KEY, _store);
}


function updateZoomingValues(value, origin) {
    var scaleFactor = value / 100, scaleString;
    scaleString = "scale(" + scaleFactor + ")";
    jQuery('#device-layout').css('-webkit-transform', scaleString);
    if (origin === "center") {
        jQuery('#device-layout').css('-webkit-transform-origin', 'center top');
    } else {
        jQuery('#device-layout').css('-webkit-transform-origin', 'left top');
    }
}


function _process(collapseNode, panelNode, side, callback) {
    var jNode = collapseNode.children("span"),
        jPanelNode = jQuery(panelNode),
        properties = {},
        collapseProperties = {},
        options = {
            duration: 600,
            complete: callback
        },
        oldIcon, newIcon,
        zoomingValue =  db.retrieve(constants.ENCAPSULATOR.ZOOMING);

    if (_store[side] === true) {
        _store[side] = false;
        
        if (side === "left") {
            jQuery('#left_div').show("fast");
            collapseNode.removeClass("PanelCollapseBarCollapsed");
            collapseNode.addClass("PanelCollapseBar");
            collapseNode.children().remove();
            collapseNode.append('<img src="images/sideCollapseIconLeftSide.png" style="margin-left:330px; margin-top: 6px;"/>');
            collapseNode.css("top", $(window).height() - 56);
            collapseNode.css("left", 0);
            jQuery("#middle_div").css("width", $(window).width());
            updateZoomingValues(zoomingValue, "left");
        }
        
        oldIcon = (side === "left" ? "ui-icon-arrowthick-1-e" : "ui-icon-arrowthick-1-w");
        newIcon = (side === "left" ? "ui-icon-arrowthick-1-w" : "ui-icon-arrowthick-1-e");

        properties[side] = "0px";
        collapseProperties[side] = "345px";
        properties.opacity = "1";
    } else {
        _store[side] = true;
        
        if (side === "left") {
            collapseNode.removeClass("PanelCollapseBar");
            collapseNode.addClass("PanelCollapseBarCollapsed");
            collapseNode.children().remove();
            collapseNode.append('<img src="images/sideCollapseIconRightSide.png" style="position: absolute; margin-left:5px; margin-top:48%;"/>');
            collapseNode.css("top", 10);
            collapseNode.css("left", 0);
            collapseNode.css("margin-left", 0);
            jQuery('#left_div').hide("slow");
            jQuery("#middle_div").css("width", $(window).width());
            updateZoomingValues(zoomingValue, "left");
        }
        
        oldIcon = (side === "left" ? "ui-icon-arrowthick-1-w" : "ui-icon-arrowthick-1-e");
        newIcon = (side === "left" ? "ui-icon-arrowthick-1-e" : "ui-icon-arrowthick-1-w");

        properties[side] = "-340px";
        collapseProperties[side] = "5px";
        properties.opacity = "0.1";
    }

    jNode.removeClass(oldIcon).addClass(newIcon);

    jPanelNode.animate(properties, options);
    _persist();
}

module.exports = {
    initialize: function () {
        var rightCollapseNode = jQuery(_RIGHT_PANEL_COLLAPSE),
            leftCollapseNode = jQuery(_LEFT_PANEL_COLLAPSE),
            device = devices.getCurrentDevice(),
            zoomingValue =  db.retrieve(constants.ENCAPSULATOR.ZOOMING),
            deviceNode = jQuery("#device-layout");
           
        _store = db.retrieveObject(_SAVE_KEY) || {
            left: false,
            right: false
        };

        jQuery("#left_div").css("height", $(window).height() - 21);
        jQuery("#middle_div").css("width", $(window).width());

        jQuery("#device-container").bind("mousedown", function () {
            jQuery("#device-maskmask").show();
        });

        jQuery("#device-container").bind("mouseup", function () {
            jQuery("#device-maskmask").hide();
        });

        jQuery("#deviceTitleBar").bind("mousedown", function () {
            jQuery("#device-maskmask").show();
        });

        jQuery("#deviceTitleBar").bind("mouseup", function () {
            jQuery("#device-maskmask").hide();
        });

        deviceNode.draggable({ cursor: 'move', handle: "#deviceTitleBar", containment: [0, 52, 1280, 800]});
        jQuery("#deviceTitle").text(platform.current().name + "-v" + platform.current().version + " (" + device.screen.width + "x" + device.screen.height + ")");

        if (_store.left === true) {
            jQuery(_LEFT_PANEL).css({
                left: "-340px",
                opacity: "0.1"
            });

            leftCollapseNode.removeClass("PanelCollapseBar");
            leftCollapseNode.addClass("PanelCollapseBarCollapsed");
            leftCollapseNode.children().remove();
            leftCollapseNode.append('<img src="images/sideCollapseIconRightSide.png" style="position: absolute; margin-left:5px; margin-top:48%;"/>');
            leftCollapseNode.css("top", 10);
            leftCollapseNode.css("left", 0);
            leftCollapseNode.css("margin-left", 0);
            jQuery('#left_div').hide();
            jQuery("#device-layout").css("left", "21px");
            updateZoomingValues(zoomingValue, "left");
        } else {
            jQuery('#left_div').show("fast");
            leftCollapseNode.removeClass("PanelCollapseBarCollapsed");
            leftCollapseNode.addClass("PanelCollapseBar");
            leftCollapseNode.children().remove();
            leftCollapseNode.append('<img src="images/sideCollapseIconLeftSide.png" style="margin-left:330px; margin-top: 6px;"/>');
            leftCollapseNode.css("top", $(window).height() - 56);
            leftCollapseNode.css("left", 0);
            jQuery("#device-layout").css("left", "350px");
            updateZoomingValues(zoomingValue, "left");
        }   

        if (_store.right === true) {
            jQuery(_RIGHT_PANEL).css({
                right: "-340px",
                opacity: "0.1"
            });

            rightCollapseNode.css({
                right: "5px"
            }).children("span").removeClass("ui-icon-arrowthick-1-e").addClass("ui-icon-arrowthick-1-w");
        }

        leftCollapseNode.bind("click", function () {
            if (!_leftEngaged) {
                _leftEngaged = true;
                _process(leftCollapseNode, _LEFT_PANEL, "left", function () {
                    _leftEngaged = false;
                });
            }
        });

        rightCollapseNode.bind("click", function () {
            if (!_rightEngaged) {
                _rightEngaged = true;
                _process(rightCollapseNode, _RIGHT_PANEL, "right", function () {
                    _rightEngaged = false;
                });
            }
        });
    }
};

});
define('ripple/ui/plugins/geoView', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    geo = require('ripple/geo'),
    db = require('ripple/db'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    platform = require('ripple/platform'),
    markers,
    _gpsMapZoomLevel,
    _routePoints = [],
    _routes = [],
    _routeMarkers,
    _lineLayer,
    _drawLineTimeout,
    _playFrequency = 0,
    _playState = {'play': false, 'replay': false};

function _initTimeZone() {
    var allTZ, dbTZ, node = jQuery("#time-locale-select"),
        timezone = require('ripple/platform/tizen/2.0/timezone_info'),
        alarms, time;

    function triggerAlarm() {
        time = new Date();
        alarms = db.retrieveObject("tizen1.0-db-alarms");
        if (alarms !== null) {
            utils.forEach(alarms, function (obj) {
                if (obj.id !== undefined) {
                    event.trigger("CheckAlarm", [obj.id]);
                }
            });
        }
    }
    window.setInterval(triggerAlarm, 1000);

    allTZ = timezone.getAllTimezone();
    utils.forEach(allTZ, function (tz) {
        node.append(utils.createElement("option", {
            "value": tz,
            "innerHTML": tz + " - " + timezone.getTimezoneAbbr(tz) + "(" + timezone.getTimezoneDiff(tz) + ")"
        }));
    });
    dbTZ = db.retrieve("tizen-timezone");
    if (timezone.isValidTimezone(dbTZ)) {
        node.val(dbTZ);
    } else {
        db.save("tizen-timezone", node.val());
    }
    node.bind("change", function () {
        db.save("tizen-timezone", node.val());
    });
}

function _updateGpsMap() {
    var positionInfo = geo.getPositionInfo(),
        mapContainer = document.getElementById(constants.GEO.OPTIONS.MAP_CONTAINER);

    if (mapContainer && jQuery(mapContainer).is(':visible')) {
        geo.map.setCenter(new OpenLayers.LonLat(positionInfo.longitude, positionInfo.latitude).transform(
            new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), _gpsMapZoomLevel, true);
    }

    if (_lineLayer) {
        geo.map.removeLayer(_lineLayer);
        geo.map.addLayer(_lineLayer);
    }
}

function _updateGpsMapZoom(goUp) {
    if (goUp && _gpsMapZoomLevel < constants.GEO.MAP_ZOOM_MAX) {
        _gpsMapZoomLevel++;
    }
    else if (!goUp && _gpsMapZoomLevel > constants.GEO.MAP_ZOOM_MIN) {
        _gpsMapZoomLevel--;
    }

    _updateGpsMap();
    db.save(constants.GEO.MAP_ZOOM_KEY, _gpsMapZoomLevel);
}

function _getTextHeading(heading) {
    if (heading >= 337.5 || (heading >= 0 && heading <= 22.5)) {
        return 'N';
    }

    if (heading >= 22.5 && heading <= 67.5) {
        return 'NE';
    }

    if (heading >= 67.5 && heading <= 112.5) {
        return 'E';
    }
    if (heading >= 112.5 && heading <= 157.5) {
        return 'SE';
    }

    if (heading >= 157.5 && heading <= 202.5) {
        return 'S';
    }

    if (heading >= 202.5 && heading <= 247.5) {
        return 'SW';
    }

    if (heading >= 247.5 && heading <= 292.5) {
        return 'W';
    }

    if (heading >= 292.5 && heading <= 337.5) {
        return 'NW';
    }
}

function _updateRoutes() {
    var i, j, k, lon_step, lat_step;
    _routes = [];

    for (i = 0; i < _routePoints.length - 1; i++) {
        lon_step = (_routePoints[i + 1].lonlat.lon - _routePoints[i].lonlat.lon) / 50;
        lat_step = (_routePoints[i + 1].lonlat.lat - _routePoints[i].lonlat.lat) / 50;

        _routes.push(new OpenLayers.LonLat(_routePoints[i].lonlat.lon, _routePoints[i].lonlat.lat));
        for (j = 1, k = _routes.length; j < 50; j++, k++) {
            _routes.push(new OpenLayers.LonLat(_routes[k - 1].lon + lon_step, _routes[k - 1].lat + lat_step));
        }
    }
    _routes.push(new OpenLayers.LonLat(
        _routePoints[_routePoints.length - 1].lonlat.lon,
        _routePoints[_routePoints.length - 1].lonlat.lat)
    );
}

function _drawLine(array) {
    var GEO_OPTIONS = constants.GEO.OPTIONS,
        latitude = document.getElementById(GEO_OPTIONS.LATITUDE),
        longitude = document.getElementById(GEO_OPTIONS.LONGITUDE),
        lonlat = new OpenLayers.LonLat(array[0].lon, array[0].lat).transform(
            new OpenLayers.Projection("EPSG:900913"),
            new OpenLayers.Projection("EPSG:4326")
        ),
        points = new Array(
            new OpenLayers.Geometry.Point(array[0].lon, array[0].lat),
            new OpenLayers.Geometry.Point(array[1].lon, array[1].lat)
        ),
        line = new OpenLayers.Geometry.LineString(points),
        style = {
            strokeColor: '#0000ff',
            strokeOpacity: 1,
            strokeWidth: 3
        },
        lineFeature = new OpenLayers.Feature.Vector(line, null, style);

    if (!_lineLayer) {
        _lineLayer = new OpenLayers.Layer.Vector("Line Layer");
        geo.map.addLayer(_lineLayer);
    }

    _lineLayer.addFeatures([lineFeature]);
    longitude.value = lonlat.lon;
    latitude.value = lonlat.lat;

    if (_playFrequency % 10 === 0) {
        geo.map.panTo(new OpenLayers.LonLat(array[0].lon, array[0].lat), _gpsMapZoomLevel);
    }
    _playFrequency++;
}

function clearRoute() {
    if (!_playState.play) {
        _routePoints.forEach(function (item) {
            _routeMarkers.removeMarker(item.marker);
        });
        _routePoints = [];
        _routes = [];
        _lineLayer.removeFeatures(_lineLayer.features);
    }
}

function setRoute() {
    var clickHandler = new OpenLayers.Handler.Click(
        this,
        {
            click: function (e) {
                if (geo.map.calculateBounds(null, 1) === null) {
                    geo.map.zoomTo(geo.map.zoom);
                }
                var location = geo.map.getLonLatFromViewPortPx(e.xy),
                    size = new OpenLayers.Size(21, 25),
                    offset = new OpenLayers.Pixel(-(size.w / 2), -size.h),
                    icon = new OpenLayers.Icon('images/map_marker.png', size, offset),
                    marker = new OpenLayers.Marker(new OpenLayers.LonLat(location.lon, location.lat), icon);

                geo.map.addLayer(_routeMarkers);
                _routeMarkers.addMarker(marker);
                _routePoints.push({
                    lonlat : location,
                    marker : marker
                });
            }
        },
        {double: true}
    );
    clickHandler.dblclick = function () {
        _updateRoutes();
        this.deactivate();
    };

    if (!_playState.play) {
        clickHandler.setMap(geo.map);
        clickHandler.activate();
    }
}

function playRoute() {
    var speed = document.getElementById("play-route-speed"),
        getPlaySpeed = function () {
            return 20 / speed.value * 1000 / 50;
        },
        draw = function () {
            if (_routes.length <= 1) {
                window.clearTimeout(_drawLineTimeout);
                geo.map.panTo(new OpenLayers.LonLat(
                    _routePoints[_routePoints.length - 1].lonlat.lon,
                    _routePoints[_routePoints.length - 1].lonlat.lat),
                    _gpsMapZoomLevel);
                _playState.play = false;
                _playState.replay = true;
                document.getElementById('play-btn-icon').src = "images/play.png";
            } else {
                _drawLine(_routes);
                _routes.splice(0, 1);
                _drawLineTimeout = window.setTimeout(draw, getPlaySpeed());
            }
        };

    if (!_playState.play && _routes.length !== 0) {
        if (_lineLayer && _playState.replay) {
            _lineLayer.removeFeatures(_lineLayer.features);
            _updateRoutes();
        }
        draw();
        _playState.play = true;
        document.getElementById('play-btn-icon').src = "images/pause.png";
    } else if (_playState.play) {
        window.clearTimeout(_drawLineTimeout);
        _playState.play = false;
        _playState.replay = false;
        document.getElementById('play-btn-icon').src = "images/play.png";
    }
}

function skipTo(position) {
    if (_routes.length !== 0) {
        var index = (position === 'start' ? 0 : _routePoints.length - 1);
        window.clearTimeout(_drawLineTimeout);
        _lineLayer.removeFeatures(_lineLayer.features);
        geo.map.panTo(new OpenLayers.LonLat(_routePoints[index].lonlat.lon, _routePoints[index].lonlat.lat), _gpsMapZoomLevel);
        _routes = [];
        _updateRoutes();
        _playFrequency = 0;
        _playState.play = false;
        _playState.replay = false;
        document.getElementById('play-btn-icon').src = "images/play.png";
    }
}

module.exports = {
    panel: {
        domId: "gps-container",
        collapsed: true,
        pane: "left",
        titleName: "Geolocation",
        display: true
    },
    initialize: function () {
        var GEO_OPTIONS = constants.GEO.OPTIONS,
            positionInfo = geo.getPositionInfo(),
            positionEvent = "PositionInfoUpdatedEvent",
            latitude = document.getElementById(GEO_OPTIONS.LATITUDE),
            longitude = document.getElementById(GEO_OPTIONS.LONGITUDE),
            altitude = document.getElementById(GEO_OPTIONS.ALTITUDE),
            accuracy = document.getElementById(GEO_OPTIONS.ACCURACY),
            altitudeAccuracy = document.getElementById(GEO_OPTIONS.ALTITUDE_ACCURACY),
            heading = document.getElementById(GEO_OPTIONS.HEADING),
            speed = document.getElementById(GEO_OPTIONS.SPEED),
            cellID = document.getElementById(GEO_OPTIONS.CELL_ID),
            delay = document.getElementById(GEO_OPTIONS.DELAY),
            delayLabel = document.getElementById(GEO_OPTIONS.DELAY_LABEL),
            headingLabel = document.getElementById(GEO_OPTIONS.HEADING_LABEL),
            headingMapLabel = document.getElementById(GEO_OPTIONS.HEADING_MAP_LABEL),
            timeout = document.getElementById(GEO_OPTIONS.TIMEOUT),
            gpxMultiplier = document.getElementById(GEO_OPTIONS.GPXMULTIPLIER),
            gpxReplayStatus = document.getElementById(GEO_OPTIONS.GPXREPLAYSTATUS),
            gpxGo = $(document.getElementById(GEO_OPTIONS.GPXGO)).find("span")[0],
            mapContainer = document.getElementById(GEO_OPTIONS.MAP_CONTAINER),
            map = null,
            track = [],
            _replayingGpxFile = false,
            _haltGpxReplay = false;

        function updateGeo() {
            if (parseFloat(latitude.value) > 90)
                latitude.value = 90;
            else if (parseFloat(latitude.value) < -90)
                latitude.value = -90;

            if (parseFloat(longitude.value) > 180)
                longitude.value = 180;
            else if (parseFloat(longitude.value) < -180)
                longitude.value = -180;

            geo.updatePositionInfo({
                latitude: parseFloat(latitude.value),
                longitude: parseFloat(longitude.value),
                altitude: parseInt(altitude.value, 10),
                accuracy: parseInt(accuracy.value, 10),
                altitudeAccuracy: parseInt(altitudeAccuracy.value, 10),
                heading: heading.value ? parseFloat(heading.value) : 0, // HACK: see techdebt http://www.pivotaltracker.com/story/show/5478847
                speed: speed.value ? parseInt(speed.value, 10) : 0, // HACK: see techdebt http://www.pivotaltracker.com/story/show/5478847
                cellID: cellID.value,
                timeStamp: new Date()
            },
            delay.value,
            timeout.checked);
        }

        function updateHeadingValues() {
            var headingDeg = parseFloat(heading.value),
                headingText = _getTextHeading(parseFloat(heading.value));

            headingLabel.innerText = headingText;
            headingMapLabel.innerHTML = headingText + "</br>" + headingDeg + "&deg;";
        }

        function updateValsFromMap() {
            var center = geo.map.getCenter().transform(
                new OpenLayers.Projection("EPSG:900913"),
                new OpenLayers.Projection("EPSG:4326"));
            longitude.value = center.lon;
            latitude.value = center.lat;
            updateGeo();
        }

        function initializeValues() {
            latitude.value =          positionInfo.latitude;
            longitude.value =         positionInfo.longitude;
            altitude.value =          positionInfo.altitude;
            accuracy.value =          positionInfo.accuracy;
            altitudeAccuracy.value =  positionInfo.altitudeAccuracy;
            cellID.value =            positionInfo.cellID;
            delay.value = document.getElementById(GEO_OPTIONS.DELAY_LABEL).innerText = geo.delay || 0;
            if (geo.timeout) {
                timeout.checked = true;
            }
            updateHeadingValues();
        }

        function initMap() {
            var marker, clickHandler;
            // override image location so we don't have to include image assets
            OpenLayers.ImgPath = 'http://openlayers.org/api/img/';

            // init map
            geo.map = new OpenLayers.Map(mapContainer, { controls: [] });

            // add controls and OSM map layer
            geo.map.addLayer(new OpenLayers.Layer.OSM());
            geo.map.addControl(new OpenLayers.Control.Navigation());

            // override behaviour of click to pan and double click to zoom in
            clickHandler = new OpenLayers.Handler.Click(
                this,
                {
                    click: function (e) {
                        if (geo.map.calculateBounds(null, 1) === null) {
                            geo.map.zoomTo(geo.map.zoom);
                        }
                        var location = geo.map.getLonLatFromViewPortPx(e.xy);
                        geo.map.panTo(new OpenLayers.LonLat(location.lon, location.lat), _gpsMapZoomLevel);
                    },

                    dblclick: function () {
                        _updateGpsMapZoom(true);
                    }
                },
                {double: true}
            );

            // add click handler to map
            clickHandler.setMap(geo.map);
            clickHandler.activate();

            // update long and lat when map is panned
            geo.map.events.register("moveend", map, function () {
                updateValsFromMap();
            });

            markers = new OpenLayers.Layer.Markers("markers");
            _routeMarkers = new OpenLayers.Layer.Markers("markers");
            geo.map.addLayer(markers);

            event.on("ApplicationState", function (obj) {
                if (obj && obj[0].id === 'gps-container' && obj.hasClass('ui-box-open')) {
                    _updateGpsMap();

                    // Simulator is loaded with geo panel folded, now it's the first time it's unfolded
                    if (!marker) {
                        // Only when the geo panel is unfolded, getCenter() will go well
                        marker = new OpenLayers.Marker(geo.map.getCenter(),
                            new OpenLayers.Icon("images/arrow.png", new OpenLayers.Size(22, 30), new OpenLayers.Pixel(-11, -15)));
                        markers.addMarker(marker);

                        navigator.geolocation.getCurrentPosition(function (geoPosition) {
                            geo.map.panTo(new OpenLayers.LonLat(geoPosition.coords.longitude, geoPosition.coords.latitude).transform(
                                new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), _gpsMapZoomLevel);
                        });
                    }
                }
            });
            _updateGpsMap();

            // Simulator is loaded with geo panel unfolded
            if (mapContainer && jQuery(mapContainer).is(':visible')) {
                marker = new OpenLayers.Marker(geo.map.getCenter(),
                    new OpenLayers.Icon("images/arrow.png", new OpenLayers.Size(22, 30), new OpenLayers.Pixel(-11, -15)));
                markers.addMarker(marker);

                navigator.geolocation.getCurrentPosition(function (geoPosition) {
                    geo.map.panTo(new OpenLayers.LonLat(geoPosition.coords.longitude, geoPosition.coords.latitude).transform(
                        new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), _gpsMapZoomLevel);
                });
            }

            geo.map.events.register("move", map, function () {
                markers.clearMarkers();
                marker = new OpenLayers.Marker(geo.map.getCenter(),
                        new OpenLayers.Icon("images/arrow.png", new OpenLayers.Size(22, 30), new OpenLayers.Pixel(-11, -15)));
                markers.addMarker(marker);
            });
        }

        function loadGpxFile(win, fail, args) {
            var reader = new FileReader(),
                file = args[0],
                _xml,
                t,
                att,
                lastAtt,
                _ele,
                _timestamp,
                _lastTimestamp,
                _useTimestamp = new Date().getTime(),
                _tempTimestamp,
                _tempPosition,
                _lastPosition,
                _useLastTimestamp,
                _heading = 0,
                _speed = 0,
                _dist = 0,
                navUtils = new utils.navHelper();

            reader.onload = function (e) {
                _xml = e.target.result;
                t = $(_xml).find('trkpt');

                track = [];

                utils.forEach(t, function (p, i) {
                    if (!isNaN(i)) {
                        att = t[i].attributes;
                        lastAtt = t[i - 1] ? t[i - 1].attributes : {};
                        _ele = $(t[i]).find("ele")[0];
                        _timestamp = $(t[i]).find("time")[0];
                        _lastTimestamp = $(t[i - 1]).find("time")[0];

                        if (_timestamp) {
                            //files recorded with endomondo and others have timestamps, this is not a route plan but a record of a track
                            _useTimestamp = new Date(_timestamp.innerText).getTime();
                        }

                        if (t[i - 1]) {
                            _dist = navUtils.getDistance(att["lat"].value, att["lon"].value, lastAtt["lat"].value, lastAtt["lon"].value);

                            if (_lastTimestamp) {
                                _useLastTimestamp = new Date(_lastTimestamp.innerText).getTime();
                            }
                            else {
                                //routes from YOURS come in as tracks (rather than routes under the GPX schema), but with no timestamps.  This is a route.
                                _useLastTimestamp = _useTimestamp;
                                _useTimestamp += Math.round(_dist / 22.2222 * 1000);  //80km/h in m/s
                            }

                            _heading = navUtils.getHeading(lastAtt["lat"].value, lastAtt["lon"].value, att["lat"].value, att["lon"].value);
                            _speed = (_dist / ((_useTimestamp - _useLastTimestamp) / 1000)).toFixed(2);

                            if (!_lastTimestamp) {
                                //on YOURS routes, make sure we have at least one update a second
                                _tempTimestamp = _useLastTimestamp;

                                while (_useTimestamp - _tempTimestamp > 1000) {
                                    _tempTimestamp += 1000;
                                    _lastPosition = track[track.length - 1].coords;
                                    _tempPosition = navUtils.simulateTravel(_lastPosition.latitude, _lastPosition.longitude, _heading, _speed);
                                    track.push({
                                        coords: {
                                            latitude: _tempPosition.latitude,
                                            longitude: _tempPosition.longitude,
                                            altitude: _ele ? _ele.innerText : 0,
                                            accuracy: 150,
                                            altitudeAccuracy: 80,
                                            heading: _heading,
                                            speed: _speed
                                        },
                                        timestamp: _tempTimestamp
                                    });
                                }
                            }
                        }

                        track.push({
                            coords: {
                                latitude: att["lat"].value,
                                longitude: att["lon"].value,
                                altitude: _ele ? _ele.innerText : 0,
                                accuracy: 150,
                                altitudeAccuracy: 80,
                                heading: _heading,
                                speed: _speed
                            },
                            timestamp: _useTimestamp
                        });
                    }
                });
            };
            reader.onerror = function (e) {
                fail(e);
            };
            reader.readAsText(file.target.files[0], "UTF-8");
        }

        function replayGpxTrack() {
            if (_replayingGpxFile) {
                _haltGpxReplay = true;
                gpxGo.innerText = constants.GEO.GPXGO_LABELS.GO;
            }
            else {
                if (track.length > 0) {
                    _haltGpxReplay = false;
                    gpxGo.innerText = constants.GEO.GPXGO_LABELS.STOP;

                    latitude.value = track[0].coords.latitude;
                    longitude.value = track[0].coords.longitude;
                    altitude.value = track[0].coords.altitude;
                    accuracy.value = track[0].coords.accuracy;
                    altitudeAccuracy.value = track[0].coords.altitudeAccuracy;
                    heading.value = track[0].coords.heading;
                    speed.value = track[0].coords.speed;

                    updateGeo();
                    updateHeadingValues();
                    _triggerEvent();

                    moveNextGpxTrack(1);
                }
            }
        }

        function moveNextGpxTrack(i)
        {
            if (_haltGpxReplay) {
                _replayingGpxFile = false;
                _haltGpxReplay = false;
                console.log("Ripple :: User interrupted replay of GPX file (Aye Captain, answers All Stop.)");
            }
            else {
                _replayingGpxFile = true;
                var _timeMultiplier = !isNaN(gpxMultiplier.value) ? gpxMultiplier.value : 1,
                _step = 0,
                _interval = 0;

                while (_interval < 250) {
                    _step++;
                    if ((i + _step) >= track.length) { break; }
                    _interval = (track[i + _step].timestamp - track[i].timestamp) / _timeMultiplier;
                }

                gpxReplayStatus.textContent = (_interval / 1000).toFixed(2) + "s (" + (_interval / 1000 * _timeMultiplier).toFixed(2) + "s realtime), " + (i + 1) + " of " + track.length + " (stepping " + _step + " at " + _timeMultiplier + "x)";

                setTimeout(function () {
                    latitude.value = track[i].coords.latitude;
                    longitude.value = track[i].coords.longitude;
                    altitude.value = track[i].coords.altitude;
                    accuracy.value = track[i].coords.accuracy;
                    altitudeAccuracy.value = track[i].coords.altitudeAccuracy;
                    heading.value = track[i].coords.heading;
                    speed.value = track[i].coords.speed;

                    updateGeo();
                    updateHeadingValues();
                    _triggerEvent();

                    if (track[i + _step]) {
                        moveNextGpxTrack(i + _step);
                    }
                    else {
                        if (i < track.length - 1) {
                            moveNextGpxTrack(track.length - 1);
                        }
                        else {
                            _replayingGpxFile = false;
                            gpxGo.innerText = constants.GEO.GPXGO_LABELS.GO;
                            console.log("Ripple :: Finished replaying GPX file (Arriving at our destination, assuming standard orbit Captain.)");
                        }
                    }
                }, _interval);
            }
        }

        // HACK: see techdebt http://www.pivotaltracker.com/story/show/5478847 (double HACK!!!)
        if (platform.current().id === 'phonegap' ||
            platform.current().id === 'webworks' ||
            platform.current().id === 'cordova') {
            // make the fields visible
            jQuery("#geo-cellid-container").hide();
            jQuery("#geo-heading-container").show();
            jQuery("#geo-speed-container").show();
        }
        else {
            jQuery("#geo-cellid-container").show();
            jQuery("#geo-heading-container").hide();
            jQuery("#geo-speed-container").hide();
        }

        _gpsMapZoomLevel = db.retrieve(constants.GEO.MAP_ZOOM_KEY) || 14;

        jQuery("#geo-map-zoom-decrease").bind("click", function () {
            _updateGpsMapZoom(false);
        });

        jQuery("#geo-map-zoom-increase").bind("click", function () {
            _updateGpsMapZoom(true);
        });

        utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.LATITUDE), updateGeo);
        utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.LONGITUDE), updateGeo);
        utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.ALTITUDE), updateGeo);
        utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.ACCURACY), updateGeo);
        utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.ALTITUDE_ACCURACY), updateGeo);
        utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.CELL_ID), updateGeo);

        jQuery("#play-route-speed-label").html(jQuery("#play-route-speed").val() + 'x');
        jQuery("#play-route-speed").bind("change", function () {
            jQuery("#play-route-speed-label").html(jQuery("#play-route-speed").val() + 'x');
        });
        jQuery("#clear-route-btn").bind("click", function () {
            clearRoute();
        });
        jQuery("#set-route-btn").bind("click", function () {
            setRoute();
        });
        jQuery("#play-route-btn").bind("click", function () {
            playRoute();
        });
        jQuery("#back-route-btn").bind("click", function () {
            skipTo("start");
        });
        jQuery("#forward-route-btn").bind("click", function () {
            skipTo("end");
        });

        jQuery("#" + GEO_OPTIONS.DELAY).bind("change", function () {
            updateGeo();
            delayLabel.innerText = delay.value;
        });
        jQuery("#" + GEO_OPTIONS.TIMEOUT).bind("click", function () {
            updateGeo();
        });
        jQuery("#" + GEO_OPTIONS.GPXFILE).bind("change", function (a) {
            loadGpxFile(null, null, [a]);
        });
        jQuery("#" + GEO_OPTIONS.GPXGO).bind("click", function () {
            replayGpxTrack();
        });

        // HACK: see techdebt http://www.pivotaltracker.com/story/show/5478847 (double HACK!!!)
        if (platform.current().id === 'phonegap' || platform.current().id === 'webworks' || platform.current().id === 'cordova') {
            jQuery("#" + GEO_OPTIONS.HEADING).bind("change", function () {
                updateGeo();
                updateHeadingValues();
            });

            utils.bindAutoSaveEvent(jQuery("#" + GEO_OPTIONS.SPEED), updateGeo);
            heading.value =       positionInfo.heading;
            speed.value =         positionInfo.speed;
        }

        initMap();
        if (navigator.onLine === false) {
            jQuery("#disable_geo_panel").show();
        }
        jQuery(window).bind("online", function () {
            jQuery("#disable_geo_panel").hide();
            console.log("ONLINE");
        });
        jQuery(window).bind("offline", function () {
            jQuery("#disable_geo_panel").show();
            console.log("OFFLINE");
        });

        initializeValues();
        _initTimeZone();

        event.on(positionEvent, function () {
            _updateGpsMap();
        });

        _triggerEvent();

        function _triggerEvent() {
            event.trigger(positionEvent, [{
                latitude: latitude.value,
                longitude: longitude.value,
                altitude: altitude.value,
                accuracy: accuracy.value,
                altitudeAccuracy: altitudeAccuracy.value,
                heading: heading ? heading.value : 0, // HACK: see techdebt http://www.pivotaltracker.com/story/show/5478847
                speed: speed ? speed.value : 0, // HACK: see techdebt http://www.pivotaltracker.com/story/show/5478847
                cellID: cellID.value,
                timeStamp: new Date()
            }]);
        }
    }
};

});
define('ripple/ui/plugins/fileSystem', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    fileSystem = require('ripple/fileSystem'),
    fileSystemPaths = fileSystem.getFileSystemPaths();

module.exports = {
    panel: {
        domId: "filsystem-container",
        collapsed: true,
        pane: "left"
    },
    initialize: function () {
        var fileSystemPaths = fileSystem.getFileSystemPaths();

        utils.forEach(fileSystemPaths, function (value, key) {
            utils.bindAutoSaveEvent(jQuery(constants.FILESYSTEM.INPUT_PREFIX_ID + key).val(value.uri), function () {
                value.uri = jQuery(constants.FILESYSTEM.INPUT_PREFIX_ID + key).val();
                fileSystem.updateFileSystemPaths(fileSystemPaths);
            });
        });
    }
};

});
define('ripple/ui/plugins/firstRunCheck', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    _platform = require('ripple/platform'),
    db = require('ripple/db');

function _handleFirstRunResponse(platform, version) {
    var device = jQuery("#device-select").val(),
        api = {
            name: platform.id,
            version: version
        };


    _platform.changeEnvironment(api, device, function () {
        window.tinyHipposReload = true;
        location.reload();
    });
}

function _addPlatformButton(platform, version) {
    var section = jQuery(".platform-select-buttons"),
        buttonID = "platform-" + platform.id,
        button = utils.createElement("button", {
            "id": buttonID,
            "class": "ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"
        });

    button.appendChild(utils.createElement("span", {
        "class": "ui-button-text",
        "innertext" : platform.name
    }));

    section.append(button);

    document.getElementById(buttonID).addEventListener("click", function () {
        _handleFirstRunResponse(platform, version);
    });
}

function _initializeFirstRunCheck() {
    var savedPlatform = db.retrieveObject("api-key"),
        firstRunOverlayNode, firstRunOptionsNode,
        width, p;

    if (!savedPlatform) {
        width = jQuery(document).width();
        p = (width / 2) - 277;

        firstRunOverlayNode = jQuery(".first-run-window").css({display: 'block'});
        firstRunOptionsNode = jQuery(".platform-select-dialog").css({display: 'block', left: p + "px"});

        utils.forEach(_platform.getList(), function (platform) {
            utils.forEach(platform, function (details, version) {
                _addPlatformButton(details, version);
            });
        });
    }
}

module.exports = {
    initialize: function () {
        if (utils.map(_platform.getList(), function (platform) {
            return platform;
        }).length > 1) {
            _initializeFirstRunCheck();
        }
    }
};

});
define('ripple/ui/plugins/deviceSettings', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    constants = require('ripple/constants'),
    deviceSettings = require('ripple/deviceSettings'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    platform = require('ripple/platform'),
    _CONST = {
        "CONTENT_CONTAINER_ID": "devicesettings-content-container",
        "UKNOWN_CONTROL_MESSAGE": "Unknown device control type"
    },
    _contentContainer,
    _network_contentContainer,
    _CONTAINER_ID = _CONST.CONTENT_CONTAINER_ID;

function _retrieveDeviceInfo(key) {
    var deviceInfo = require('ripple/devices').getCurrentDevice();

    switch (key) {
    case "Device.model":
        return deviceInfo.model;
    case "Device.version":
        return deviceInfo.firmware;
    case "Device.vendor":
        return deviceInfo.manufacturer;
    case "Display.resolutionHeight":
        return deviceInfo.screen.height;
    case "Display.resolutionWidth":
        return deviceInfo.screen.width;
    case "Display.pixelAspectRatio":
        return (deviceInfo.screen.width / deviceInfo.screen.height).toFixed(2);

    case "Display.physicalWidth":
        return (deviceInfo.screen.width / deviceInfo.ppi).toFixed(2);
    case "Display.physicalHeight":
        return (deviceInfo.screen.height / deviceInfo.ppi).toFixed(2);
    case "Display.dpiY":
    case "Display.dotsPerInchHeight":
        return deviceInfo.ppi;
    case "Display.dpiX":
    case "Display.dotsPerInchWidth":
        return deviceInfo.ppi;
    case "OperatingSystem.version":
        return deviceInfo.osVersion;
    case "OperatingSystem.name":
        return deviceInfo.osName;
    case "OperatingSystem.vendor":
        return deviceInfo.manufacturer;
    default:
        return deviceSettings.retrieve(key);
    }
}

function _retrieveSettingName(type) {
    
    switch (type) {
    case "CellularHardware":
        return "Cellular Hardware";
    case "CellularNetwork":
        return "Cellular Network";
    case "MemoryUnit":
        return "Memory Unit";
    case "OperatingSystem":
        return "Operating System";
    case "WebRuntime":
        return "Web Runtime";
    case "WiFiHardware":
        return "WiFi Hardware";
    case "WiFiNetwork":
        return "WiFi Network";
    default:
        return type;
    }
}

function _appendSettingNode(labelNode, inputNode, label) {
    var frag = document.createDocumentFragment(),
        rowNode = frag.appendChild(utils.createElement("tr")),
        tempTdNode;

    rowNode.appendChild(utils.createElement("td"))
           .appendChild(labelNode);

    tempTdNode = rowNode.appendChild(utils.createElement("td"));

    if (label) {
        tempTdNode.appendChild(label);
    }

    tempTdNode.appendChild(inputNode);

    return frag;
}

function _buildDOMNode(setting, settingType, key) {
    var settingsNode, tagName, jNode,
        fullKey = settingType + "." + key,
        savedSetting = _retrieveDeviceInfo(fullKey),
        // TODO: move this into Utils (isSet method)
        currentSetting = (savedSetting || savedSetting === false || savedSetting === "" || savedSetting === 0) ? savedSetting : setting.control.value,
        domNode,
        domNodeLabel = null;


    switch (setting.control.type) {
    case "text":
    case "number":
    case "range":
    case "checkbox":
        tagName = "input";
        break;
    case "textarea":
        tagName = "textarea";
        break;
    case "select":
        tagName = "select";
        break;
    case "label":
        tagName = "label";
        break;
    default:
        exception.raise(exception.types.Application, _CONST.UKNOWN_CONTROL_MESSAGE);
    }

    settingsNode = utils.createElement(tagName, setting.control.type === "select" ? null : setting.control);
    settingsNode.setAttribute("id", "device-settings-" + settingType + "-" + key);

    // TODO: this should really be part of utils.createControl? add element of type "range" with label?
    if (setting.control.type === "range") {
        domNodeLabel = utils.createElement("label", {
            "class": constants.UI.LEFT_RANGE_LABEL_CLASS
        });
    }

    domNode = _appendSettingNode(utils.createElement("span", {"innerText": setting.name, "class": "configure-window-text-label"}), settingsNode, domNodeLabel);

    jNode = jQuery(settingsNode);
    if (tagName !== "label") {
        jNode.addClass(constants.UI.JQUERY_UI_INPUT_CLASSES);
    }

    switch (setting.control.type) {
    case "checkbox":
        jNode.bind("click", function () {
            var checked = this.checked ? true : false;
            deviceSettings.persist(fullKey, checked);
            if (typeof setting.callback === "function") {
                setting.callback(checked);
            }
        });

        if (currentSetting === true) {
            jNode.attr("checked", "checked");
        }

        break;

    case "text":
    case "textarea":
    case "number":
        jNode.val(currentSetting);
        utils.bindAutoSaveEvent(jNode, function () {
            deviceSettings.persist(fullKey, jNode.val());
            if (typeof setting.callback === "function") {
                setting.callback(jNode.val());
            }
        });
        break;
    
    case "label":
        jNode.text(currentSetting);
        break;

    case "select":
    case "range":
        if (setting.control.type === "select") {
            utils.forEach(setting.options,  function (value, option) {
                jNode.append(utils.createElement("option", {
                    "value": option,
                    "innerText": value
                }));
            });
        }
        else {
            if (domNodeLabel) {
                domNodeLabel.innerText = currentSetting;
            }
        }

        jNode.val(currentSetting)
             .bind("change", function () {
                if (setting.control.type === "range" && domNodeLabel) {
                    domNodeLabel.innerText = jQuery(this).val();
                }
                deviceSettings.persist(fullKey, jQuery(this).val());

                if (typeof setting.callback === "function") {
                    setting.callback(jQuery(this).val(), currentSetting);
                }
            }
        );
    }

    // TODO: Brent, do in DeviceSettings on load instead?
    if (currentSetting !== setting.control.value) {
        deviceSettings.register(fullKey, currentSetting);
    }

    return domNode;
}

// goes through current platforms device settings
// adds nodes to panel and binds respective events
// talks to DeviceSettings for persistence
module.exports = {
    initialize: function () {
        var settings;

        _contentContainer = document.getElementById(_CONTAINER_ID);
        _network_contentContainer = document.getElementById("networksettings-content-container");

        settings = platform.current().device;

        utils.forEach(settings, function (settingSection, settingType) {

            var currentTableNode, currentTableNode2, settingNameNode, settingName = _retrieveSettingName(settingType);

            settingNameNode = utils.createElement("h3", { "innerText": settingName });
            settingNameNode.setAttribute("class", "configure-window-session-title");

            if (settingType === 'Config' || settingType === 'Cpu' || settingType === 'Storage' || settingType === 'Display' || settingType === 'Device') {
                _contentContainer.appendChild(settingNameNode);
            }
            else {
                _network_contentContainer.appendChild(settingNameNode);
            }

            currentTableNode = utils.createElement("table", {
                "class": constants.UI.PANEL_TABLE_CLASS
            });
			currentTableNode.setAttribute("class", "configure-window-panel-table");
            _contentContainer.appendChild(currentTableNode);


            currentTableNode2 = utils.createElement("table", {
                "class": constants.UI.PANEL_TABLE_CLASS
            });
			currentTableNode2.setAttribute("class", "configure-window-panel-table");
            _network_contentContainer.appendChild(currentTableNode2);

            utils.forEach(settingSection, function (setting, key) {
                if (settingType === 'Config' || settingType === 'Cpu'|| settingType === 'Storage' || settingType === 'Display' || settingType === 'Device') {
                    currentTableNode.appendChild(_buildDOMNode(setting, settingType, key));
                }
                else {
                    currentTableNode2.appendChild(_buildDOMNode(setting, settingType, key));
                }

                if (setting.callback) {
                    setting.callback(setting.control.value);
                }
            });
        });
        event.on("CpuLoadChanged", function (value) {
            document.getElementById("device-settings-Cpu-load").value = value;
        });
        event.on("DisplayBrightnessChanged", function (value) {
            document.getElementById("device-settings-Display-brightness").value = value;
        });
        event.on("CpuLoadChangedByPower", function (value) {
            document.getElementById("device-settings-Cpu-load").value = value;
        });
        event.on("DisplayBrightnessChangedByPower", function (value) {
            document.getElementById("device-settings-Display-brightness").value = value;
        });
    }
};

});
define('ripple/ui/plugins/goodVibrations', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants');

module.exports = {
    vibrateDevice: function (milliseconds) {
        var node = jQuery("#device-container"),
            x, times;

        times = Math.floor(milliseconds / 100);

        for (x = 1; x <= times; x++) {
            node.animate({ left: -10 }, 5)
            .animate({ left: 0 }, 1)
            .animate({ left: 10 }, 5)
            .animate({ left: 0 }, 1);

            node.animate({ top: -10 }, 5)
            .animate({ top: 0 }, 1)
            .animate({ top: 10 }, 5)
            .animate({ top: 0 }, 1);
        }
    },
    shakeDevice: function (times) {
        var node = jQuery("#device-container"),
            x;

        for (x = 1; x <= times; x++) {
            node.animate({ left: -25 }, 50)
            .animate({ left: 0 }, 30)
            .animate({ left: 25 }, 50)
            .animate({ left: 0 }, 30);
        }
    }
};

});
define('ripple/ui/plugins/storage', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event'),
    platform = require('ripple/platform'),
    utils = require('ripple/utils'),
    app = require('ripple/app'),
    db = require('ripple/db');

function _updatePreferencesView() {
    var node = document.getElementById(constants.COMMON.STORAGE_TABLE_BODY_CLASS),
        countTitle = document.getElementById(constants.COMMON.STORAGE_COUNT_CONTAINER_ID);

    // TODO: convert to appendChild
    if (node) {
        db.retrieveAll(platform.getPersistencePrefix(), function (results) {
            var str = "",
                counter = 0;

            utils.forEach(results, function (value, key) {
                // TODO: based of current platform
                if (app.isPreferenceReadOnly(key)) {
                    str += '<tr class="ui-text-highlight">';
                } else {
                    str += '<tr>';
                }
                str += '<td>' + key + '</td><td>' + value + "</td></tr>";
                counter ++;
            });

            node.innerHTML = str;
            countTitle.innerHTML = counter.toString();

            if (counter === 0) {
                jQuery("#" + constants.COMMON.STORAGE_CLEAR_BUTTON_ID).addClass(constants.CSS_PREFIX.IRRELEVANT);
            }
            else {
                jQuery("#" + constants.COMMON.STORAGE_CLEAR_BUTTON_ID).removeClass(constants.CSS_PREFIX.IRRELEVANT);
            }
        });
    }
}

module.exports = {
    panel: {
        domId: "preferences",
        collapsed: true,
        pane: "left"
    },
    initialize: function () {
        jQuery("#preferences-clear-button").bind("click", function () {
            db.removeAll(platform.getPersistencePrefix());
        });

        event.on("StorageUpdatedEvent", function () {
            _updatePreferencesView();
        });

        _updatePreferencesView();
    }
};

});
define('ripple/ui/plugins/devices', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    db = require('ripple/db');

function _getTextZooming(zooming) {
    return zooming + '%';
}

module.exports = {
    panel: {
        domId: "devices-container",
        collapsed: true,
        pane: "left",
        titleName: "Orientation & Zooming",
        display: true
    },

    initialize: function () {
        var zooming = document.getElementById(constants.ENCAPSULATOR.ZOOMING);

        function updateZoomingValues() {
            var zoomingText, scaleFactor, scaleString;
            
            zoomingText = _getTextZooming(zooming.value);
            jQuery('#screen-zooming-label').html(zoomingText);

            // Zooming device skin
            scaleFactor = zooming.value / 100;
            scaleString = "scale(" + scaleFactor + ")";
            jQuery('#device-layout').css('-webkit-transform', scaleString);
            jQuery('#device-layout').css('-webkit-transform-origin', 'left top');
        }

        function initializeValues() {
            var zoomingValue =  db.retrieve(constants.ENCAPSULATOR.ZOOMING);

            if (!zoomingValue) {
                zoomingValue = 100;
            }
            jQuery("#" + constants.ENCAPSULATOR.ZOOMING).val(zoomingValue);
            updateZoomingValues();
        }

        jQuery("#" + constants.ENCAPSULATOR.ZOOMING).bind("change", function () {
            updateZoomingValues();
            db.save(constants.ENCAPSULATOR.ZOOMING, zooming.value);
        });

        initializeValues();
    }
};


});
define('ripple/ui/plugins/options', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var about = require('ripple/ui/plugins/about-dialog'),
    settings = require('ripple/ui/plugins/settings-dialog'),
    tooltip = require('ripple/ui/plugins/tooltip'),
    hide,
    show;

show = function () {
    if (settings.value("remoteInspector")) {
        $("#options-menu-build-warning").show();
        tooltip.create("#options-menu-build-warning", "Remote Web Inspector should be disabled when packaging for App World release");
    }
    else {
        $("#options-menu-build-warning").hide();
    }

    $("#options-window").show();
    $("#options-menu").show();
};

hide = function () {
    $("#options-window").hide();
    $("#options-menu").effect("fade", {}, 300);
};

module.exports = {
    initialize: function () {
        $("#options-menu").menu().hide();
        $("#options-menu").bind("click", function (event) {
            var target = $("#" + event.target.parentElement.id),
                action;

            if (target.hasClass("not-ready")) {
                return;
            }

            switch (target.attr("id")) {
            case "options-menu-build":
            case "options-menu-launch":
            case "options-menu-sign":
                action = target.attr("id").split("-")[2];
                if (!settings.can(action)) {
                    settings.show(action);
                }
                else {
                    settings.perform(action);
                }
                break;
            case "options-menu-about":
                about.show();
                break;
            case "options-menu-settings":
                settings.show();
                break;
            default:
                break;
            }
            hide();
        });

        $("#options-window").click(hide);
        
        $("#options-button-about").bind("click", function (event) {
            about.show();
        });
        
        hide();
    }
};

});
define('ripple/ui/plugins/audioPlayer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    constants = require('ripple/constants'),
    audioObj = document.getElementById("multimedia-audio"),
    audioProgress = document.getElementById(constants.COMMON.MULTIMEDIA_AUDIO_PROGRESS_ID);

module.exports = {
    initialize: function () {
        var audioObj = document.getElementById("multimedia-audio"),
            audioProgress = document.getElementById(constants.COMMON.MULTIMEDIA_AUDIO_PROGRESS_ID);

        if (audioObj) {
            event.on("MultimediaVolumeChanged", function (volume) {
                audioObj.volume = parseFloat(volume / 10);
            });

            audioObj.addEventListener("timeupdate", function () {
                var s = parseInt(audioObj.currentTime % 60, 10),
                    m = parseInt((audioObj.currentTime / 60) % 60, 10);

                audioProgress.innerText = ((m > 9) ? m  : "0" + m) + ':' + ((s > 9) ? s  : "0" + s);
            }, false);

            event.on("MultimediaAudioStateChanged", function (state) {
                document.getElementById(constants.COMMON.MULTIMEDIA_AUDIO_STATE_FIELD_ID).innerText = state;
                document.getElementById(constants.COMMON.MULTIMEDIA_AUDIO_FILE_FIELD_ID).innerText = audioObj.getAttribute("src");
            });
        }
    }
};

});
define('ripple/ui/plugins/power', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    deviceSettings = require('ripple/deviceSettings'),
    power = require('ripple/platform/tizen/2.0/power'),
    _volume  = document.getElementById(constants.BATTERY.VOLUME),
    _volumeLabel  = document.getElementById(constants.BATTERY.VOLUME + "-label"),
    _charging = document.getElementById(constants.BATTERY.CHARGING),
    _battery = {
        volume: 600,
        level:  1.0,
        timerId: null,
        charge: function (isStart, isCharge, callback) {
            var currentVolume,
                checkValue = function () {
                    if (_battery.level < 0 || _battery.level > 1.0 || !isStart) {
                        clearInterval(_battery.timerId);
                        _battery.timerId = null;
                        if (_battery.level < 0)
                            _battery.level = 0;
                        else if (_battery.level > 1.0)
                            _battery.level = 1.0;
                    }
                };

            if (isStart && !_battery.timerId) {
                _battery.timerId = setInterval(function () {
                    currentVolume = isCharge ? _battery.level * _battery.volume + 1 : _battery.level * _battery.volume - 1;
                    _battery.level = currentVolume / _battery.volume;
                    checkValue();
                    return callback && callback();
                }, 1000);
            }
            checkValue();
            return callback && callback();
        }
    };

function _triggerEvent(chargingStatus, chargingTime, dischargingTime, level, type) {
    var status = {
        charging: chargingStatus,
        chargingTime: chargingTime,
        dischargingTime: dischargingTime,
        level: level,
        type: type
    };
    event.trigger("BatteryEvent", [status]);
}

function _updateLevelIcons() {
    var colors = ["black", "black", "black", "black", "black", "black", "#404040", "#606060", "#808080", "#b0b0b0", "#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff"],
        colorIndex = 10 - Math.round(_battery.level * 10),
        index;

    //map the battery level to the color range
    for (index = 0 ; index <= 5 ; index++) {
        $("#block" + index).css("backgroundColor", colors[colorIndex]);
        colorIndex++;
    }
}

function _setVolumeReadOnly(flag) {
    if (flag) {
        $("#" + constants.BATTERY.VOLUME).hide();
        $("#" + constants.BATTERY.VOLUME + "-label").show();
    } else {
        $("#" + constants.BATTERY.VOLUME).show();
        $("#" + constants.BATTERY.VOLUME + "-label").hide();
    }
}

function _startDischarging() {
    var remainVolume = $("#simulate-low-battery #low-battery-remain-time").val();

    _setVolumeReadOnly(true);
    if (_charging.checked) {
        _charging.checked = false;
        _battery.charge(false);
    }
    $("#is-charging").attr("disabled", "disable");
    $("#remaining-time-label").html("Remaining Time to empty (seconds)");
    _battery.level = $("#simulate-low-battery #low-battery-start-at").val() / 100.0;
    _battery.volume = remainVolume / _battery.level;
    _volumeLabel.innerText = (_battery.level * 100).toFixed(2);
    _battery.charge(true, false, function () {
        _volumeLabel.innerText = (_battery.level * 100).toFixed(2);
        _volume.value = (_battery.level * 100).toFixed(2);
        changeBatteryVolume();
        $("#remain-time").html(Math.round(_battery.volume * _battery.level) + " Seconds");
        _updateLevelIcons();
        _triggerEvent(false, Infinity, Math.round(_battery.volume * _battery.level), _battery.level, "dischargingtimechange");
        if (_battery.level <= 0.0) {
            _stopDischarging();
        }
    });
    $("#simulate-low-battery").dialog("close");
    $("#simulate-low-battery-btn").hide();
    $("#stop-btn").show();
}

function _stopDischarging() {
    $("#is-charging").removeAttr("disabled");
    _battery.level = _volume.value / 100.0;
    $("#remain-time").html("");
    $("#remaining-time-label").html("Remaining Time (seconds)");
    _setVolumeReadOnly(false);
    _battery.charge(false);
    $("#simulate-low-battery-btn").show();
    $("#stop-btn").hide();
    _updateLevelIcons();
}

function _setCharging() {
    // if it's unchecked, the timer will stop in this function call, the UI update blow it
    _battery.charge(_charging.checked, true, function () {
        _volumeLabel.innerText = (_battery.level * 100).toFixed(2);
        _volume.value = (_battery.level * 100).toFixed(2);
        changeBatteryVolume();
        $("#remain-time").html(Math.round(_battery.volume * (1 - _battery.level)) + " Seconds");    //show current remain time
        _updateLevelIcons();
        _triggerEvent(true, Math.round(_battery.volume * (1 - _battery.level)), Infinity, _battery.level, "chargingtimechange");
    });

    // update the UI parts
    if (_charging.checked) {
        _battery.volume = 600;
        _battery.level = _volume.value / 100;
        _setVolumeReadOnly(true);
        $("#remaining-time-label").html("Remaining Time to fully charged (seconds)");
        $("#charging-state").html("Plugged in - charging rate 0.17%/second");
    } else {
        _battery.level = _volume.value / 100.0;
        _updateLevelIcons();
        $("#remain-time").html("");
        _setVolumeReadOnly(false);
        $("#remaining-time-label").html("Remaining Time (seconds)");
        $("#charging-state").html("Plugged in?");
    }
}


function changeBatteryVolume() {
    if (_volume.value < 0)
                _volume.value = 0;
            else if (_volume.value > 100)
                _volume.value = 100;

            _battery.level = _volume.value / 100.0;
            _triggerEvent(true, 0, Infinity, _battery.level, "chargingtimechange");
            db.save(constants.BATTERY.VOLUME, _battery.level * 100);
            _updateLevelIcons();
}

function initBattery() {
    $("#" + constants.BATTERY.CHARGING).bind("change", _setCharging);

    $("#simulate-low-battery-btn").bind("click", function () {
        $("#simulate-low-battery").dialog("open");
    });

        $("#simulate-low-battery-cancel").bind("click", function () {
            $("#low-battery-start-at").val = 20;  //UI initialize
            $("#low-battery-remain-time").val = 1200;
            $("#simulate-low-battery").dialog("close");
        });

        $("#simulate-low-battery-start").bind("click", _startDischarging);
        $("#stop-btn").bind("click", _stopDischarging);

        $("#" + constants.BATTERY.VOLUME).bind("change", function () {
            changeBatteryVolume();
        });

        _charging.checked = false;
        _battery.level = db.retrieve(constants.BATTERY.VOLUME) / 100.0;
        _volume.value = (_battery.level * 100).toFixed(2);
        _updateLevelIcons();
        $("#simulate-low-battery").dialog({
            resizable: false,
            draggable: true,
            modal: true,
            autoOpen: false,
            position: 'center',
            minWidth: '460',
            minHeight: '240'
        });
}

module.exports = {
    panel: {
        domId: "power-container",
        collapsed: true,
        pane: "left",
        titleName: "Power",
        display: true
    },

    initialize: function () {
        var _RULES          =  constants.POWER_RULES,
            _PORWER_RULES_KEY = "tizen1-db-power-role",
            _DISPLAY_STATE  = constants.POWER_RESOURCE.DISPLAY.STATE,
            displayObj       = document.getElementById("display-power-state"),
            brightnessLabel  = document.getElementById("diplay-brightness-label"),
            brightness, stateObj;

        function initPowerState() {
            var obj, dbRules;
            brightness = deviceSettings.retrieve("Display.brightness");
            brightness = Number(brightness);
            brightnessLabel.innerHTML = "Display : (brightness = " + brightness + ")";
            //Init DISPLAY state.
            if (brightness ===  _DISPLAY_STATE.OFF.MAX) {
                displayObj.options[0].selected = true;
            } else if (brightness <= _DISPLAY_STATE.DIM.MAX) {
                displayObj.options[1].selected = true;
            } else if (brightness <= _DISPLAY_STATE.NORMAL.MAX) {
                displayObj.options[2].selected = true;
            } else {
                displayObj.options[3].selected = true;
            }
        }

        event.on("initPowerDB", function (rules) { //Update rule selects
            var obj;
            _RULES = rules;
            for (obj in rules) {
                stateObj = document.getElementById(obj.toLowerCase() + "-role");
                if (rules[obj]) {//Allow : true
                    stateObj.options[0].selected = true;
                } else {//Deny : false
                    stateObj.options[1].selected = true;
                }
            }
        });
        event.on("DisplayBrightnessChanged", initPowerState);
        event.on("DisplayBrightnessChangedByPower", initPowerState);

        displayObj.addEventListener("change", function () {
            var state = displayObj.value, value;
            value = _DISPLAY_STATE[state].VALUE;
            deviceSettings.persist("Display.brightness", value);
            event.trigger("DisplayBrightnessChanged", [value]);
        });

        document.getElementById("off-role").addEventListener("change", function () {
            var value = this.value;
            value = (value === '1' ? true : false);
            event.trigger("updatePowerRules", [{"state": 'OFF', "value": value}]);
        });
        document.getElementById("dim-role").addEventListener("change", function () {
            var value = this.value;
            value = (value === '1' ? true : false);
            event.trigger("updatePowerRules", [{"state": 'DIM', "value": value}]);
        });
        document.getElementById("normal-role").addEventListener("change", function () {
            var value = this.value;
            value = (value === '1' ? true : false);
            event.trigger("updatePowerRules", [{"state": 'NORMAL', "value": value}]);
        });
        document.getElementById("bright-role").addEventListener("change", function () {
            var value = this.value;
            value = (value === '1' ? true : false);
            event.trigger("updatePowerRules", [{"state": 'BRIGHT', "value": value}]);
        });
        initPowerState();
        initBattery();
    }
};
});
define('ripple/ui/plugins/accelerometer', function (require, exports, module) {
/*
 * Copyright (c) 2010 Epic Train Hack
 * Copyright (c) 2011 Research In Motion Limited
 * Contributors: Wolfram Kriesing, Dan Silivestru, Brent Lintner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
var ui = require('ripple/ui'),
    goodVibrations = require('ripple/ui/plugins/goodVibrations'),
    accelerometer = require('ripple/accelerometer'),
    event = require('ripple/event'),
    Rotation = require('ripple/platform/w3c/1.0/Rotation'),
    Acceleration = require('ripple/platform/w3c/1.0/Acceleration'),
    _mouseDown,
    _shiftKeyDown,
    _offsets = {
        x: 0,
        y: 0,
        z: -9.81,
    },
    _oldX,
    _oldY,
    _oldAlphaX,
    _shape =
        //
        // The front side
        //
        // x, y, z      x, y, z         x, y, z
        // for some strange reason for y -100 is top, 100 is bottom
        "-30,30,10,     30,30,10,       30,60,10,       100,100,100,-1,0;" + // top left, top right, bottom right - of the right triangle
        "-30,30,10,     30,60,10,       -30,60,10,      100,100,100,-1,0;" + // top left, right bottom, left bottom - of the left triangle
        // front side "the phone display"
        "-20,-50,11,    20,-50,11,      20,20,11,       100,100,100,-1,0;" +
        "-20,-50,11,    20,20,11,       -20,20,11,      100,100,100,-1,0;" +
        // below the display
        "-30,30,10,     30,20,10,       30,30,10,       0,0,0,-1,0;" +
        "-30,30,10,     -30,20,10,      30,20,10,       0,0,0,-1,0;" +
        // above the display
        "-30,-60,10,    30,-60,10,      30,-50,10,      0,0,0,-1,0;" +
        "-30,-60,10,    30,-50,10,      -30,-50,10,     0,0,0,-1,0;" +
        // left of the display
        "-30,-50,10,    -20,-50,10,     -20,20,10,      0,0,0,-1,0;" +
        "-30,-50,10,    -20,20,10,      -30,20,10,      0,0,0,-1,0;" +
        // right of the display
        "20,-50,10,     30,-50,10,      30,20,10,       0,0,0,-1,0;" +
        "20,-50,10,     30,20,10,       20,20,10,       0,0,0,-1,0;" +


        // back side, opposite side to the above one
        "-30,-60,-10,   30,60,-10,      30,-60,-10,     0,0,0,-1,0;" +
        "-30,-60,-10,   -30,60,-10,     30,60,-10,      0,00,-1,0;" +
        // right side
        "30,-60,-10,    30,60,-10,      30,60,10,       50,50,80,-1,0;" +
        "30,-60,-10,    30,60,10,       30,-60,10,      50,50,80,-1,0;" +
        // left side
        "-30,-60,-10,   -30,60,10,      -30,60,-10,     50,50,80,-1,0;" +
        "-30,-60,-10,   -30,-60,10,     -30,60,10,      50,50,80,-1,0;" +

        // top
        "30,-60,-10,    -30,-60,10, -30,-60,-10,    50,80,50,-1,0;" +
        "30,-60,-10,    30,-60,10,      -30,-60,10, 50,80,50,-1,0;" +
        // bottom
        "30,60,-10, -30,60,-10,     -30,60,10,      80,50,50,-1,0;" +
        "30,60,-10, -30,60,10,      30,60,10,       80,50,50,-1,0";

function _shakeDevice() {
    window.setTimeout(goodVibrations.shakeDevice(8), 1);
    accelerometer.shake();
}

function _updateAccelerometerPanel(motion) {
    jQuery("#accelerometer-x").html(Math.round(motion.accelerationIncludingGravity.x * 100) / 100);
    jQuery("#accelerometer-y").html(Math.round(motion.accelerationIncludingGravity.y * 100) / 100);
    jQuery("#accelerometer-z").html(Math.round(motion.accelerationIncludingGravity.z * 100) / 100);
    jQuery("#accelerometer-alpha").html(Math.round(motion.orientation.alpha));
    jQuery("#accelerometer-beta").html(Math.round(motion.orientation.beta));
    jQuery("#accelerometer-gamma").html(Math.round(motion.orientation.gamma));
}

function _updateCanvas(a, b, g) {
    ThreeDee.loadMesh(_shape);
    g = g || 0;
    ThreeDee.rotate(0, g, 0);
    ThreeDee.rotate(b, 0, a);
    ThreeDee.backface();
    ThreeDee.shade();
    ThreeDee.zSort();
    Draw.initialize(document.querySelector("#accelerometer-canvas"));
    Draw.clear(0, 0, 480, 300);
    Draw.drawScene(ThreeDee.getTranslation(), 3);
}

function _createCanvas() {
    var node = document.querySelector("#accelerometer-canvas"),
        x = 0, y = 0, z = -9.81,
        alpha = 0, beta = 0, gamma = 0,
        cosX, sinX, cosY, sinY,
        deltaAlpha = 360;

    ThreeDee.setCenter(150, 100);
    ThreeDee.setLight(-300, -300, 800);

    node.addEventListener("mousemove", function (e) {
        if (!_mouseDown)
            return;

        if (!_shiftKeyDown) {
            _offsets.x = (_offsets.x + _oldX - e.offsetX) % 360;
            _offsets.y = (_offsets.y + _oldY - e.offsetY) % 360;

            alpha = alpha || 0;

            // enforce gamma in [-90,90] as per w3c spec
            gamma = -_offsets.x;
            if (gamma < -90) {
                gamma = -90;
            }
            if (gamma > 90) {
                gamma = 90;
            }

            // enforce beta in [-180,180] as per w3c spec
            beta = -_offsets.y % 360;
            if (beta < -180) {
                beta += 360;
            }
            else if (beta >= 180) {
                beta -= 360;
            }

            cosX = Math.cos((gamma) * (Math.PI / 180));
            sinX = Math.sin((gamma) * (Math.PI / 180));
            cosY = Math.cos((beta) * (Math.PI / 180));
            sinY = Math.sin((beta) * (Math.PI / 180));
            x = 9.81 * cosY * sinX;
            y = -9.81 * sinY;
            z = -9.81 * cosY * cosX;

        }
        else {
            deltaAlpha = (deltaAlpha - (_oldAlphaX - e.offsetX) * 2.5) % 360;
            alpha = (360 - deltaAlpha) % 360;
        }

        _oldX = e.offsetX;
        _oldY = e.offsetY;
        _oldAlphaX = e.offsetX;

        _updateCanvas(deltaAlpha, -beta, gamma);
        accelerometer.setInfo({
            x: x,
            y: y,
            z: z,
            alpha: alpha,
            beta: beta,
            gamma: gamma
        });

    });

    node.addEventListener("mousedown", function (e) {
        _oldX = e.offsetX;
        _oldY = e.offsetY;
        if (_shiftKeyDown) {
            _oldAlphaX = _oldX;
        }
        _mouseDown = true;
    });

    node.addEventListener("mouseup", function (e) {
        _mouseDown = false;
    });

    node.addEventListener("dblclick", function (e) {   
        x = 0;
        y = 0;
        z = -9.81;
        alpha = 0;
        beta = 0;
        gamma = 0;
        deltaAlpha = 360;
        _resetAccelerometer();
    });

    document.addEventListener("mouseup", function (e) {
        //Catch mouseup events that fire when outside canvas bounds
        _mouseDown = false;
    });

    document.addEventListener("keydown", function (e) {
        if (e.keyCode === 16) { // Shift Key            
            _shiftKeyDown = true;
        }
    });

    document.addEventListener("keyup", function (e) {
        if (e.keyCode === 16) { // Shift Key
            _shiftKeyDown = false;
        }
    });    
}

function _resetAccelerometer() {    
    _updateCanvas(0, 0);
    _oldX = 0;
    _oldY = 0;
    _oldAlphaX = 0;
    _offsets = {
        x: 0,
        y: 0,
        z: -9.81,
    };
    accelerometer.setInfo({
        acceleration: new Acceleration(0, 0, 0),
        accelerationIncludingGravity: new Acceleration(0, 0, -9.81),
        rotationRate: new Rotation(0, 0, 0),
        orientation: new Rotation(0, 0, 0),
        timestamp: new Date().getTime()
    });
}

module.exports = {
    panel: {
        domId: "accelerometer-container",
        collapsed: true,
        pane: "left",
        titleName: "Accelerometer",
        display: true
    },
    initialize: function () {
        _createCanvas();
        
        _resetAccelerometer();

        _updateAccelerometerPanel(accelerometer.getInfo());

        jQuery("#accelerometer-shake").click(_shakeDevice);

        event.on("AccelerometerInfoChangedEvent", _updateAccelerometerPanel, this);
    }
};

});
define('ripple/ui/plugins/phone', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    Phone = require('ripple/platform/webworks.handset/2.0.0/client/Phone'),
    CallLog = require('ripple/platform/webworks.handset/2.0.0/client/CallLog'),
    event = require('ripple/event'),
    _console = require('ripple/console'),
    eventSelect = document.getElementById("phone-event-types"),
    eventErrorContainer = document.getElementById("phone-event-error-container"),
    eventErrorSelect = document.getElementById("phone-event-error-types");

function _firePhoneLogEvents(type, number, error) {
    if (type === Phone.CB_CALL_INITIATED ||
        type === Phone.CB_CALL_ANSWERED) {
        event.trigger("PhoneCallLogAdded", [{
            date: new Date(),
            number: number,
            status: CallLog.STATUS_NORMAL,
            type: CallLog.TYPE_RECEIVED_CALL
        }], true);
    } else if (type === Phone.CB_CALL_ENDED_BYUSER ||
                type === Phone.CB_CALL_FAILED) {
        event.trigger("PhoneCallLogAdded", [{
            date: new Date(),
            number: number,
            status: CallLog.STATUS_NORMAL,
            type: CallLog.TYPE_PLACED_CALL
        }], true);
    }
}

function _updateActiveCalls(type, number, error) {
    if (type === Phone.CB_CALL_INITIATED ||
        type === Phone.CB_CALL_CONNECTED ||
        type === Phone.CB_CALL_CONFERENCECALL_ESTABLISHED ||
        type === Phone.CB_CALL_DIRECTCONNECT_CONNECTED ||
        type === Phone.CB_CALL_ANSWERED) {
        event.trigger("PhoneCallInitiated", [{
            id: number,
            onhold: false,
            outgoing: false,
            recipient: {
                name: "",
                number: String(number)
            }
        }], true);
    } else if (type === Phone.CB_CALL_ENDED_BYUSER ||
                type === Phone.CB_CALL_FAILED ||
                type === Phone.CB_CALL_DISCONNECTED ||
                type === Phone.CB_CONFERENCECALL_DISCONNECTED ||
                type === Phone.CB_CALL_DIRECTCONNECT_DISCONNECTED) {
        event.trigger("PhoneCallEnded", [{
            id: number
        }], true);
    }
}

module.exports = {
    panel: {
        domId: "phone-container",
        collapsed: true,
        pane: "right"
    },
    initialize: function (prev, baton) {
        utils.forEach(Phone, function (value, prop) {
            if (prop.match(/^CB_/)) {
                eventSelect.appendChild(utils.createElement("option", {
                    value: value,
                    innerHTML: prop.replace(/^CB_(CALL_)?/, "")
                }));
            }

            if (prop.match(/^CALL_ERROR_/)) {
                eventErrorSelect.appendChild(utils.createElement("option", {
                    value: value,
                    innerHTML: prop.replace(/^CALL_ERROR_/, "")
                }));
            }
        });

        document.getElementById("phone-event-types").addEventListener("change", function () {
            eventErrorContainer.setAttribute("style", parseInt(eventSelect.value, 10) === Phone.CB_CALL_FAILED ? "" : "display: none");
        });

        document.getElementById("phone-logs-clear").addEventListener("click", function () {
            event.trigger("PhoneCallLogReset");
        });

        document.getElementById("phone-event-send").addEventListener("click", function () {
            var type = parseInt(eventSelect.value, 10),
                error = type === Phone.CB_CALL_FAILED ? eventErrorSelect.value : undefined,
                callId = document.getElementById("phone-call-id").value;

            _firePhoneLogEvents(type, callId, error);
            _updateActiveCalls(type, callId, error);

            event.trigger("PhoneEvent", [type, callId, error]);

            _console.log("Fired PhoneEvent (type " + type +  ") CallID: " +
                         callId + (error ? (" (error type " + error + ")") : ""));
        }, false);
    }
};

});
define('ripple/ui/plugins/configWindow', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    db = require('ripple/db'),
    platform = require('ripple/platform'),
    items = [{name: "DEVICE", id: "device-conf-panel"},
             {name: "SYSTEM SETTINGS", id: "system-settings-conf-panel"},
             {name: "NETWORK", id: "network-conf-panel"},
             {name: "PROGRAMS", id: "programs-conf-panel"}
            ],
    _KEY = "tizen-configuration-window-setting",
    _DIALOG_SETTING_KEY = "tizen-configuration-window-dialog-setting",
    _dialog_show_setting = 1,
    _settings = {};

function reload() {
    window.tinyHipposReload = true;
    location.reload();
}

function _hideConfigWindow() {
    $("#configure-window-popup").hide("slide", {direction: "up"}, "slow");
    $("#overlayBackground").hide("fade", "slow");
}

function _showConfigWindowDoneDialog() {
    $("#configure-window-done-popup").show("slide", {direction: "up"}, "slow");
    $("#overlayBackground").show("fade", "slow");
}

function _hideConfigWindowDoneDialog() {
    $("#configure-window-done-popup").hide("slide", {direction: "up"}, "slow");
    $("#overlayBackground").hide("fade", "slow");
}

function checkResolutionValue(val) {
	var ret = false;
	if (val >= 200 && val <= 2000) {
		ret = true;
	}
	return ret;
}

function _showConfigWindow() {
    var position_x;
    $("#item_container").empty();
    items.forEach(function (item) {
        $("#item_container").append('<div class="configuration-window-item">' + item.name + '</div>');
        $("#" + item.id).hide();
    });

    $("#content_container").show();
    $("#" + items[0].id).show("fast");
    
    $(".configuration-window-item:eq(0)").css("background-color", "#003399");
    $(".configuration-window-item:eq(0)").css("color", "#ffffff");

    $(".configuration-window-item").unbind('click');
    $(".configuration-window-item").bind("click", function () {    
        $(".configuration-window-item").css("background-color", "#eeeeee");
        $(".configuration-window-item").css("color", "#333333");
       
        $(this).css("background-color", "#003399");
        $(this).css("color", "#ffffff");

        items.forEach(function (item) {
            $("#" + item.id).hide();
        });
        $("#" + items[$(this).index()].id).show("fast");
    });

    if ($("#configure-window-popup").is(":visible")) {
        $("#configure-window-popup").hide("slide", {direction: "up"}, "slow");
        $("#overlayBackground").hide("fade", "slow");
        return;
    }

    position_x = (($(window).width() - 800) / 2)  < 0 ? 0 : ($(window).width() - 800) / 2;
    $("#configure-window-popup").css("top", 80);
    $("#configure-window-popup").css("left", position_x);

    position_x = (($(window).width() - 400) / 2)  < 0 ? 0 : ($(window).width() - 400) / 2;
    $("#configure-window-done-popup").css("top", 80);
    $("#configure-window-done-popup").css("left", position_x);

    $("#overlayBackground").css("width", $(window).width());
    $("#overlayBackground").css("height", $(window).height());
    $("#overlayBackground").show("fade", "slow");
    $("#configure-window-popup").show("slide", {direction: "up"}, "slow");

    $("#configuration-window-done-btn").unbind('click');
	$("#configuration-window-done-btn").bind("click", function () {
		var platformId, version, device, type, width, height;

		// device & resolution setting
		platformId = jQuery("#platform-select").val();
		version = jQuery("#version-select").val();
		device = jQuery("#device-select").val();
		width = jQuery("#resolution-custom-width").val();
		height = jQuery("#resolution-custom-height").val();
		type = jQuery('input:radio[name="resolution-type"]:checked').val();

		if (type === "custom") {
			device = "custom";
			if (!checkResolutionValue(width) || !checkResolutionValue(height)) {
				return;
			}
		}

		platform.changeEnvironment({
			"name": platformId,
			"version": version
		}, device, null);

        _hideConfigWindow();
        _dialog_show_setting = db.retrieve(_DIALOG_SETTING_KEY);
        if (_dialog_show_setting === undefined) {
            _dialog_show_setting = 1;
        }

        if (_dialog_show_setting === 1) {
            _showConfigWindowDoneDialog();
        }
        else {
		    setTimeout(reload, 500);
	    }
	});

    $("#configuration-window-done-btn2").unbind('click');
	$("#configuration-window-done-btn2").bind("click", function () {
	    if ($("#configure-window-done-dialog-show").is(':checked')) {
	        _dialog_show_setting = 0;
	    }

        db.save(_DIALOG_SETTING_KEY, _dialog_show_setting);
	    _hideConfigWindowDoneDialog();
	    setTimeout(reload, 500);
	});

    $("#configuration-window-close-btn").unbind('click');
    $("#configuration-window-close-btn").bind("click", function () {
        if ($("#configure-window-popup").is(":visible")) {
            _hideConfigWindow();
            return;
        }
    });

    $("#configuration-window-save-btn").unbind('click');
    $("#configuration-window-save-btn").bind("click", function () {
        var _type, _device, _custom_width = 0, _custom_height = 0;
        _device = jQuery("#device-select").val();
        _type = jQuery('input:radio[name="resolution-type"]:checked').val();
        if (_type === "custom") {
            _device = "custom";
            _custom_width = jQuery("#resolution-custom-width").val();
            _custom_height = jQuery("#resolution-custom-height").val();
        }
        _settings = {
            platformId : jQuery("#platform-select").val(),
            version : jQuery("#version-select").val(),
            device : _device,
            type : _type,
            custom_width : _custom_width,
            custom_height : _custom_height
        };
        db.saveObject(_KEY, _settings);
    });

    $("#configuration-window-load-btn").unbind('click');
    $("#configuration-window-load-btn").bind("click", function () {
    	var platformList,
    	    versionSelect = document.getElementById("version-select");
        _settings = db.retrieveObject(_KEY);

        jQuery("#platform-select").val(_settings.platformId);
        jQuery("#device-select").val(_settings.device);
        if (_settings.type === "custom") {
            $('input:radio[name="resolution-type"][value="custom"]').click();
            jQuery("#resolution-custom-width").val(parseInt(_settings.custom_width, 10));
            jQuery("#resolution-custom-height").val(parseInt(_settings.custom_height, 10));
        } else {
            $('input:radio[name="resolution-type"][value="predefined"]').click();
        }

        platformList = platform.getList();
        utils.forEach(platformList, function (platform) {
        	utils.forEach(platform, function (version, versionNumber) {
        		if (_settings.platformId === version.id) {
        			versionSelect.appendChild(utils.createElement("option", {
        				"innerText": versionNumber,
        				"value":  versionNumber
        			}));
                }
            });
        });
		jQuery("#version-select").val(_settings.version);
    });

    $(window).bind('resize', function () {
        var position_x = 0;
        $("#configure-window-popup").css("top", 80);
        position_x = (($(window).width() - 800) / 2)  < 0 ? 0 : ($(window).width() - 800) / 2;
        $("#configure-window-popup").css("left", position_x);

        $("#configure-window-done-popup").css("top", 180);
        position_x = (($(window).width() - 400) / 2)  < 0 ? 0 : ($(window).width() - 400) / 2;
        $("#configure-window-done-popup").css("left", position_x);

        $("#overlayBackground").css("width", $(window).width());
        $("#overlayBackground").css("height", $(window).height());
    });
}

module.exports = {
    initialize: function () {
        if (platform.current().id === "cordova") {
            items.splice(1, 1);
        }
        $("#options-button-config-window").bind("click", function ()  {
            _showConfigWindow();
        });
    }
};

});
define('ripple/ui/plugins/notifications', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    _notificationUIStack,
    _notificationTemplate = "";

function _remove(id) {
    delete _notificationUIStack[id];
    db.saveObject("posted-notifications", _notificationUIStack);
    event.trigger("refreshNotificationStack", [], true);
    _render();
}

function _removeAll() {
    _notificationUIStack = {};
    db.saveObject("posted-notifications", _notificationUIStack);
    event.trigger("refreshNotificationStack", [], true);
    $("#notification-box").empty();
    $("#remove-all-notifications-btn").hide();
}

function _render() {
    var notificationHTML = "",
        htmlContent = "";

    utils.forEach(_notificationUIStack, function (item) {
        notificationHTML = _notificationTemplate.replace(/#id/g, item.id)
            .replace(/#title/g, item.title)
            .replace(/#content/, item.content ? item.content : "")
            .replace(/#type/, item.type)
            .replace(/#statusType/, item.statusType)
            .replace(/#postedTime/, item.postedTime)
            .replace(/#iconPath/, item.iconPath ? item.iconPath : "")
            .replace(/#soundPath/, item.soundPath ? item.soundPath : "")
            .replace(/#vibration/, item.vibration !== undefined ? (item.vibration === true ? "true" : "false") : "")
            .replace(/#service/, item.service ? item.service : "")
            .replace(/#progressValue/, (item.statusType === "PROGRESS" && item.progressValue) ? item.progressValue.toString() + "%" : "")
            .replace(/#progressBarValue/, (item.statusType === "PROGRESS" && item.progressValue) ? item.progressValue : 0)
            .replace(/#displayBar/, item.statusType === "PROGRESS" ? "" : "none");
        htmlContent += notificationHTML;
    });

    $("#notification-box").accordion("destroy");
    $("#notification-box").html(htmlContent).accordion({
        active : false,
        collapsible : true,
        autoHeight : false
    });

    $("#notification-box .progress-bar").each(function (index, item) {
        $(item).width(this.id);
    });
    if (utils.count(_notificationUIStack) !== 0) {
        $("#remove-all-notifications-btn").show();
    } else {
        $("#remove-all-notifications-btn").hide();
    }
    $("." + "remove-notification-btn").bind("click", function () {
        _remove(this.id);
    });
}

module.exports = {
    panel: {
        domId: "notification-container",
        collapsed: true,
        pane: "left",
        titleName: "Notification",
        display: true
    },
    initialize: function () {
        _notificationTemplate = $("#notification-template").html();
        $("#notification-box").empty();
        _notificationUIStack = db.retrieveObject("posted-notifications") || {};
        _render();
        $("#remove-all-notifications-btn").bind("click", _removeAll);

        event.on("refreshNotificationUI", function () {
            _notificationUIStack = db.retrieveObject("posted-notifications");
            _render();
        });
    }
};

});
define('ripple/ui/plugins/widgetConfig', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    tooltip = require('ripple/ui/plugins/tooltip'),
    platform = require('ripple/platform'),
    widgetConfig = require('ripple/widgetConfig');

function _buildConfigAccordionNode(node, accordionContainer, counter) {
    var nodeDiv, nodeTitleH3, nodeContentDiv, tableString, attribute, child, result,
        tableClass, nameClass, attributeNameClass, messageClass, nameId, messageId, attributeName, attributeValue, attributeMessage,
        helpText = {},
        nodeCounter = 0,
        attributeCounter = 0,
        moreNodes = node.validationResult,
        createTooltip = function (value, index) {
            tooltip.create("#" +  index, value);
        };

    while (moreNodes) {
        result = node.validationResult[nodeCounter];

        if (!result) {
            // this should never happen
            return;
        }

        // the container of the entire accordion block
        nodeDiv = utils.createElement("div", {
            "id": "config-accordion-node-content-" + counter + "-" + nodeCounter,
            "class": "ui-corner-all"
        });

        // the header bar of the accordion block
        nodeTitleH3 = utils.createElement("h3", {
            "id": "config-accordion-node-title-" + counter + "-" + nodeCounter,
            "class": "config-accordion-node-title"
        });

        nodeTitleH3.appendChild(utils.createElement("a", {
            href: "#",
            innerText: node.nodeName,
            "class": constants.CONFIG.SUCCESS_CSS[(result.valid === undefined) ? "missing" : result.valid.toString()]
        }));
        nodeDiv.appendChild(nodeTitleH3);

        if (node.helpText) {
            helpText[nodeTitleH3.id] = node.helpText;
        }

        nodeContentDiv = utils.createElement("div");

        // display node value (add tool tip if exists)
        if (node.type || (!node.type && result && result.value)) {
            nodeContentDiv.appendChild(utils.createElement("div", {
                "id": "config-accordion-node-content-value-" + counter + "-" + nodeCounter,
                "class": "config-accordion-node-content-value",
                "innerHTML": "<span>Value:</span>" + (result.value || "")
            }));

            if (node.helpValueText) {
                helpText["config-accordion-node-content-value-" + counter + "-" + nodeCounter] = node.helpValueText;
            }
        }

        // display node message if failed validation
        if (result && result.message) {
            nodeContentDiv.appendChild(utils.createElement("div", {
                "id": "config-accordion-node-content-value-message-" + counter + "-" + nodeCounter,
                "class": "config-accordion-node-content-value-message ui-text-fail",
                "innerHTML": "<span>Message:</span>" + result.message
            }));
        }

        // display node attributes with name, value, message if failed validation
        if (result.attributes) {
            nodeContentDiv.appendChild(utils.createElement("div", {
                "id": "config-accordion-node-content-attributes-title-" + counter + "-" + nodeCounter,
                "class": "config-accordion-node-content-attributes-title",
                "innerHTML": "Attributes..."
            }));

            tableClass = "preferences-table";
            nameClass = "config-attributes-name-value";
            attributeNameClass = "ui-text-label";
            messageClass = "config-attributes-message";

            tableString = '<table class="' + tableClass + ' ui-widget-content">';
            for (attribute in result.attributes) {
                if (result.attributes.hasOwnProperty(attribute)) {
                    nameId = "config-accordion-node-content-attributes-table-name-" + counter + "-" + nodeCounter + "-" + attributeCounter;
                    messageId = "config-accordion-node-content-attributes-table-message-" + counter + "-" + nodeCounter + "-" + attributeCounter;
                    attributeName = result.attributes[attribute].attributeName;
                    attributeValue = result.attributes[attribute].value || "&nbsp;";
                    attributeMessage = result.attributes[attribute].message || null;

                    tableString += '<tr class="' + nameClass + '" id="' + nameId + '">' +
                            '<td class="' + attributeNameClass + '">' + attributeName + '</td>' +
                            '<td>' + attributeValue + '</td></tr>';

                    if (node.attributes[attributeName].helpText) {
                        helpText[nameId] = node.attributes[attributeName].helpText;
                    }

                    if (attributeMessage !== null) {
                        tableString += "<tr class=" + messageClass + " id=" + messageId + "><td colspan=\"2\">" +
                                attributeMessage + "</td></tr>";
                    }
                    attributeCounter++;
                }
            }
            tableString += "</table>";

            nodeContentDiv.innerHTML += tableString;
        }


        nodeDiv.appendChild(nodeContentDiv);
        accordionContainer.appendChild(nodeDiv);

        utils.forEach(helpText, createTooltip);

        nodeCounter ++;

        if (!node.validationResult[nodeCounter]) {
            nodeCounter = 0;
            moreNodes = false;
        }
    }

    if (node.children) {
        for (child in node.children) {
            if (node.children.hasOwnProperty(child)) {
                counter ++;
                _buildConfigAccordionNode(node.children[child], accordionContainer, counter);
            }
        }
    }
}

function _initializeConfigResultsView(results) {
    try {
        var rootNode,
            accordionContainer = document.getElementById("widget-config");

        accordionContainer.innerHTML = "";
        if (!results) {
            accordionContainer.appendChild(utils.createElement("div", {
                "class": "config-accordion-node-title " + constants.CONFIG.SUCCESS_CSS["false"],
                "innerHTML": "Expected to find a configuration file for your application, but none is present. Please create" +
                        " a configuration file with the following name in the root directory of your application: " +
                        platform.current().fileName
            }));
            return;
        }

        rootNode = results[results.rootElement];

        _buildConfigAccordionNode(rootNode, accordionContainer, 0);

        jQuery(function () {
            var stop = false;
            jQuery("#widget-config h3").click(function (event) {
                if (stop) {
                    event.stopImmediatePropagation();
                    event.preventDefault();
                    stop = false;
                }
            });
            jQuery("#widget-config").accordion("destroy").accordion({
                header: "> div > h3",
                autoHeight: false
            });
        });
    } catch (e) {
        exception.handle(e, true);
    }
}

event.on("FrameHistoryChange", function () {
    module.exports.initialize();
});

module.exports = {
    panel: {
        domId: "config-container",
        collapsed: true,
        pane: "right",
        titleName: "Feature Configuration",
        display: true
    },
    initialize: function () {
        var results = widgetConfig.getValidationResults();
        _initializeConfigResultsView(results);
    }
};

});
define('ripple/ui/plugins/settings-dialog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    utils = require('ripple/utils'),
    platform = require('ripple/platform'),
    notifications = require('ripple/notifications'),
    transport = require('ripple/platform/webworks.core/2.0.0/client/transport'),
    tooltip = require('ripple/ui/plugins/tooltip'),
    bus = require('ripple/bus'),
    required = {
        build: {
            "webworks.tablet": ["sdk", "projectPath", "outputPath", "projectName"],
            "webworks.bb10": ["sdk", "projectPath", "outputPath", "projectName"],
            "webworks.handset": ["sdk", "projectPath", "outputPath", "projectName"]
        },
        sign: {
            "webworks.tablet": ["sdk", "projectPath", "outputPath", "projectName", "csk_password", "p12_password", "bundle_number"],
            "webworks.bb10": ["sdk", "projectPath", "outputPath", "projectName", "signingPassword", "bundle_number"],
            "webworks.handset": ["sdk", "projectPath", "outputPath", "projectName", "signingPassword"]
        },
        launch: {
            "webworks.tablet": ["sdk", "projectPath", "outputPath", "projectName", "device"],
            "webworks.bb10": ["sdk", "projectPath", "outputPath", "projectName", "device"],
            "webworks.handset": ["sdk", "projectPath", "outputPath", "projectName", "simulator"]
        }
    },
    _settings = {
        get: function () {
            var settings = db.retrieveObject("build-settings", platform.getPersistencePrefix()) || {};
            settings.debug = !!settings["remoteInspector"];

            return settings;
        },
        save: function (settings) {
            db.saveObject("build-settings", settings, platform.getPersistencePrefix());
        }
    },
    port = "9910",
    host = "http://127.0.0.1:" + port + "/ripple",
    progressContainer = jQuery("#options-progress"),
    progressInterval,
    _passwordFields = [
        "signingPassword",
        "devicePassword",
        "csk_password",
        "p12_password"
    ],
    _checkboxFields = [
        "remoteInspector"
    ],
    _passwords = {},
    _self;

function missing(settings, action) {
    return required[action][platform.current().id].filter(function (field) {
        return !settings.hasOwnProperty(field);
    });
}

function _isPasswordField(id) {
    var match = typeof id === "string" && new RegExp("^" + id + "$", "i");
    return match && utils.some(_passwordFields, function (name) {
        return match.test(name);
    });
}

function _isCheckboxField(id) {
    var match = typeof id === "string" && new RegExp("^" + id + "$", "i");
    return match && utils.some(_checkboxFields, function (name) {
        return match.test(name);
    });
}

function table(action) {
    var _table = $("<table class='panel-table'>"),
        _row = {
            row: function (item, desc, opts) {
                var id = "settings-field-" + item.toLowerCase(),
                    input = "",
                    save = function () {
                        var s = _settings.get(),
                            v = $("#" + id).val(),
                            val = opts.type === "number" ? parseInt(v, 10) : v;

                        if (_isCheckboxField(item)) {
                            s[item] = $("#" + id).prop("checked");
                        }
                        else if (val) {
                            (_isPasswordField(item) ? _passwords : s)[item] = val;
                        }
                        else {
                            delete s[item];
                        }
                        _settings.save(s);

                        if (opts.onChanged) {
                            opts.onChanged(s[item]);
                        }
                    },
                    row;

                opts = opts || { type: "text" };

                switch (opts.type) {
                case "select":
                    input = "<select id='" + id + "' class='ui-state-default ui-corner-all' style='width:100%'/>";
                    break;
                case "span":
                    input = "<span id = '" + id + "'>" + opts.text + "</span>";
                    break;
                default:
                    input = "<input id='" + id + "' type='" + opts.type + "' class='ui-state-default ui-corner-all' style='width:90%' />";
                    break;
                }

                row = $("<tr>" +
                    "<td><label for='" + id + "' class='ui-text-label'>" + desc + "</label></td>" +
                    "<td>" + input + "</td>" +
                "</tr>");

                row.appendTo(_table);

                //bind save handlers to the row
                utils.bindAutoSaveEvent(row.find("#" + id).change(save), save);

                return _row;
            },
            appendTo: function (id) {
                var fs = $("<fieldset class='main'><legend class='cap-text'>" + action + "</legend></fieldset>");

                $(_table).appendTo(fs);
                fs.appendTo($(id));
            }
        };

    return _row;
}

function create() {
    var build = table('build'),
        sign = table('sign'),
        launch = table('launch');

    build
        .row("sdk", "SDK Path")
        .row("projectPath", "Project Root")
        .row("projectName", "Archive Name")
        .row("outputPath", "Output Folder")
        .row("remoteInspector", "Enable Remote Web Inspector", {
            type: "checkbox",
            onChanged: function (enabled) {
                if (enabled) {
                    $("#options-menu-build-warning").show();
                    tooltip.create("#options-menu-build-warning", "Remote Web Inspector should be disabled when packaging for App World release");
                }
                else {
                    $("#options-menu-build-warning").hide();
                }
            }
        })
        .appendTo("#settings-tabs-build");

    switch (platform.current().id) {
    case "webworks.handset":
        sign.row("signingPassword", "Password", {
            type: "password"
        });

        launch.row("simulator", "Simulator", {
            type: "select"
        });

        launch.row("simulatorstatus", "Simulator", {
            type: "span",
            text: "Searching for simulators ..."
        });
        
        break;

    case "webworks.tablet":
        sign.row("csk_password", "CSK Password", {
            type: "password"
        });
        sign.row("p12_password", "P12 Password", {
            type: "password"
        });
        sign.row("bundle_number", "Bundle Number", {
            type: "number"
        });

        launch.row("device", "Playbook IP");
        launch.row("devicePassword", "Playbook Password", {
            type: "password"
        });

        break;

    case "webworks.bb10":
        sign.row("signingPassword", "Signing Password", {
            type: "password"
        });
        sign.row("bundle_number", "Bundle Number", {
            type: "number"
        });

        launch.row("device", "Device IP");
        launch.row("devicePassword", "Device Password", {
            type: "password"
        });

        break;
    }

    sign.appendTo("#settings-tabs-build");
    launch.appendTo("#settings-tabs-build");

    $("#settings-field-simulator").parent().parent().hide();
}

function populate(settings) {
    var fill = function (action, prop) {
        var element = $("#settings-field-" + prop.toLowerCase());

        if (_isPasswordField(prop)) {
            element.val(_passwords[prop]);
        }
        else if (_isCheckboxField(prop)) {
            element.prop("checked", settings[prop]);
        }
        else {
            element.val(settings[prop]);
        }
    };

    fill("build", "sdk");
    fill("build", "projectPath");
    fill("build", "outputPath");
    fill("build", "projectName");
    fill("build", "remoteInspector");

    fill("sign", "signingPassword");
    fill("sign", "csk_password");
    fill("sign", "p12_password");
    fill("sign", "bundle_number");

    fill("launch", "simulator");
    fill("launch", "device");
    fill("launch", "devicePassword");
}

function url(action) {
    var target = "";

    switch (platform.current().id) {
    case "webworks.bb10":
        target = "bb10";
        break;
    case "webworks.tablet":
        target = "tablet";
        break;
    case "webworks.handset":
        target = "smartphone";
        break;
    }

    return host + "/" + action + "/" + target;
}

function enable(action) {
    $("#options-menu-" + action).removeClass("not-ready");
    if (action === "launch") {
        $("#settings-field-simulatorstatus").parent().parent().hide();
        $("#settings-field-simulator").parent().parent().show();
    }
}

function disable(action) {
    $("#options-menu-" + action).addClass("not-ready");
    if (action === "launch") {
        $("#settings-field-simulatorstatus").parent().parent().show();
        $("#settings-field-simulator").parent().parent().hide();
    }
}

function getSimulators() {
    if (!_settings.get().sdk) {
        $("#settings-field-simulatorstatus").text("");
        disable("launch");
        return;
    }

    bus.ajax(
        "POST", 
        host + "/simulators",
        _settings.get(), 
        function (resp) {
            var sims = resp.data.simulators;

            $("#settings-field-simulator").empty();
            if (sims.length > 0) {
                $(resp.data.simulators.map(function (sim) {
                    return "<option value='" + sim + "'>" + sim + "</option>";
                }).join()).appendTo("#settings-field-simulator");

                enable("launch");
            }
            else {
                disable("launch");
                $("#settings-field-simulatorstatus").text("No simulators found :(");
            }
        },
        function () {
            disable("launch");
            $("#settings-field-simulatorstatus").text("Error attempting to get simulators :(");
        }
    );
}

function _startProgress() {
    if (progressInterval) {
        window.clearInterval(progressInterval);
    }
    progressInterval = window.setInterval(function () {
        if (progressContainer.html().length === 5) {
            progressContainer.html(".");
        }
        else {
            progressContainer.html(progressContainer.html() + ".");
        }
    }, 250);
}

function _endProgress() {
    window.clearInterval(progressInterval);
    progressInterval = null;
    progressContainer.html("");
}


_self = {
    initialize: function () {
        $("#settings-dialog").dialog({
            autoOpen: false,
            modal: true,
            width: 700,
            title: "Settings",
            position: 'center'
        }).hide();

        $("#settings-tabs").tabs();
        $("#settings-action").button();

        create();

        if (platform.current().id === "webworks.handset") {
            enable("build");
            enable("sign");
            enable("settings");

            getSimulators();
            $("#settings-field-sdk").change(getSimulators);
        }
        else if (platform.current().id === "webworks.tablet") {
            enable("build");
            enable("sign");
            enable("launch");
            enable("settings");
        }
        else if (platform.current().id === "webworks.bb10") {
            enable("build");
            enable("sign");
            enable("launch");
            enable("settings");
        }
    },

    can: function (action) {
        var settings = {};

        utils.mixin(_settings.get(), settings);
        utils.mixin(_passwords, settings);

        return action && missing(settings, action).length === 0;
    },

    value: function (prop) {
        var settings = {};

        utils.mixin(_settings.get(), settings);
        return settings[prop];
    },

    show: function (action) {
        var settings = {};

        utils.mixin(_settings.get(), settings);
        utils.mixin(_passwords, settings);

        populate(settings);

        $("#settings-dialog").dialog("open");
        $("#settings-action").button("option", "label", action || "Close")[action ? "show" : "hide"]();

        if (action) {
            missing(settings, action).forEach(function (field) {
                $("#settings-field-" + field.toLowerCase()).effect("highlight", {color: "red"}, 1500);
            });

            $("#settings-action").unbind("click").click(function () {
                if (_self.can(action)) {
                    _self.perform(action);
                    $("#settings-dialog").dialog("close");
                }
                else {
                    _self.show(action);
                }
            });
        }
    },

    perform: function (action) {
        var settings = _settings.get(),
            data = {},
            poll = function (resp) {
                var notifications = require("ripple/notifications");

                if (resp && resp.code !== 0) {
                    notifications.openNotification("error", "Build request failed with message: " + resp.msg);
                    _endProgress();
                }
                else {
                    if (resp && resp.data.status === "building") {
                        setTimeout(function () {
                            bus.ajax(
                                "GET",
                                host + "/build_status/" + resp.data.id,
                                null,
                                poll,
                                function (error) {
                                    notifications.openNotification("error", "Build request failed with message: " + JSON.stringify(error));
                                    _endProgress();
                                }
                            );
                        }, 500);
                    }
                    else {
                        if (action.match(/sign/)) {
                            settings["bundle_number"] = $("#settings-field-bundle_number").val(parseInt($("#settings-field-bundle_number").val(), 10) + 1).val();
                            _settings.save(settings);
                        }
                        notifications.openNotification("normal", "Build succeeded!");
                        _endProgress();
                    }
                }
            };

        utils.mixin(settings, data);
        utils.mixin(_passwords, data);

        bus.ajax(
            "POST",
            url(action),
            data,
            function (resp) {
                _startProgress();
                poll(resp);
            },
            function (error) {
                var message = "Build request failded with message: " + error.data;

                if (error.code === 0 || error.code === 404) {
                    message += "<br>This could be due to the Build and Deploy services not running or not being installed";
                }

                notifications.openNotification("error", message);
            }
        );
    }
};

module.exports = _self;

});
define('ripple/ui/plugins/multimedia', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event'),
    volumeField = document.getElementById(constants.COMMON.MULTIMEDIA_VOLUME_FIELD_ID),
    volume = document.getElementById(constants.COMMON.MULTIMEDIA_VOLUME_SLIDER_ID);

module.exports = {
    panel: {
        domId: "multimedia-container",
        collapsed: true,
        pane: "left"
    },
    initialize: function () {
        var volumeField = document.getElementById(constants.COMMON.MULTIMEDIA_VOLUME_FIELD_ID),
            volume = document.getElementById(constants.COMMON.MULTIMEDIA_VOLUME_SLIDER_ID);

        event.on("MultimediaVolumeChanged", function (volume) {
            volumeField.innerText = volume > 9 ? volume : "0" + volume;
            if (volume.value !== volume) {
                volume.value = volume;
            }
        });

        volume.addEventListener('change', function () {
            event.trigger("MultimediaVolumeChanged", [this.value], true);
        }, false);

        event.on("MultimediaAudioStateChanged", function updateIsAudioPlaying(state) {
            document.getElementById(constants.COMMON.MULTIMEDIA_AUDIO_PLAYING_FIELD_ID).innerHTML = state === constants.MULTIMEDIA.AUDIO_STATES.PLAYING;
        });
    }
};

});
define('ripple/ui/plugins/nfc', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    _NFC_TAG = "tizen1.0-nfc-tag",
    _NFC_PEER = "tizen1.0-nfc-peer",
    _NFC_OUTPUT_MESSAGE = "tizen1.0-nfc-output-message",
    powered = false,
    polling = false,
    isConnected = false,
    _tagNDEF = {
        type: "GENERIC_TARGET",
        isSupportedNDEF: true,
        ndefSize: 2,
        ndefs: [{
            recordCount: 2,
            records: [{
                tnf: 1,
                type: "TypeA",
                id: "ID001",
                payload: "This is 1st payload"
            }, {
                tnf: 1,
                type: "TypeA",
                id: "ID002",
                payload: "This is 2nd payload"
            }]
        },
            {
            recordCount: 2,
            records: [{
                tnf: 1,
                type: "TypeA",
                id: "ID001",
                payload: "This is 1st payload"
            }, {
                tnf: 1,
                type: "TypeA",
                id: "ID002",
                payload: "This is 2nd payload"
            }]
        }]
    },
    _tagRaw = {
        type: "GENERIC_TARGET",
        isSupportedNDEF: false,
        rawData : ""
    },
    _peerNDEF = {
        ndef: {
            recordCount: 2,
            records: [{
                tnf: 1,
                type: "TypeA",
                id: "ID001",
                payload: "This is 1st payload"
            }, {
                tnf: 1,
                type: "TypeA",
                id: "ID002",
                payload: "This is 2nd payload"
            }]
        }
    };

function elementEnableDisableSetting(prop) {
    jQuery("#nfc-attach-msg").text("\xa0");
    jQuery("#nfc-peer-send-msg").text("\xa0");
    if (prop && prop.power !== undefined && prop.power !== null) {
        if (prop.power) {
            $("#nfc-polling").removeAttr("disabled");
            $("#nfc-main-container").show();
        } else {
            $("#nfc-polling").attr("disabled", "disabled");
            $("#nfc-type").removeAttr("disabled");
            $("#nfc-main-container").hide();
        }
    }
    if (prop && prop.connectedState !== undefined && prop.connectedState !== null) {
        if (prop.connectedState) {
            $("#nfc-type").attr("disabled", "disabled");
            $("#nfc-tag-type-text").text($("#nfc-tag-type option:selected").text());
            $("#nfc-tag-type").hide();
            $("#nfc-tag-type-text").show();
            $("#nfc-tag-NDEF-support-text").text($("#nfc-tag-NDEF-support option:selected").text());
            $("#nfc-tag-NDEF-support").hide();
            $("#nfc-tag-NDEF-support-text").show();
            $("#nfc-raw-data").attr("disabled", "disabled");
        } else {
            $("#nfc-type").removeAttr("disabled");
            $("#nfc-tag-type").show();
            $("#nfc-tag-type-text").hide();
            $("#nfc-tag-NDEF-support").show();
            $("#nfc-tag-NDEF-support-text").hide();
            $("#nfc-raw-data").removeAttr("disabled");
        }
    }
}

function _initializeElements() {

    jQuery(function () {
        var stop = false,
            isSupportNDEF, type;

        jQuery("nfc-tag-ndef-container h3").click(function (event) {
            if (stop) {
                event.stopImmediatePropagation();
                event.preventDefault();
                stop = false;
            }
        });
        jQuery("#nfc-tag-ndef-container").accordion("destroy").accordion({
            header: "> div > h3",
            autoHeight: false
        });
        jQuery("nfc-nfcpeer h3").click(function (event) {
            if (stop) {
                event.stopImmediatePropagation();
                event.preventDefault();
                stop = false;
            }
        });
        jQuery("#nfc-nfcpeer").accordion("destroy").accordion({
            header: "> div > h3",
            autoHeight: false
        });
        jQuery("#nfc-tag-NDEF-support").bind("change", function () {
            isSupportNDEF = jQuery("#nfc-tag-NDEF-support").val();
            if (isSupportNDEF === "Yes") {
                jQuery("#nfc-tag-ndef-container").fadeIn();
                jQuery("#nfc-tag-raw-container").hide();
            } else {
                jQuery("#nfc-tag-ndef-container").hide();
                jQuery("#nfc-tag-raw-container").fadeIn();
            }
        });
        jQuery("#nfc-type").bind("change", function () {
            type = jQuery("#nfc-type").val();
            if (type === "Tag") {
                jQuery("#nfc-nfctag").fadeIn();
                jQuery("#nfc-nfcpeer").hide();
            } else {
                jQuery("#nfc-nfctag").hide();
                jQuery("#nfc-nfcpeer").fadeIn();
            }
            elementEnableDisableSetting();
        });
        jQuery("#nfc-power").bind("change", function () {
            var status;
            status = jQuery("#nfc-power").val() === "On" ? true : false;
            event.trigger("nfc-power-setting", [status]);
        });
        jQuery("#nfc-polling").bind("change", function () {
            var status;
            status = jQuery("#nfc-polling").val() === "On" ? true : false;
            event.trigger("nfc-polling-setting", [status]);
        });
        jQuery("#nfc-attach").bind("click", function () {
            var type, isAttached;
            isAttached = jQuery("#nfc-attach").children().text() === "Attach" ? true : false;
            jQuery("#nfc-attach-msg").text("\xa0");

            if (!polling && isAttached) {
                jQuery("#nfc-attach-msg").text("Polling:Off, attach won't work");
                return;
            }
            type = jQuery("#nfc-type").val();
            event.trigger("nfc-attach-setting", [type, isAttached]);
        });
        jQuery("#nfc-peer-send").bind("click", function () {
            jQuery("#nfc-peer-send-msg").text("\xa0");
            if (!isConnected) {
                jQuery("#nfc-peer-send-msg").text("Disconnected. Send won't work");
                return;
            }
            db.saveObject(_NFC_PEER, _peerNDEF);
            event.trigger("nfc-peer-sending-ndef", []);
        });
    });
}

module.exports = {
    panel: {
        domId: "nfc-container",
        collapsed: true,
        pane: "left",
        titleName: "NFC",
        display: true
    },
    initialize: function () {
        _initializeElements();
        event.on("nfc-power-changed", function (status) {
            powered = status;
            if (powered === true) {
                $("#nfc-power").val("On");
            } else {
                $("#nfc-power").val("Off");
            }
            elementEnableDisableSetting({power: status});
        });
        event.on("nfc-polling-changed", function (status) {
            polling = status;
            if (polling === true) {
                $("#nfc-polling").val("On");
            } else {
                $("#nfc-polling").val("Off");
            }
            elementEnableDisableSetting();
        });
        event.on("nfc-connectedState-changed", function (state) {
            var i, type, isSupportedNDEF, str, bytes = [];
            isConnected = state;
            elementEnableDisableSetting({connectedState: state});
            type = jQuery("#nfc-type").val();
            if (state) {
                jQuery("#nfc-attach").children().text("Detach");
                jQuery("#nfc-tag-connection").text("Connected");
                jQuery("#nfc-peer-connection").text("Connected");
                if (type === "Tag") {
                    isSupportedNDEF = jQuery("#nfc-tag-NDEF-support").val() === "Yes" ? true : false;
                    if (isSupportedNDEF) {
                        _tagNDEF.type = jQuery("#nfc-tag-type").val();
                        db.saveObject(_NFC_TAG, _tagNDEF);
                    } else {
                        _tagRaw.type = jQuery("#nfc-tag-type").val();
                        str = jQuery("#nfc-raw-data").val();
                        for (i = 0; i < str.length; i++) {
                            bytes.push(str.charCodeAt(i));
                        }
                        _tagRaw.rawData = bytes;
                        db.saveObject(_NFC_TAG, _tagRaw);
                    }
                    event.trigger("nfc-tag-send", [true]);
                } else {
                    event.trigger("nfc-peer-send", [true]);
                }
            } else {
                jQuery("#nfc-attach").children().text("Attach");
                jQuery("#nfc-tag-connection").text("Disconnected");
                jQuery("#nfc-peer-connection").text("Disconnected");
                jQuery("#nfc-output").text("");
                jQuery("#nfc-output-table").hide();
                if (type === "Tag") {
                    event.trigger("nfc-tag-send", [false]);
                } else {
                    event.trigger("nfc-peer-send", [false]);
                }
            }
        });
        event.on("nfc-output-msg", function () {
            var msg;
            msg = db.retrieve(_NFC_OUTPUT_MESSAGE);
            jQuery("#nfc-output").text(msg);
            jQuery("#nfc-output-table").show();
        });
    }
};


});
define('ripple/ui/plugins/platformEvents', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _console = require('ripple/console'),
    platform = require('ripple/platform'),
    event = require('ripple/event'),
    exception = require('ripple/exception'),
    utils = require('ripple/utils');

module.exports = {
    panel: {
        domId: "platform-events-container",
        collapsed: true,
        pane: "right",
        titleName: "Platform Events",
        display: true
    },
    initialize: function () {
        var eventSelect = document.getElementById("platform-events-select"),
            spec = platform.current();

        if (!spec.events) {
            return;
        }

        utils.forEach(spec.events, function (method, name) {
            eventSelect.appendChild(utils.createElement("option", {
                "innerText": name,
                "value": name
            }));
        });

        jQuery("#platform-events-fire").click(function () {
            var eventName = document.getElementById("platform-events-select").value,
                args = spec.events[eventName].args ? document.getElementById("platform-events-args").value : null,
                callback = spec.events[eventName].callback;

            _console.log("fired event => " + eventName);

            try {
                callback(args);
            } catch (e) {
                exception.throwMaskedException(e);
            }
        });

        jQuery(eventSelect).change(function () {
            var argsSelect = jQuery("#platform-events-args"),
                args = spec.events[this.value].args;

            argsSelect.empty();

            if (args) {
                utils.forEach(spec.events[this.value].args, function (arg, index) {
                    argsSelect.append(utils.createElement("option", {
                        innerText: arg,
                        value: index
                    }));
                });

                argsSelect.show();
            } else {
                argsSelect.hide();
            }
        });
    }
};

});
define('ripple/ui/plugins/communication', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var ui = require('ripple/ui'),
    event = require('ripple/event'),
    db = require('ripple/db'),
    utils = require('ripple/utils'),
    _messageType = {
        sms: "SMS",
        mms: "MMS",
        email: "E-mail"
    },
    _attachments = [],
    _exception = {
        "":                  "Connection Issue",
        "unknown":           "Unknown",
        "network":           "Network",
        "unreachable":       "Unreachable",
        "no-answer":         "No Answer",
        "bad-number":        "Bad Number",
        "number-not-in-use": "Number Not In Use",
        "media":             "Media",
        "no-sim":            "No Sim Card",
        "account-down":      "Account Down",
        "credit-down":       "Credit Down",
        "barred":            "Barred",
        "network-busy":      "Network Busy",
        "network-down":      "Network Down"
    },
    _status = {
        IDLE:       0,
        DIALED:     1,
        INPROGRESS: 2,
    },
    _data = {
        status: _status.IDLE,
        isInException: false,
        conversationStartTime: null
    },
    _contactNameArr = [],
    _contactNumArr = [],
    _CONTACT_KEY = "tizen1-contact",
    _record = {},
    _conversationSeconds = 0,
    _conversationTimer,
    _msgTimer;

function _showMsg() {
    var messageName = jQuery("#communication-senderName").val(),
        messageContent = jQuery("#communication-messageContent").val(),
        disMsgName = jQuery(".communication-messageContainer tr:first-child td"),
        disMsgContent = jQuery(".communication-messageContainer tr:nth-child(2) td textarea");

    ui.showOverlay("communication-window");

    disMsgName.text(messageName ? messageName : "UNKONW NAME");
    disMsgContent.val(messageContent ? messageContent : "");

    jQuery("#communication-viewport").css("height", jQuery("#viewport-container").css("height"))
                                     .show("clip", 1000);
    jQuery(".communication-callContainer").hide();
    jQuery(".communication-messageContainer").show();
}

function _msgEventInitialize() {
    jQuery("#communication-sendMessage").unbind("click").click(function () {
        var messageItem,
            number = jQuery("#communication-senderName").val(),
            text = jQuery("#communication-messageContent").val(),
            type = jQuery("#communication-msgType").val(),
            message = {
                type: type,
                body: text,
                from: number,
                time: new Date(),
                attachments: _attachments
            };

        event.trigger("MessageReceived", [message]);
        _attachments = [];

        _showMsg();

        jQuery(".communication-messageContainer textarea").attr("disabled", "disabled");
        jQuery("#communication-messageOut td:nth-child(3)").text(jQuery("#communication-messageContent").val());
        messageItem = jQuery("#communication-messageOut").html();
        jQuery("#communication-messageDisplay").append(messageItem);

        _msgTimer = setTimeout(function () {
            ui.hideOverlay("communication-window");
        }, 5000);
    });

    jQuery("#communication-clearMessage").unbind("click").click(function () {
         jQuery("#communication-messageDisplay").empty();
    });

    event.on("OutsideMessageReceived", function (message) {
        var i = 0,
            recipients = [],
            recipientsStatus = {},
            messageItem;

        recipientsStatus.id = message.id;
        recipientsStatus.msg = message.msg;
        for (i in message.to) {
            recipientsStatus[message.to[i]] = true;
            recipients.push(message.to[i]);
        }
        for (i in message.cc) {
            recipientsStatus[message.cc[i]] = true;
            recipients.push(message.cc[i]);
        }
        for (i in message.bcc) {
            recipientsStatus[message.bcc[i]] = true;
            recipients.push(message.bcc[i]);
        }

        event.trigger("MessageSent", [recipientsStatus]);
        jQuery("#communication-messageIn td:nth-child(1)").text(message.body);
        messageItem = jQuery("#communication-messageIn").html();
        jQuery("#communication-messageDisplay").append(messageItem);
    });

    jQuery("#communication-ok").unbind("click").click(function () {
        ui.hideOverlay("communication-window");
        clearTimeout(_msgTimer);
    });

}

function _msgInitialize() {
    _msgEventInitialize();

    utils.forEach(_messageType, function (msgTypeText, msgType) {
        var typeNode = utils.createElement("option", {
                "innerText": msgTypeText,
                "value": msgType
            });

        jQuery("#communication-msgType").append(typeNode);
    });
}

function _showCall() {
    var callName = jQuery("#communication-callerName").val(),
        callNum = jQuery("#communication-callNum").val(),
        disCallName = jQuery(".communication-callContainer tr:first-child td"),
        disCallNum = jQuery(".communication-callContainer tr:nth-child(2) td");

    ui.showOverlay("communication-window");

    disCallName.text(callName ? callName : "Unknown Name");
    disCallNum.text(callNum ? callNum : "Unknown Number");

    jQuery("#communication-viewport").css("height", jQuery("#viewport-container").css("height"))
                                     .show("clip", 1000);
    jQuery(".communication-callContainer").show();
    jQuery(".communication-messageContainer").hide();
}

function _initRecord() {
    var callerName = jQuery("#communication-callerName").val(),
        callerNum = jQuery("#communication-callNum").val(),
        displayName = callerName ? callerName : "Unknown",
        displayNum = callerNum ? callerNum : "Unknown";

    _record = {};
    _record.serviceId = (new Date()).getTime() || 0;
    _record.callParticipants = [{
        id: displayName + ':' + displayNum,
        displayName: displayName,
        contactRef: null
    }];
    _record.forwardedFrom = null;
    _record.startTime = new Date();
    _record.recording = [];
    _record.direction = "dialed";
}

function _endCall(callEndReason) {
    _record.duration = _data.conversationStartTime ? ((new Date()) - _data.conversationStartTime) : 0;
    _data.conversationStartTime = null;

    _record.endReason = callEndReason;

    event.trigger("CallRecorded", [_record]);
    event.trigger("CallInProgress", [false]);

    _data.status = _status.IDLE;
    _record = {};

    _conversationSeconds = 0;
    window.clearInterval(_conversationTimer);

    ui.hideOverlay("communication-window");
}

function _callEventInitialize() {
    jQuery("#communication-callStart").toggle(
        function () {
            if (_data.isInException) {
                jQuery("#communication-callStart").removeData();
                return;
            }

            if (_data.status === _status.IDLE) {
                _data.status = _status.DIALED;
                _initRecord();
            } else {
                return;
            }

            _showCall();
            jQuery("#callSettings tr:last-child td").text("Caliing...");
            jQuery("#communication-callStart > span").text("End Call");
            jQuery("#callSettings input").attr("disabled", "disabled");
        },
        function () {
            _endCall("local");

            jQuery("#callSettings tr:last-child td").text("");
            jQuery("#communication-callStart > span").text("Call");
            jQuery(".communication-callContainer tr:nth-child(3)").show();
            jQuery(".communication-callContainer tr:last-child").hide();
            jQuery("#callSettings input").removeAttr("disabled");
        }
    );

    jQuery("#communication-ignore").unbind('click').click(function () {
        _endCall("rejected");

        jQuery("#callSettings tr:last-child td").text("");
        jQuery("#communication-callStart > span").text("Call");
        jQuery("#communication-callStart").removeData();
        jQuery("#callSettings input").removeAttr("disabled");
    });

    jQuery("#communication-answer").unbind('click').click(function () {
        _data.conversationStartTime = new Date();
        event.trigger("CallInProgress", [true]);
        _data.status = _status.INPROGRESS;

        _conversationTimer = setInterval(function () {
            var timeObj = new Date(1970, 0, 1),
                timeString;

            timeObj.setSeconds(_conversationSeconds);
            timeString = timeObj.toTimeString().substr(0, 8);
            jQuery("#callSettings tr:last-child td").text(timeString);
            _conversationSeconds = _conversationSeconds + 1;
        }, 1000);

        jQuery(".communication-callContainer tr:nth-child(3)").hide();
        jQuery(".communication-callContainer tr:last-child").show();
    });

    jQuery("#communication-end").unbind('click').click(function () {
        _endCall("remote");

        jQuery("#callSettings tr:last-child td").text("");
        jQuery("#communication-callStart > span").text("Call");
        jQuery("#communication-callStart").removeData();
        jQuery(".communication-callContainer tr:nth-child(3)").show();
        jQuery(".communication-callContainer tr:last-child").hide();
        jQuery("#callSettings input").removeAttr("disabled");
    });

    jQuery("#communication-callEndReason").unbind("change").change(function () {
        if (!jQuery("#communication-callEndReason").val()) {
            _data.isInException = false;
        } else {
            _data.isInException = true;
            if (_data.isInException && (_data.status !== _status.IDLE)) {
                _endCall(jQuery("#communication-callEndReason").val());
            }
        }

        jQuery("#callSettings tr:last-child td").text("");
        jQuery("#communication-callStart > span").text("Call");
        jQuery("#communication-callStart").removeData();
        jQuery(".communication-callContainer tr:nth-child(3)").show();
        jQuery(".communication-callContainer tr:last-child").hide();
        jQuery("#callSettings input").removeAttr("disabled");
    });
}

function _contactInitialize() {
    var data = db.retrieveObject(_CONTACT_KEY),
        displayName = null, number = null, index = 0;

    _contactNameArr = [];
    _contactNumArr = [];

    utils.forEach(data, function (addrBook) {
        utils.forEach(addrBook._contacts, function (contact) {
            if (contact.name && contact.name && contact.phoneNumbers && contact.phoneNumbers.length > 0) {
                displayName = contact.name.firstName + ' ' + contact.name.lastName;
                number = contact.phoneNumbers[0].number;
                _contactNameArr.push(displayName);
                _contactNumArr[displayName] = number;
                index++;
            }
        });
    });

    jQuery("#communication-callerName").autocomplete({
        source: _contactNameArr,
        select: function (event, ui) {
            jQuery("#communication-callNum").val(_contactNumArr[ui.item.value]);
        }
    });
    jQuery("#communication-senderName").autocomplete({
        source: _contactNameArr
    });
}

function _callInitialize() {
    _callEventInitialize();

    _contactInitialize();

    utils.forEach(_exception, function (value, key) {
        var typeNode = utils.createElement("option", {
                "innerText": value,
                "value": key
            });

        jQuery("#communication-callEndReason").append(typeNode);
    });
}

module.exports = {
    panel: {
        domId: "communication-container",
        collapsed: true,
        pane: "left",
        titleName: "Communications",
        display: true
    },
    initialize: function () {
        jQuery("#communication-select").tabs();
        _callInitialize();
        _msgInitialize();
    }
};

});
define('ripple/ui/plugins/geoDB', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    lbs = require('ripple/platform/tizen/2.0/lbs_utils'),
    _GEO_OBJECTS = "tizen1.0-geocode-objects",
    _geoList, _currentGeo, _saveID, _showGeoDetail;

function _getGeo() {
    var geoList = [],
        data = db.retrieveObject(_GEO_OBJECTS);

    utils.forEach(data, function (geo) {
        geoList.push(geo);
    });
    return geoList;
}

function _saveGeo() {
    db.saveObject(_GEO_OBJECTS, _geoList);
}

function GeoEntry(addr, coord) {
    var _self;
    _self = {
        address : addr || null,
        coordinate : coord || null
    };
    return _self;
}

function _updateGeoDBSelect() {
    var geoDBSelect = document.getElementById("geo-select"),
        geoNode, i;

    geoDBSelect.innerHTML = "";
    for (i = 0; i < _geoList.length; i++) {
        geoNode = utils.createElement("option", {
            "innerText": "(" + _geoList[i].coordinate.latitude + ", " + _geoList[i].coordinate.longitude + ")",
            "value": i
        });
        if (_currentGeo === Number(geoNode.value)) {
            geoNode.selected = true;
            _showGeoDetail(_geoList[_currentGeo].coordinate, _geoList[_currentGeo].address);
        }
        geoDBSelect.appendChild(geoNode);
    }
}

function _showGeoDetail(coord, addr) {
    jQuery("#geoDB-latitude").val(coord.latitude);
    jQuery("#geoDB-longitude").val(coord.longitude);
    jQuery("#geoDB-altitude").val(coord.altitude);
    jQuery("#geoDB-accuracy").val(coord.accuracy);
    jQuery("#geoDB-altitudeAccuracy").val(coord.altitudeAccuracy);
    jQuery("#geoDB-heading").val(coord.heading);
    jQuery("#geoDB-speed").val(coord.speed);

    jQuery("#geoDB-country").val(addr.country);
    jQuery("#geoDB-region").val(addr.region);
    jQuery("#geoDB-county").val(addr.county);
    jQuery("#geoDB-city").val(addr.city);
    jQuery("#geoDB-street").val(addr.street);
    jQuery("#geoDB-streetNumber").val(addr.streetNumber);
    jQuery("#geoDB-premises").val(addr.premises);
    jQuery("#geoDB-additionalInformation").val(addr.additionalInformation);
    jQuery("#geoDB-postalCode").val(addr.postalCode);
}

function _changeGeoData() {
    var id = Number(jQuery("#geo-select").val());
    _currentGeo = id;
    _showGeoDetail(_geoList[id].coordinate, _geoList[id].address);
}

function _triggerReadOnly(on) {
    if (on === true) {
        jQuery("#geoDB-table input").attr("readonly", "readonly");
        jQuery("#geoDB-add").show();
        jQuery("#geoDB-modify").show();
        jQuery("#geoDB-delete").show();
        jQuery("#geo-select").removeAttr("disabled");
        jQuery("#geoDB-save").hide();
        jQuery("#geoDB-cancel").hide();
    } else {
        jQuery("#geoDB-table input").removeAttr("readonly");
        jQuery("#geoDB-add").hide();
        jQuery("#geoDB-modify").hide();
        jQuery("#geoDB-delete").hide();
        jQuery("#geo-select").attr("disabled", "disabled");
        jQuery("#geoDB-save").show();
        jQuery("#geoDB-cancel").show();
    }
}

function _addGeoData() {
    _triggerReadOnly(false);
    jQuery("#geoDB-table input").val("");
    _saveID = _geoList.length;
    jQuery("#geo-select").val("");
}
function _modifyGeoData() {
    _triggerReadOnly(false);
    _saveID = _currentGeo;
}
function _deleteGeoData() {
    _geoList.splice(_currentGeo, 1);
    _saveGeo();
    _currentGeo = 0;
    _updateGeoDBSelect();
}
function _saveGeoData() {
    var entry;
    entry = new GeoEntry(new lbs.StructuredAddress({
        country: jQuery("#geoDB-country").val(),
        region: jQuery("#geoDB-region").val(),
        county: jQuery("#geoDB-county").val(),
        city: jQuery("#geoDB-city").val(),
        street: jQuery("#geoDB-street").val(),
        streetNumber: jQuery("#geoDB-streetNumber").val(),
        premises: jQuery("#geoDB-premises").val(),
        additionalInformation: jQuery("#geoDB-additionalInformation").val(),
        postalCode: jQuery("#geoDB-postalCode").val()
    }),
        new lbs.GeoCoordinates({
        latitude: parseFloat(jQuery("#geoDB-latitude").val()),
        longitude: parseFloat(jQuery("#geoDB-longitude").val()),
        altitude: parseFloat(jQuery("#geoDB-altitude").val()),
        accuracy: parseFloat(jQuery("#geoDB-accuracy").val()),
        altitudeAccuracy: parseFloat(jQuery("#geoDB-altitudeAccuracy").val()),
        heading: parseFloat(jQuery("#geoDB-heading").val()),
        speed: parseFloat(jQuery("#geoDB-speed").val())
    }));
    if (_saveID === _geoList.length)
        _geoList.push(entry);
    else
        _geoList[_saveID] = entry;
    
    _saveGeo();
    _currentGeo = _saveID;
    _updateGeoDBSelect();
    _triggerReadOnly(true);
}

function _cancelGeoData() {
    _triggerReadOnly(true);
    _updateGeoDBSelect();
}

module.exports = {
    panel: {
        domId: "geoDB-container",
        collapsed: true,
        pane: "right"
    },

    initialize: function () {
        _currentGeo = 0; // set _geoList[0] as default value
        _geoList = _getGeo();
        _updateGeoDBSelect();
        _triggerReadOnly(true);

        jQuery("#geo-select").bind("change", function () {
            _changeGeoData();
        });
        jQuery("#geoDB-add").bind("click", function () {
            _addGeoData();
        });
        jQuery("#geoDB-modify").bind("click", function () {
            _modifyGeoData();
        });
        jQuery("#geoDB-delete").bind("click", function () {
            _deleteGeoData();
        });
        jQuery("#geoDB-save").bind("click", function () {
            _saveGeoData();
        });
        jQuery("#geoDB-cancel").bind("click", function () {
            _cancelGeoData();
        });
    }
};

});
define('ripple/ui/plugins/call', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    _exception = {
        "unknown":           "Unknown",
        "network":           "Network",
        "unreachable":       "Unreachable",
        "no-answer":         "No Answer",
        "bad-number":        "Bad Number",
        "number-not-in-use": "Number Not In Use",
        "media":             "Media",
        "no-sim":            "No Sim Card",
        "account-down":      "Account Down",
        "credit-down":       "Credit Down",
        "barred":            "Barred",
        "network-busy":      "Network Busy",
        "network-down":      "Network Down"
    },
    _status = {
        IDLE:       0,
        DIALED:     1,
        PLACED:     2,
        INPROGRESS: 3,
    },
    _statusInfo = [
        "Waiting...;Waiting",                                   // IDLE
        "Calling... ;Incomming call from simulator",               // DIALED
        "Incomming call from ;Calling simulator",                // PLACED
        "In conversation with ;In conversation with simulator"   // INPROGRESS
    ],
    _data = {
        status: _status.IDLE,
        isInException: false,
        isAutoAccept: false,
        autoAcceptTimerId: null,
        conversationStartTime: null
    },
    _contactMap = {
        "861012345678": "Guest"
    },
    _CONTACT_KEY = "tizen1-contact",
    _RECORDING_KEY = "tizen1-call-recording",
    _RECORDING_PATH = "music/",
    _record = {},
    _conversationSeconds = 0,
    _conversationTimer,
    _callingEffectTimer;

function _initContacts() {
    var data = db.retrieveObject(_CONTACT_KEY),
        contactsSelect = document.getElementById("call-local-phone-number"),
        displayName = null, number = null, index = 0, i;
        
    contactsSelect.innerHTML = "";

    utils.forEach(data, function (addrBook) {
        utils.forEach(addrBook._contacts, function (contact) {
            if (contact.name && contact.name && contact.phoneNumbers &&
                contact.phoneNumbers.length > 0) {
                displayName = contact.name.firstName + ' ' + contact.name.lastName;
                number = contact.phoneNumbers[0].number;
                _contactMap[number] = displayName;

                contactsSelect.appendChild(utils.createElement("option", {
                    "innerText": displayName + ':' + number,
                    "value": index
                }));
                index++;
            }
        });
    });

    if (displayName === null && number === null) {
        for (i in _contactMap) {
            displayName = _contactMap[i];
            number = i;
            contactsSelect.appendChild(utils.createElement("option", {
                "innerText": displayName + ':' + number,
                "value": index
            }));
        }
    }
}

function _initEventWatchers() {
    event.on("DialerLaunched", function (remoteParty) {
        var localContact = document.getElementById("call-local-phone-number");

        if (_data.status !== _status.IDLE) {
            return;
        }

        localContact.appendChild(utils.createElement("option", {
            "innerText": remoteParty.displayName,
            "value": remoteParty.remoteParty,
            "selected": "selected"
        }));
        _localCall();
    });
}

function _initExceptionTypes() {
    utils.forEach(_exception, function (value, key) {
        document.getElementById("call-exception-type").appendChild(utils.createElement("option", {
            "innerText": value,
            "value": key
        }));
    });
}

function _initRecord() {
    var localPartString = jQuery("#call-local-phone-number option:selected").text() || "",
        localPartStringList = localPartString.split(":"),
        displayName;

    if (localPartStringList.length > 1) {
        displayName = localPartStringList[0];
    }
    else {
        displayName = localPartString;
    }

    _record = {};
    _record.serviceId = (new Date()).getTime() || 0;
    _record.callParticipants = [{
        id: localPartString + ':' + displayName,
        displayName: displayName,
        contactRef: null
    }];
    _record.forwardedFrom = null;
    _record.startTime = new Date();
    _record.recording = [];
}


function updateConvTime() {
    var timeObj = new Date(1970, 0, 1),
    timeString;

    timeObj.setSeconds(_conversationSeconds);
    timeString = timeObj.toTimeString().substr(0, 8);
    jQuery("#ConvTimeString").text(timeString);
    jQuery("#ConvTimeString2").text(timeString);
    _conversationSeconds = _conversationSeconds + 1;
}


function CallingEffect() {
    var color = jQuery("#callingString").css('color');
    if (color === "rgb(255, 255, 255)") {
        jQuery("#callingString").css('color', "black");
        jQuery("#callingString2").css('color', "black");
    }
    else {
        jQuery("#callingString").css('color', "white");
        jQuery("#callingString2").css('color', "white");
    }
}


function _transferStatus() {
    var statusStringList = _statusInfo[_data.status].split(";"),
        localPartString = jQuery("#call-local-phone-number option:selected").text() || "",
        localPartStringList = localPartString.split(":"),
        localNumber = localPartStringList[0],
        localName = _contactMap[localNumber] || localNumber;
    jQuery("#status-text").show();
    jQuery("#remote-status-text").show();
    jQuery("#call-status").show();
    jQuery("#remote-call-status").show();
    jQuery("#remotePartyName").html(localName);
    jQuery("#call-local-call").show();
    window.clearInterval(_callingEffectTimer);

    switch (_data.status) {
    case _status.DIALED:      // local call
        jQuery("#call-remote-text").html("Accept");
        jQuery("#end-remote-text").html("Reject");
        jQuery("#call-status").html("<span style='font-size: 22px;'>" + localName + "</span><br>" + 
                        "<span id='callingString' style='font-size: 14px;'>&nbsp;" + statusStringList[0] + 
                        "</span><br><br><br><button id='call-local-end-d' class='ui-corner-all' style='padding:2px;" +
                        " border-width:1px; background-color:red; color:white; font-size:14px; font-weight:bold; width:100%;'>End call</button>");
        jQuery("#call-local-end-d").bind("click", _localEnd);
        jQuery("#remote-call-status").html("<span style='font-size: 20px;'>Simulator Bot</span><br>" + 
                        "<span id='callingString2' style='font-size: 12px;'>&nbsp;Incoming call...</span>" +
                        "<br><br><br><button id='call-remote-decline-d' class='ui-corner-all' style='padding:2px;" +
                        " border-width:1px; background-color:red; color:white; font-size:14px; font-weight:bold; width:48%;'>Decline</button>&nbsp;&nbsp;" +
                        "<button id='call-remote-answer-d' class='ui-corner-all' style='padding:2px; border-width:1px; background-color:green; color:white; font-size:14px; font-weight:bold; width:48%;'>Answer</button>");
        jQuery("#call-remote-answer-d").bind("click", _remoteCall);
        jQuery("#call-remote-decline-d").bind("click", _remoteEnd);
        _callingEffectTimer = window.setInterval(CallingEffect, 800);
        break;
    case _status.PLACED:      // Remote Call
        jQuery("#call-local-text").html("Accept");
        jQuery("#end-local-text").html("Reject");
        jQuery("#call-status").html(statusStringList[0] + localName);
        jQuery("#remote-call-status").html(statusStringList[1]);
        jQuery("#remote-call-status").html("<span style='font-size: 22px;'>Simulator Bot</span><br>" + 
                        "<span id='callingString' style='font-size: 14px;'>&nbsp;Calling..." + 
                        "</span><br><br><br><button id='call-remote-end-d' class='ui-corner-all' style='padding:2px;" +
                        " border-width:1px; background-color:red; color:white; font-size:14px; font-weight:bold; width:100%;'>End call</button>");
        jQuery("#call-remote-end-d").bind("click", _remoteEnd);
        jQuery("#call-status").html("<span style='font-size: 22px;'>" + localName + "</span><br>" + 
                        "<span id='callingString2' style='font-size: 14px;'>&nbsp;Incoming call...</span>" +
                        "<br><br><br><button id='call-local-decline-d' class='ui-corner-all' style='padding:2px;" +
                        " border-width:1px; background-color:red; color:white; font-size:14px; font-weight:bold; width:48%;'>Decline</button>&nbsp;&nbsp;" +
                        "<button id='call-local-answer-d' class='ui-corner-all' style='padding:2px; border-width:1px;" +
                        " background-color:green; color:white; font-size:14px; font-weight:bold; width:48%;'>Answer</button>");
        jQuery("#call-local-answer-d").bind("click", _localCall);
        jQuery("#call-local-decline-d").bind("click", _localEnd);
        _callingEffectTimer = window.setInterval(CallingEffect, 800);
        break;
    case _status.INPROGRESS:
        jQuery("#call-status").html("<span style='font-size: 22px;'>" + localName + "</span><br>" + 
                        "<span id='ConvTimeString' style='font-size: 14px;'>" + "00:00:00" + 
                        "</span><br><br><br><button id='call-local-end-d-c' class='ui-corner-all' style='padding:2px;" +
                        " border-width:1px; background-color:red; color:white; font-size:14px; font-weight:bold; width:100%;'>End call</button>");
        jQuery("#remote-call-status").html("<span style='font-size: 22px;'>Simulator Robot</span><br>" + 
                        "<span id='ConvTimeString2' style='font-size: 14px;'>" + "00:00:00" + 
                        "</span><br><br><br><button id='call-remote-end-d-c' class='ui-corner-all' style='padding:2px;" +
                        " border-width:1px; background-color:red; color:white; font-size:14px; font-weight:bold; width:100%;'>End call</button>");
        jQuery("#call-local-end-d-c").bind("click", _localEnd);
        jQuery("#call-remote-end-d-c").bind("click", _remoteEnd);
        _conversationTimer = window.setInterval(updateConvTime, 1000);
        jQuery("#call-remote-text").html("Call");
        jQuery("#end-remote-text").html("End");
        jQuery("#call-local-text").html("Call");
        jQuery("#end-local-text").html("End");
        break;
    default:
        jQuery("#call-status").html(statusStringList[0]);
        jQuery("#call-status").html("default");
        jQuery("#remote-call-status").html(statusStringList[1]);
        jQuery("#remote-call-status").html("default");
        jQuery("#call-remote-text").html("Call");
        jQuery("#end-remote-text").html("End");
        jQuery("#call-local-text").html("Call");
        jQuery("#end-local-text").html("End");
        return;
    }
}

function _startCall() {
    _data.conversationStartTime = new Date();
    event.trigger("CallInProgress", [true]);
    _data.status = _status.INPROGRESS;
    //_transferStatus();
}

function _endCall(callEndReason) {
    if (_data.autoAcceptTimerId) {
        var path = _RECORDING_PATH + _record.serviceId + ".mp3";

        _record.recording.push(path);
        db.saveObject(_RECORDING_KEY, path);

        clearTimeout(_data.autoAcceptTimerId);
        _data.autoAcceptTimerId = null;
    }

    _record.duration = _data.conversationStartTime ? ((new Date()) - _data.conversationStartTime) : 0;
    _data.conversationStartTime = null;
    
    _record.endReason = callEndReason;

    if (_data.status === _status.PLACED) {
        _record.direction = "missed-new";
    }

    event.trigger("CallRecorded", [_record]);
    event.trigger("CallInProgress", [false]);

    _data.status = _status.IDLE;
    _transferStatus();
    _record = {};

    _conversationSeconds = 0;
    window.clearInterval(_conversationTimer);
    jQuery("#call-status").hide();
    jQuery("#remote-call-status").hide();

    jQuery("#status-text").hide();
    jQuery("#remote-status-text").hide();
}

function _localCall() {
    if (_data.isInException) {
        return;
    }

    switch (_data.status) {
    case _status.IDLE:    //local call
        _data.status = _status.DIALED;
        _initRecord();
        _record.direction = "dialed";
        break;
    case _status.PLACED:
        _data.status = _status.INPROGRESS;
        _record.direction = "received";
        if (_data.autoAcceptTimerId) {
            clearTimeout(_data.autoAcceptTimerId);
            _data.autoAcceptTimerId = null;
        }
        _startCall();
        break;
    default:
        return;
    }

    _transferStatus();

    if (_data.isInException) {
        _endCall(document.getElementById("call-exception-type").value);
    }
}

function _localEnd() {
    switch (_data.status) {
    case _status.DIALED:     // Local Cancel
    case _status.INPROGRESS: // Local End
        _endCall("local");
        break;
    case _status.PLACED:
        _record.direction = "missed-new";
        _endCall("local");
        break;
    default:
        return;
    }
}

function _remoteCall() {
    if (_data.isInException) {
        return;
    }

    switch (_data.status) {
    case _status.IDLE:      // Remote Call
        _data.status = _status.PLACED; 
        _initRecord();
        if (_data.isAutoAccept) {
            _data.autoAcceptTimerId = setTimeout(_localCall, 2000);
        }
        break;
    case _status.DIALED:    // Remote Answer
        _startCall();
        break;
    default:
        return;
    }

    _transferStatus();

    if (_data.isInException) {
        _endCall(document.getElementById("call-exception-type").value);
    }
}

function _remoteEnd() {
    switch (_data.status) {
    case _status.DIALED:     // Remote Reject
        _endCall("rejected");
        break;
    case _status.INPROGRESS: // Remote End
        _endCall("remote");
        break;
    case _status.PLACED:    // Remote Cancel
        _record.direction = "missed-new";
        _endCall("remote");
        break;
    default:
        return;
    }
}

function _leaveMessage() {
    if (!this.checked && _data.autoAcceptTimerId) {
        clearTimeout(_data.autoAcceptTimerId);
        _data.autoAcceptTimerId = null;
    }
    _data.isAutoAccept = this.checked;
}

function _exceptionStatus() {
    _data.isInException = this.checked;
    if (_data.isInException && (_data.status !== _status.IDLE)) {
        if (_data.status === _status.RECEIVED) {   // Remote Cancel
            _record.direction = "missed-new";
            _record.duration = 0;
        }
        _endCall(document.getElementById("call-exception-type").value);
    }
}


function _updateRemotePartyName() {
    jQuery("#remotePartyName").text(jQuery("#call-local-phone-number option:selected").text());
}


module.exports = {
    panel: {
        domId: "call-container",
        collapsed: true,
        pane: "left",
        titleName: "Call",
        display: true
    },
    initialize: function () {
        jQuery("#call-local-call").bind("click", _localCall);
        jQuery("#call-local-end").bind("click", _localEnd);
        jQuery("#call-remote-call").bind("click", _remoteCall);
        jQuery("#call-remote-end").bind("click", _remoteEnd);
        jQuery("#recording-status").bind("click", _leaveMessage);
        jQuery("#call-exception-status").bind("click", _exceptionStatus);
        jQuery("#call-exception-type").bind("click", null);

        _initEventWatchers();
        _initContacts();
        jQuery("#remotePartyName").text(jQuery("#call-local-phone-number option:selected").text());
        jQuery("#call-local-phone-number").bind("change", _updateRemotePartyName);
        _initExceptionTypes();
    }
};

});
define('ripple/ui/plugins/settings-menu', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    constants = require('ripple/constants'),
    platform = require('ripple/platform'),
    db = require('ripple/db'),
    _applicationStateId
    ;


function reload() {
    window.tinyHipposReload = true;
    location.reload();
}

function _showSettingMenu() {
    var contentTable = "",
    settings = [],
    _applicationState = [],
    _applicationStateTmp = [],
    i = 0;

    if ($("#settings-menu-popup").is(":visible")) {
        $("#settings-menu-popup").hide("slide", {direction: "up"}, "slow");
        $("#overlayBackground").hide("fade", "slow");
        return;
    }

    _applicationStateId = constants.COMMON.APPLICATION_STATE + platform.current().id;

    _applicationStateTmp = db.retrieveObject(_applicationStateId) || [];

    utils.forEach(_applicationStateTmp, function (obj) {
        if (obj.display)
            _applicationState.push(obj);
    });

    utils.forEach(_applicationStateTmp, function (obj) {
        if (!obj.display)
            _applicationState.push(obj);
    });

    $("#settings-menu-content-panel-table").remove();

    contentTable = '<table id="settings-menu-content-panel-table" class="settings-menu-content-table">';
    utils.forEach(_applicationState, function (obj) {
        var checked = obj.display ? 'checked="yes"':"";
        contentTable += '<tr><td><input name="panel-display-setting" type="checkbox" class="settings-menu-checkbox "' +
                        checked + '></input>' +
                        obj.titleName + '</td></tr>\n';
    });
    contentTable += "</table>";

    $("#settings-menu-container-div").append(contentTable);
    $("#settings-menu-popup").css("top", 50);
    $("#settings-menu-popup").css("left", $(window).width() - 340);

    $("#overlayBackground").css("width", $(window).width());
    $("#overlayBackground").css("height", $(window).height());
    $("#overlayBackground").show("fade", "slow");
    $("#settings-menu-popup").show("slide", {direction: "up"}, "slow");

    $("#settings-menu-save-btn").unbind('click');
    $("#settings-menu-save-btn").bind("click", function (event) {
        $("input[name='panel-display-setting']").each(function (i, a) {
            settings.push(a.checked);
        });

        utils.forEach(_applicationState, function (obj) {
            if (!settings[i])
                obj.collapsed = true;
            obj.display = settings[i];
            i++;
        }, this);
  
        db.saveObject(_applicationStateId, _applicationState);
        _applicationStateTmp = db.retrieveObject(_applicationStateId) || [];

        $("#settings-menu-popup").hide("slide", {direction: "up"}, "slow");
        $("#overlayBackground").hide("fade", "slow");
        setTimeout(reload, 500);
    });

    $(".settings-menu-content-table td").unbind('click');
    $(".settings-menu-content-table td").bind("click", function (event) {
        var checkbox;
        if (($(event.target).children().length === 0)) {
            return;
        } else {
            checkbox = $(event.target).children();
        }
        
        if (checkbox.is(':checked')) {
            checkbox.prop('checked', false);
        }
        else
            checkbox.prop('checked', true);
    });

    $("#settings-menu-close-btn").unbind('click');
    $("#settings-menu-close-btn").bind("click", function (event) {
        if ($("#settings-menu-popup").is(":visible")) {
            $("#settings-menu-popup").hide("slide", {direction: "up"}, "slow");
            $("#overlayBackground").hide("fade", "slow");
            return;
        }
    });

    $(window).bind('resize', function () {
        $("#settings-menu-popup").css("top", 50);
        $("#settings-menu-popup").css("left", $(window).width() - 340);
        $("#overlayBackground").css("width", $(window).width());
        $("#overlayBackground").css("height", $(window).height());
    });

    $("#panelSettingSelectAll").unbind('click');
    $("#panelSettingSelectAll").bind("click", function (event) {
        if ($("#panelSettingSelectAll").is(':checked')) {
            $("#select_unselect_text").text("Unselect All");
            $(".settings-menu-checkbox").prop('checked', true);
        }
        else {
            $("#select_unselect_text").text("Select All");
            $(".settings-menu-checkbox").prop('checked', false);
        }
    });
}

module.exports = {
    initialize: function () {
        $("#options-button-panels").bind("click", function (event) {
            _showSettingMenu();
        });
    }
};

});
define('ripple/ui/plugins/sensorSettings', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var constants = require('ripple/constants'),
    sensorSettings = require('ripple/sensorSettings'),
    utils = require('ripple/utils'),
    exception = require('ripple/exception'),
    platform = require('ripple/platform'),
    _CONST = {
        "CONTENT_CONTAINER_ID": "sensorsettings-content-container",
        "UKNOWN_CONTROL_MESSAGE": "Unknown sensor control type"
    },
    _contentContainer,
    _CONTAINER_ID = _CONST.CONTENT_CONTAINER_ID;

function _appendSettingNode(labelNode, inputNode, label) {
    var frag = document.createDocumentFragment(),
        rowNode = frag.appendChild(utils.createElement("tr")),
        tempTdNode;

    rowNode.appendChild(utils.createElement("td"))
           .appendChild(labelNode);

    tempTdNode = rowNode.appendChild(utils.createElement("td"));

    if (label) {
        tempTdNode.appendChild(label);
    }

    tempTdNode.appendChild(inputNode);

    return frag;
}

function _buildDOMNode(setting, settingType, key) {
    var settingsNode, tagName, jNode,
        fullKey = settingType + "." + key,
        savedSetting = sensorSettings.retrieve(fullKey),
        // TODO: move this into Utils (isSet method)
        currentSetting = (savedSetting || savedSetting === false || savedSetting === "" || savedSetting === 0) ? savedSetting : setting.control.value,
        domNode,
        domNodeLabel = null;

    switch (setting.control.type) {
    case "text":
    case "number":
    case "range":
    case "checkbox":
        tagName = "input";
        break;
    case "textarea":
        tagName = "textarea";
        break;
    case "select":
        tagName = "select";
        break;
    default:
        exception.raise(exception.types.Application, _CONST.UKNOWN_CONTROL_MESSAGE);
    }

    settingsNode = utils.createElement(tagName, setting.control.type === "select" ? null : setting.control);

    // TODO: this should really be part of utils.createControl? add element of type "range" with label?
    if (setting.control.type === "range") {
        domNodeLabel = utils.createElement("label", {
            "class": constants.UI.LEFT_RANGE_LABEL_CLASS
        });
    }

    domNode = _appendSettingNode(utils.createElement("span", {"innerText": setting.name, "class": constants.UI.TEXT_LABEL_CLASS}), settingsNode, domNodeLabel);

    jNode = jQuery(settingsNode);
    jNode.addClass(constants.UI.JQUERY_UI_INPUT_CLASSES);

    switch (setting.control.type) {
    case "checkbox":
        jNode.bind("click", function () {
            var checked = this.checked ? true : false;
            sensorSettings.persist(fullKey, checked);
            if (typeof setting.callback === "function") {
                setting.callback(checked);
            }
        });

        if (currentSetting === true) {
            jNode.attr("checked", "checked");
        }

        break;

    case "text":
    case "textarea":
    case "number":
        jNode.val(currentSetting);
        utils.bindAutoSaveEvent(jNode, function () {
            sensorSettings.persist(fullKey, jNode.val());
            if (typeof setting.callback === "function") {
                setting.callback(jNode.val());
            }
        });
        break;

    case "select":
    case "range":
        if (setting.control.type === "select") {
            utils.forEach(setting.options,  function (value, option) {
                jNode.append(utils.createElement("option", {
                    "value": option,
                    "innerText": value
                }));
            });
        }
        else {
            if (domNodeLabel) {
                domNodeLabel.innerText = currentSetting;
            }
        }

        jNode.val(currentSetting)
             .bind("change", function () {
                if (setting.control.type === "range" && domNodeLabel) {
                    domNodeLabel.innerText = jQuery(this).val();
                }
                sensorSettings.persist(fullKey, jQuery(this).val());

                if (typeof setting.callback === "function") {
                    setting.callback(jQuery(this).val());
                }
            }
        );
    }

    // TODO: Brent, do in DeviceSettings on load instead?
    if (currentSetting !== setting.control.value) {
        sensorSettings.register(fullKey, currentSetting);
    }

    return domNode;
}

// goes through current platforms sensor settings
// adds nodes to panel and binds respective events
// talks to SensorSettings for persistence
module.exports = {
    panel: {
        domId: "sensors-panel-container",
        collapsed: true,
        pane: "right",
        titleName: "Sensors",
        display: true
    },
    initialize: function () {
        var settings;

        _contentContainer = document.getElementById(_CONTAINER_ID);

        settings = platform.current().sensor;

        utils.forEach(settings, function (settingSection, settingType) {

            var currentTableNode, flag = false;
            
            utils.forEach(settingSection, function (setting, key) {
                if (typeof setting === "object") {
                    flag = true;
                    return;
                }
            });

            if (flag) {
                _contentContainer.appendChild(utils.createElement("h3", { "innerText": settingType }));
            }

            currentTableNode = utils.createElement("table", {
                "class": constants.UI.PANEL_TABLE_CLASS
            });

            _contentContainer.appendChild(currentTableNode);

            utils.forEach(settingSection, function (setting, key) {
                if (typeof setting === "object") {
                    currentTableNode.appendChild(_buildDOMNode(setting, settingType, key));
                }

            });
        });
    }
};

});
define('ripple/ui/plugins/exec-dialog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function exec(func) {
    return function () {
        var val = $("#exec-response").val();

        //TODO: handle multiple args
        func.apply(null, val ? [JSON.parse(val)] : []);
        $("#exec-dialog").dialog("close");
    };
}

module.exports = {
    initialize: function () {
        $("#exec-dialog").dialog({
            autoOpen: false,
            modal: true,
            title: "I Haz Cheeseburger?!?!",
            width: 500,
            position: 'center'
        }).hide();

        $("#exec-success").button();
        $("#exec-fail").button();
    },

    show: function (service, action, success, fail) {
        console.log(service);
        console.log(action);
        $("#exec-service").text(service);
        $("#exec-action").text(action);
        $("#exec-dialog").dialog("open");
        $("#exec-success").unbind().bind('click', exec(success));
        $("#exec-fail").unbind().bind('click', exec(fail));
    }
};

});
define('ripple/ui/plugins/push', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    PUSH_OPTIONS = constants.PUSH.OPTIONS;

function _updatePushPanel(ports) {
    var portsSelect = document.getElementById("port-select"),
        currentPort = portsSelect.value;

    portsSelect.innerHTML = "";

    ports.forEach(function (port) {
        portsSelect.appendChild(utils.createElement("option", {
            innerText: port,
            value: port,
            selected: currentPort === port
        }));
    });
}

module.exports = {
    panel: {
        domId: "push-container",
        collapsed: true,
        pane: "left"
    },
    initialize: function () {
        event.on("PushListenersChanged", function (listeners) {
            _updatePushPanel(listeners);
            jQuery("#port-select").effect("highlight", {color: "#62B4C8"}, 1000);
        });

        _updatePushPanel([]);

        document.getElementById("push-send")
            .addEventListener("click", function () {
                var port = document.getElementById("port-select").value,
                    text = document.getElementById(PUSH_OPTIONS.PAYLOAD).value,
                    pushData = {
                        headerField: ["21f39092"],
                        requestURI: "/",
                        source: "ripple",
                        isChannelEncrypted: false,
                        payload: text
                    };

                event.trigger("Push", [pushData, port], true);
            }, false);

        utils.bindAutoSaveEvent(jQuery("#" + PUSH_OPTIONS.PAYLOAD), function () {
            db.save(PUSH_OPTIONS.PAYLOAD, document.getElementById(PUSH_OPTIONS.PAYLOAD).value);
        });

        document.getElementById(PUSH_OPTIONS.PAYLOAD).value = db.retrieve(PUSH_OPTIONS.PAYLOAD) || "My payload data";
    }
};

});
define('ripple/ui/plugins/application', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    utils = require('ripple/utils'),
    db = require('ripple/db'),
    _data = {
        DB_APPLICATION_KEY : "tizen1-db-application",
        programs : []
    },
    _cleanInputs,
    _apps;

function _get() {
    _apps = [
        {
        appId : "ID001",
        appInfo : {id : "ID001", name : "Tizen App1", iconPath : "app1.png", version : "1.0", show : true},
        },
        {
        appId : "ID002",
        appInfo : {id : "ID002", name : "Tizen App2", iconPath : "app2.png", version : "2.0", show : true},
        },
    ];
    _data.programs = db.retrieveObject(_data.DB_APPLICATION_KEY) || _apps;
    _save();
}

function _save() {
    db.saveObject(_data.DB_APPLICATION_KEY, _data.programs);
}

function _loadPrograms() {
    var installed = document.getElementById("application-installed"), node, i;
    installed.innerHTML = "";
    for (i in _data.programs) {
        node = utils.createElement("option", {
            "innerText": _data.programs[i].appInfo.name,
            "value": _data.programs[i].appId
        });
        installed.appendChild(node);
    }
    _cleanInputs();
}

function _displayInfo(text) {
    var html = "<b>" + text + "</b>";
    document.getElementById("application-error").innerHTML = html;
}

function _programChanged(status, param) {
    event.trigger("programChanged", [status, param]);
}

function _cleanInputs() {
    document.getElementById("application-operation").value = "";
    document.getElementById("application-uri").value = "";
    document.getElementById("application-mime").value = "";
    document.getElementById("application-id").value = "";
    document.getElementById("application-name").value = "";
    document.getElementById("application-iconPath").value = "";
    document.getElementById("application-version").value = "";
    document.getElementsByName("application-show")[0].checked = false;
    document.getElementsByName("application-show")[1].checked = false;
}

function _install() {
    var operation, uri, mime, id, name, iconPath, version, show, i, app;

    operation = document.getElementById("application-operation").value;
    uri       = document.getElementById("application-uri").value;
    mime      = document.getElementById("application-mime").value;
    id        = document.getElementById("application-id").value;
    name      = document.getElementById("application-name").value;
    iconPath  = document.getElementById("application-iconPath").value;
    version   = document.getElementById("application-version").value;
    show      = document.getElementsByName("application-show")[0].checked;

    if (_data.programs.length !== 0) {
        for (i in _data.programs) {
            if (id === _data.programs[i].appId) {
                return;
            }
        }
    }
    app = {
        appId : id,
        appInfo : {id : id, name : name, iconPath : iconPath, version : version, show : show},
        appServices : [{operation : operation, uri : uri, mime : mime}]
    };
    _data.programs.push(app);
    _save();
    _programChanged("installed", app.appInfo);
    _loadPrograms();
}

function _update() {
    var i, id, name, version, show, iconPath, operation, uri, mime, length;

    length   = _data.programs.length;
    id       = document.getElementById("application-id").value;
    name     = document.getElementById("application-name").value;
    iconPath = document.getElementById("application-iconPath").value;
    version  = document.getElementById("application-version").value;
    show     = document.getElementsByName("application-show")[0].checked;
    operation = document.getElementById("application-operation").value;
    uri       = document.getElementById("application-uri").value;
    mime      = document.getElementById("application-mime").value;

    if (length === 0)
        return;

    for (i in _data.programs) {
        if (_data.programs[i].appId === id) {
            _data.programs[i].appInfo = {id : id, name : name, iconPath : iconPath, version : version, show : show};
            _data.programs[i].appServices = [{operation : operation, uri : uri, mime : mime}];
            _save();
            _programChanged("updated", _data.programs[i].appInfo);
            _loadPrograms();
            break;
        }
    }
}

function _uninstall() {
    var i, id = null;
    id = document.getElementById("application-id").value;
    if (id) {
        for (i in _data.programs) {
            if (_data.programs[i].appId === id) {
                _data.programs.splice(i, 1);
                _save();
                _programChanged("uninstalled", id);
                _loadPrograms();
            }
        }
    }
}

function _showAppDetail(id) {
    var i;
    for (i in _data.programs) {
        if (id === _data.programs[i].appId) {
            jQuery("#application-id").val(_data.programs[i].appInfo.id);
            jQuery("#application-name").val(_data.programs[i].appInfo.name);
            jQuery("#application-iconPath").val(_data.programs[i].appInfo.iconPath);
            jQuery("#application-version").val(_data.programs[i].appInfo.version);
            if (_data.programs[i].appInfo.show) {
                document.getElementsByName("application-show")[0].checked = true;
                document.getElementsByName("application-show")[1].checked = false;
            } else {
                document.getElementsByName("application-show")[0].checked = false;
                document.getElementsByName("application-show")[1].checked = true;
            }
            jQuery("#application-operation").val(_data.programs[i].appServices[0].operation);
            jQuery("#application-uri").val(_data.programs[i].appServices[0].uri);
            jQuery("#application-mime").val(_data.programs[i].appServices[0].mime);
        }
    }
}

function _changeAppData() {
    var id = jQuery("#application-installed").val();
    _showAppDetail(id);
}

event.on("appServiceReplied", function (data) {
    _displayInfo("The application has been launched successfully");
});

event.on("appsInit", function (data) {
    data.applications = _data.programs;
});

module.exports = {
    initialize: function () {
        _get();
        _loadPrograms();

        document.getElementById("application-install").addEventListener("click", _install, false);
        document.getElementById("application-update").addEventListener("click", _update, false);
        document.getElementById("application-uninstall").addEventListener("click", _uninstall, false);
        jQuery("#application-installed").bind("focus", function () {
            _changeAppData();
        });
        jQuery("#application-installed").bind("change", function () {
            _changeAppData();
        });
    }
};

});
define('ripple/ui/plugins/videoPlayer', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event');

module.exports = {
    initialize: function () {
        var videoObj,
            videoProgress = document.getElementById(constants.COMMON.MULTIMEDIA_VIDEO_PROGRESS_ID);

        event.on("MultimediaAppVideoPlayerCreated", function (videoDOMObj) {
            videoObj = videoDOMObj;

            videoObj.addEventListener("timeupdate", function () {
                var s = parseInt(videoObj.currentTime % 60, 10),
                    m = parseInt((videoObj.currentTime / 60) % 60, 10);

                videoProgress.innerText = ((m > 9) ? m  : "0" + m) + ':' + ((s > 9) ? s  : "0" + s);
            }, false);
        });

        event.on("MultimediaVolumeChanged", function (volume) {
            if (videoObj) {
                videoObj.volume = parseFloat(volume / 10);
            }
        });

        event.on("MultimediaVideoStateChanged", function (state) {
            document.getElementById(constants.COMMON.MULTIMEDIA_VIDEO_STATE_FIELD_ID).innerText = state;
            document.getElementById(constants.COMMON.MULTIMEDIA_VIDEO_FILE_FIELD_ID).innerText = videoObj.getAttribute("src");
        });
    }
};

});
define('ripple/ui/plugins/invoke', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    event = require('ripple/event');

module.exports = {
    panel: {
        domId: "invoke-container",
        collapsed: true,
        pane: "left"
    },
    initialize: function () {
        document.getElementById("invoke-send")
            .addEventListener("click", function () {
                var invokeInfo = {};

                invokeInfo.uri = document.getElementById("invoke-uri-text").value;
                invokeInfo.source = document.getElementById("invoke-source-text").value;
                invokeInfo.target = document.getElementById("invoke-target-text").value;
                invokeInfo.action = document.getElementById("invoke-action-text").value;
                invokeInfo.type = document.getElementById("invoke-mime-type-text").value;
                invokeInfo.extension = document.getElementById("invoke-extension-text").value;
                invokeInfo.data = document.getElementById("invoke-data-text").value;
                if (invokeInfo.data) {
                    invokeInfo.data = window.btoa(invokeInfo.data);
                }

                event.trigger("AppInvoke", [invokeInfo]);
            }, false);
    }
};

});
define('ripple/ui/plugins/touchEvent', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var event = require('ripple/event'),
    db = require('ripple/db'),
    constants = require('ripple/constants'),
    colors  = ["red", "green", "magenta", "blue", "yellow"],
    Point,
    intervalId,
    moveEvents  = {},
    currentIndex = 0,
    enlargeRatio = 4;

function _exec(operation) {
    var canvas = document.getElementById(constants.TOUCHEVENT.CANVAS),
        cxt = canvas.getContext("2d"),
        altKey = document.getElementById(constants.TOUCHEVENT.ALTKEY),
        metaKey = document.getElementById(constants.TOUCHEVENT.METAKEY),
        ctrlKey = document.getElementById(constants.TOUCHEVENT.CTRLKEY),
        shiftKey = document.getElementById(constants.TOUCHEVENT.SHIFTKEY),
        key, eventType;

    if (operation === "start") {
        altKey.disabled = 'disabled';
        metaKey.disabled = 'disabled';
        ctrlKey.disabled = 'disabled';
        shiftKey.disabled = 'disabled';
        clearInterval(intervalId);
        currentIndex = 0;
        eventType = "touchEvent";
    } else if (operation === "cancel") {
        altKey.disabled = '';
        metaKey.disabled = '';
        ctrlKey.disabled = '';
        shiftKey.disabled = '';
        altKey.checked = false;
        metaKey.checked = false;
        ctrlKey.checked = false;
        shiftKey.checked = false;
        cxt.clearRect(0, 0, canvas.width, canvas.height);
        moveEvents = {};
        eventType = "touchCancel";
    }

    event.trigger(eventType, [{
        data : moveEvents,
        keys : [altKey.checked, metaKey.checked, ctrlKey.checked, shiftKey.checked]
    }]);
}

Point = function (x, y, color, isDragging) {
    var _self = {};

    _self.x = x;
    _self.y = y;
    _self.color = color;
    _self.isDragging = isDragging;

    return _self;
};

module.exports = {
    panel: {
        domId: "touchEvent-container",
        collapsed: true,
        pane: "left",
        titleName: "Touch Event",
        display: true
    },

    initialize: function () {
        var deviceInfo = require('ripple/devices').getCurrentDevice(),
            canvas = document.getElementById(constants.TOUCHEVENT.CANVAS),
            button = document.getElementById(constants.TOUCHEVENT.OPTION),
            cxt = canvas.getContext("2d"),
            points = [],
            paint = false,
            currentPoint = {};

        function drawPoints() {
            var key, index, points = [], point;

            for (key in moveEvents) {
                points = moveEvents[key];
                cxt.fillStyle = colors[key];

                for (index = 0; index < points.length; index++) {
                    point = points[index];
                    cxt.beginPath();
                    cxt.arc(point.offsetX, point.offsetY, 5, 0, 2 * Math.PI, 1);
                    cxt.fill();
                }
            }
        }

        function endDraw(event) {
            if (paint) {
                paint = false;
                clearInterval(intervalId);
                moveEvents[currentIndex].push(event);
                drawPoints();

                currentIndex++;
                if (currentIndex === 5)
                    currentIndex = 0;
            }
        }

        canvas.addEventListener("mousedown", function (event) {
            if (button.value === "Touch Cancel") {
                button.value = "Touch Start";
                _exec("cancel");
            }
            moveEvents[currentIndex] = [];
            currentPoint = event;
            moveEvents[currentIndex].push(event);
            paint = true;
            drawPoints();
            intervalId = setInterval(function () {
                moveEvents[currentIndex].push(currentPoint);
            }, 100);
        });

        canvas.addEventListener("mousemove", function (event) {
            if (paint) {
                currentPoint = event;
                drawPoints();
            }
        });

        canvas.addEventListener("mouseup", endDraw);
        canvas.addEventListener("mouseout", endDraw);
        canvas.addEventListener("mouseleave", endDraw);

        document.getElementById(constants.TOUCHEVENT.OPTION).addEventListener("click", function () {
            if (!moveEvents[0])
                return;

            if (this.value === "Touch Start") {
                this.value = "Touch Cancel";
                _exec("start");
            } else if (this.value === "Touch Cancel") {
                this.value = "Touch Start";
                _exec("cancel");
            }
        }, false);

        canvas.width = deviceInfo.screen.width / enlargeRatio;
        canvas.height = deviceInfo.screen.height / enlargeRatio;
    }
};

});
define('ripple/ui/plugins/tooltips', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Class: UI.Tooltips
// Purpose: build tooltips for UI
// See here for Tooltip Options
// http://jquery.bassistance.de/tooltip/demo/
var utils = require('ripple/utils'),
    tooltip = require('ripple/ui/plugins/tooltip'),
    constants = require('ripple/constants'),
    db = require('ripple/db'),
    utils = require('ripple/utils');

function _updateButtonText() {
    document.querySelector("#settings-toggletooltips > span")
            .innerHTML = "Turn " + (tooltip.isOff() ? "On" : "Off");
}

module.exports = {
    initialize: function () {
        var saved = db.retrieve(constants.SETTINGS.TOOLTIPS_KEY);

        // blarg, tooltips are always enabled so if its saved to false disable it
        if (!tooltip.isOff() && (saved === "false" || saved === false)) {
            tooltip.toggle();
        }

        _updateButtonText();

        jQuery(constants.SETTINGS.TOOLTIPS_TOGGLE_DIV).click(function () {
            db.save(constants.SETTINGS.TOOLTIPS_KEY, !tooltip.toggle());
            _updateButtonText();
        });
    }
};

});
define('ripple/ui/plugins/camera', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var ui = require('ripple/ui'),
    event = require('ripple/event'),
    video = document.getElementById('camera-video'),
    upload = document.getElementById('picture-upload'),
    select = document.getElementById('select-file'),
    take = document.getElementById('take-file'),
    pic = document.getElementById("camera-image");


select.addEventListener('click', function () {
    upload.click();
});

upload.addEventListener('change', function () {
    pic.src = window.webkitURL.createObjectURL(upload.files[0]);
    take.style.display = "inline";
});

take.addEventListener('click', function () {
    console.log("captured-image: " + pic.src);
    event.trigger('captured-image', [pic.src, upload.files[0]]);
    module.exports.hide();
});

module.exports = {
    show: function () {
        ui.showOverlay("camera-window");
        if (pic.src) {
            take.style.display = "inline";
        }
        else {
            take.style.display = "none";
        }
    },
    hide: function () {
        ui.hideOverlay("camera-window");
    }
};

});
define('ripple/ui/plugins/layout', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    db = require('ripple/db'),
    resizer = require('ripple/resizer'),
    devices = require('ripple/devices'),
    event = require('ripple/event');

function _initializeLayout(prev, baton) {
    var layout = db.retrieve("layout"),
        layoutLandscape = document.getElementById(constants.COMMON.ORIENTATION_SELECT_LANDSCAPE_ID),
        layoutPortrait = document.getElementById(constants.COMMON.ORIENTATION_SELECT_PORTRAIT_ID),
        currentDevice = devices.getCurrentDevice(),
        defaultOrientation =  currentDevice ? currentDevice.defaultOrientation : null,
        layoutTypeChanged = false;

    jQuery("#" + constants.COMMON.ORIENTATION_SELECT_LANDSCAPE_ID).bind("click", function () {
        resizer.changeLayoutType("landscape");
        event.trigger("LayoutChanged", ["landscape"], true);
        layoutLandscape.setAttribute("class", "layout-selected");
        layoutPortrait.setAttribute("class", "layout-not-selected");
    });

    jQuery("#" + constants.COMMON.ORIENTATION_SELECT_PORTRAIT_ID).bind("click", function () {
        resizer.changeLayoutType("portrait");
        event.trigger("LayoutChanged", ["portrait"], true);
        layoutLandscape.setAttribute("class", "layout-not-selected");
        layoutPortrait.setAttribute("class", "layout-selected");
    });

    jQuery("#" + constants.COMMON.MENU_BUTTON).bind("click", function () {
        event.trigger("HardwareKey", [1]);
    });

    jQuery("#" + constants.COMMON.BACK_BUTTON).bind("click", function () {
        event.trigger("HardwareKey", [0]);
    });

    if (!layout) {
        layout = defaultOrientation || "portrait";
        layoutTypeChanged = true;
        resizer.changeLayoutType(layout);
    }

    //Hide the orientation buttons that we don't need for this device
    if (!currentDevice.viewPort.landscape) {
        layoutLandscape.setAttribute("style", "display:none");
    }

    if (!currentDevice.viewPort.portrait) {
        layoutPortrait.setAttribute("style", "display:none");
    }

    if (layout && layout === "portrait") {
        layoutLandscape.setAttribute("class", "layout-not-selected");
        layoutPortrait.setAttribute("class", "layout-selected");
    }
    else if (layout && layout === "landscape") {
        layoutLandscape.setAttribute("class", "layout-selected");
        layoutPortrait.setAttribute("class", "layout-not-selected");
    }

    if (!layoutTypeChanged) {
        resizer.resize(currentDevice);
    }
}

module.exports = {
    initialize: _initializeLayout
};

});
define('ripple/ui/plugins/build', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var tooltip = require('ripple/ui/plugins/tooltip'),
    settings = require('ripple/ui/plugins/settings-dialog'),
    bus = require('ripple/bus');

function handleBuild() {
    var node = $(this),
        action = node.attr('id').split("-")[2];

    if (node.hasClass("not-ready")) {
        return;
    }

    if (!settings.can(action)) {
        settings.show(action);
    }
    else {
        settings.perform(action);
    }
}

function areServicesRunning(success, fail) {
    bus.ajax(
        "GET",
        "http://127.0.0.1:9910/ripple/about",
        null,
        function () {
            success();
        },
        function (error) {
            fail();
        }
    );
}

function manageServices(action, callBack) {
    bus.send("services", action, function () {
        if (typeof callBack === "function") {
            callBack();
        }
    });
}

module.exports = {
    panel: {
        domId: "build-container",
        collapsed: true,
        pane: "right"
    },

    initialize: function () {
        $("#options-menu-build").click(handleBuild);
        $("#options-menu-sign").click(handleBuild);
        $("#options-menu-launch").click(handleBuild);

        $('#options-menu-start-service').click(function () {
            manageServices("start", function (result) {
                $('#options-menu-services-stop').show();
                $('#options-menu-services-start').hide();
            });
        });

        $('#options-menu-stop-service').click(function () {
            manageServices("stop", function (result) {
                $('#options-menu-services-stop').hide();
                $('#options-menu-services-start').show();
            });
        });

        $("#options-menu-settings").click(function () {
            settings.show(); 
        });

        if (settings.value("remoteInspector")) {
            $("#options-menu-build-warning").show();
            tooltip.create("#options-menu-build-warning", "Remote Web Inspector should be disabled when packaging for App World release");
        }

        areServicesRunning(
            function () {
                $('#options-menu-services-stop').show();
                $('#options-menu-services-start').hide();
            }, 
            function () {
                $('#options-menu-services-stop').hide();
                $('#options-menu-services-start').show();
            }
        );
    }
};

});
define('ripple/ui/plugins/download', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    event = require('ripple/event'),
    utils = require('ripple/utils'),
    _data = {
        DB_DOWNLOAD_KEY : "tizen1-db-download",
        resources : []
    },
    _cleanInputs, _loadResources, intervalId,
    _downloads;

function _get() {
    _downloads = [
        {id: "", url : "http://tizen.org/small_file.zip", size : "5", speed : "1.0", estimatedTime : "5"},
        {id: "", url : "http://tizen.org/big_file.zip", size : "20", speed : "1.0", estimatedTime : "20"},
    ];
    _data.resources = db.retrieveObject(_data.DB_DOWNLOAD_KEY) || _downloads;
    if (db.retrieveObject(_data.DB_DOWNLOAD_KEY) && db.retrieveObject(_data.DB_DOWNLOAD_KEY).length === 0) {
        _data.resources = _downloads;
    } else {
        _data.resources = db.retrieveObject(_data.DB_DOWNLOAD_KEY) || _downloads;
    }
    _save();
}

function _save() {
    db.saveObject(_data.DB_DOWNLOAD_KEY, _data.resources);
    event.trigger('downloadResourceChanged');
}

function checkURL(url) {
    var rg = new RegExp("((^http)|(^https)|(^ftp)):\/\/()+");
    return rg.test(url);
}

function loadResources() {
    var installed = document.getElementById("download-resource"), node, i;
    installed.innerHTML = "";
    for (i in _data.resources) {
        node = utils.createElement("option", {
            "innerText": _data.resources[i].url,
            "value": _data.resources[i].id
        });
        installed.appendChild(node);
    }
    _cleanInputs();
}

function _displayInfo(text) {
    var info = document.getElementById("download-error");
    info.innerHTML = text;
    if (intervalId) {
        clearTimeout(intervalId);
    }
    intervalId = setTimeout(clearDisplayInfo, 5000);
}

function clearDisplayInfo() {
    document.getElementById('download-error').innerHTML = '';
}

function _cleanInputs() {
    document.getElementById("download-url").value = "";
    document.getElementById("download-size").value = "";
    document.getElementById("download-speed").value = "";
    document.getElementById("download-time").innerText = "0";
}

function checkProperties(optionType, url, size, speed, time) {
    var back = true;
    if (url === "" || size === "" ||  speed === "" || time === "") {
        _displayInfo(optionType + " failed, empty input.");
        back = false;
    }
    if (!checkURL(url)) {
        _displayInfo(optionType + " failed, 'URL' is invalid.");
        back = false;
    }
    if (size <= 0 ||  speed <= 0) {
        _displayInfo(optionType + " failed, invalid input.");
        back = false;
    }
    return back;
}

function showUpdateNotification() {
    var url     = document.getElementById("download-url").value,
        size    = document.getElementById("download-size").value,
        speed   = document.getElementById("download-speed").value,
        isValid = true;
    if (url === "" || size === "" ||  speed === "" || !checkURL(url) || size <= 0 ||  speed <= 0) {
        isValid = false;
    }
    if (isValid) {
        _displayInfo("Resource changed, please Add or Update the content.");
    }
}

function _adding() {
    var id, time, url, size, speed, object, i, isValid;
    url     = document.getElementById("download-url").value;
    size    = document.getElementById("download-size").value;
    speed   = document.getElementById("download-speed").value;
    time    = size / speed;
    id      = Math.uuid(null, 16);

    isValid = checkProperties("Add", url, size, speed, time);
    if (!isValid)
        return;
    if (_data.resources.length !== 0) {
        for (i in _data.resources) {
            if (url === _data.resources[i].url) {
                _displayInfo("Add failed, the download resource is already existed.");
                return;
            }
        }
    }
    document.getElementById("download-time").innerText = Math.round(time * 100) / 100;
    object = {'id': id, 'url': url, 'size': size, 'speed': speed, 'estimatedTime': time};
    _data.resources.push(object);
    _save();
    loadResources();
}

function _update() {
    var id, time, url, size, speed, i, isExist = false, isValid;

    id    = document.getElementById("download-resource").value;
    url   = document.getElementById("download-url").value;
    size  = document.getElementById("download-size").value;
    speed = document.getElementById("download-speed").value;
    time  = size / speed;

    if (_data.resources.length === 0) {
        _displayInfo("Update failed, there is no download resource now.");
        return;
    }
    isValid = checkProperties("Update", url, size, speed, time);
    if (!isValid)
        return;
    for (i in _data.resources) {
        if (_data.resources[i].url === url) {
            isExist = true;
            _data.resources[i] = {id: id, url : url, size : size, speed : speed, estimatedTime: time};
            loadResources();
            _save();
            break;
        }
    }
    if (!isExist)
        _displayInfo("Update failed, the download resource doesn't exist.");
}

function _delete() {
    var i, id;
    id = document.getElementById("download-resource").value;
    if (id) {
        for (i in _data.resources) {
            if (_data.resources[i].id === id) {
                _data.resources.splice(i, 1);
                _save();
                loadResources();
            }
        }
    }
}

function _showAppDetail(id) {
    var i;
    for (i in _data.resources) {
        if (id === _data.resources[i].id) {
            document.getElementById("download-time").innerText = Math.round(_data.resources[i].estimatedTime * 100) / 100;
            jQuery("#download-url").val(_data.resources[i].url);
            jQuery("#download-size").val(_data.resources[i].size);
            jQuery("#download-speed").val(_data.resources[i].speed);
        }
    }
}

function _changeAppData() {
    var id = jQuery("#download-resource").val();
    _showAppDetail(id);
}
function changeValue() {
    var size  = document.getElementById("download-size").value,
        speed = document.getElementById("download-speed").value;
    if (size > 0 && speed > 0) {
        document.getElementById("download-time").innerText = Math.round(size / speed * 100) / 100;
    } else {
        document.getElementById("download-time").innerText  = "";
    }
}
function checkInputValue(input) {
    if (input.value === "" || input.value <= 0) {
        input.style['border-color'] = 'red';
        _displayInfo("Invalided value.");
    } else {
        if (input.style['border-color']) {
            input.style.removeProperty('border-color');
        }
        changeValue();
        //showUpdateNotification();
    }
}
module.exports = {
    panel: {
        domId: "download-container",
        collapsed: true,
        pane: "left",
        titleName: "Download",
        display: true
    },
    initialize: function () {
        _get();
        loadResources();

        document.getElementById("download-add").addEventListener("click", _adding, false);
        document.getElementById("download-update").addEventListener("click", _update, false);
        document.getElementById("download-delete").addEventListener("click", _delete, false);

        jQuery("#download-resource").bind("focus change", function () {
            var url = document.getElementById("download-url"),
                size = document.getElementById("download-size"),
                speed = document.getElementById("download-speed");
            if (url.style['border-color']) {
                url.style.removeProperty('border-color');
            }
            if (size.value > 0 && size.style['border-color']) {
                size.style.removeProperty('border-color');
            }
            if (speed.value > 0 && speed.style['border-color']) {
                speed.style.removeProperty('border-color');
            }
            _changeAppData();
        });
        jQuery("#download-speed").bind("blur", function () {
            changeValue();
        });
        jQuery("#download-size").bind("blur", function () {
            changeValue();
        });
        jQuery("#download-speed").bind("change", function () {
            checkInputValue(this);
        });
        jQuery("#download-size").bind("change", function () {
            checkInputValue(this);
        });
        jQuery("#download-speed").bind("change", function () {
            checkInputValue(this);
        });
        jQuery("#download-url").bind("change", function () {
            if (this.style['border-color']) {
                this.style.removeProperty('border-color');
            }
            if (this.value && checkURL(this.value)) {
                //showUpdateNotification();
            } else  {
                _displayInfo("Invalided URL.");
                this.style['border-color'] = 'red';
            }
        });
    }
};

});
define('ripple/ui/plugins/time', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function _init() {
    var db = require('ripple/db'),
        utils = require('ripple/utils'),
        allTZ, dbTZ, node = jQuery("#time-locale-select"),
        timezone = require('ripple/platform/tizen/2.0/timezone_info'),
        event = require('ripple/event'),
        triggerNode = jQuery("#trigger-alarm-id"),
        alarms, time, timeId;

    function triggerAlarm() {
        time = new Date();
        alarms = db.retrieveObject("tizen1.0-db-alarms");
        if (alarms !== null) {
            utils.forEach(alarms, function (obj) {
                if (obj.id !== undefined) {
                    event.trigger("CheckAlarm", [obj.id]);
                }
            });
        }
    }
    window.setInterval(triggerAlarm, 1000);

    allTZ = timezone.getAllTimezone();
    utils.forEach(allTZ, function (tz) {
        node.append(utils.createElement("option", {
            "value": tz,
            "innerHTML": tz + " - " + timezone.getTimezoneAbbr(tz) + "(" + timezone.getTimezoneDiff(tz) + ")"
        }));
    });
    dbTZ = db.retrieve("tizen-timezone");
    if (timezone.isValidTimezone(dbTZ)) {
        node.val(dbTZ);
    } else {
        db.save("tizen-timezone", node.val());
    }
    node.bind("change", function () {
        db.save("tizen-timezone", node.val());
    });
/* FIXME: Node "trigger-alarm-id" will be removed from Time panel
 *        due to "time" panel will changed to "time zone" panel(PTSDK-875)

    event.on("SendTriggerAppId", function (applicationId) {
        if (timeId !== undefined)
            clearTimeout(timeId);
        triggerNode.empty();
        triggerNode.append(utils.createElement("p", {
            "innerHTML": applicationId + " is triggered"
        }));
        triggerNode.show();
        timeId = setTimeout("jQuery('#trigger-alarm-id').empty();", 10000);// Comments will disappear after 10s
    });
*/
}

module.exports = {
    panel: {
        domId: "time-container",
        collapsed: true,
        pane: "right",
        titleName: "Time",
        display: true
    },
    initialize: _init
};

});
define('ripple/ui/plugins/settings', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var db = require('ripple/db'),
    constants = require('ripple/constants'),
    KEY = constants.XHR.PROXY_DISABLED_BUTTON; // TODO: one settings object for all

function _saveAndReload(key, value) {
    jWorkflow.order(function (prev, baton) {
        baton.take();
        db.save(key, value, null, baton.pass);
    }).start(function () {
        window.tinyHipposReload = true;
        location.reload();
    });
}

function _initialize(prev, baton) {
    var select = document.getElementById("settings-xhr-proxy"),
        about = require('ripple/ui/plugins/about-dialog');

    select.value = String(db.retrieve(KEY));
    select.addEventListener("change", function () {
        _saveAndReload(KEY, this.value);
    }, false);
    
    $("#options-menu-about").click(function () {
        about.show(); 
    });
    // TODO: reload here?
}

module.exports = {
    panel: {
        domId: "settings-container",
        collapsed: true,
        pane: "right"
    },
    initialize: _initialize
};

});
define('ripple/ui/plugins/omnibar', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var emulatorBridge = require('ripple/emulatorBridge'),
    db = require('ripple/db'),
    constants = require('ripple/constants'),
    event = require('ripple/event'),
    histories = [];

function _omnibar() {
    return document.querySelector(".omni-bar input");
}

function _persist(url) {
    db.save("current-url", url);
}

function _persistRoot(url) {
    db.save("root-url", url);
}

function _currentURL() {
    return db.retrieve("current-url") || "about:blank";
}

function _rootURL() {
    return db.retrieve("root-url") || "about:blank";
}

function _reload() {
    emulatorBridge.window().location.reload();
}

function _loadApplication() {
    var omnibar = _omnibar(),
            xhr;
    if (omnibar.value.trim() !== "") {
        if (_currentURL().match(/^file:/) && omnibar.value.match(/^file:/)) { // Use ajax to know whether that file exists
            xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.responseText !== '') {
                        _persist(omnibar.value);
                        _persistRoot(omnibar.value);
                        emulatorBridge.window().location.assign(omnibar.value);
                    } else {
                        alert("File doesn't exist!");
                        return;
                    }
                }
            };
            xhr.open('GET', omnibar.value, true);
            xhr.send(null);
        } else {
            omnibar.value = omnibar.value.indexOf("://") < 0 ? "http://" + omnibar.value : omnibar.value;
            _persist(omnibar.value);
            _persistRoot(omnibar.value);
            emulatorBridge.window().location.assign(omnibar.value);
        }
        _addHistory(omnibar.value);
    }
}

function _hideHistory() {
    $("#app-launching-history").hide("slide", {direction: "up"}, "fast");
    $("#overlayBackground-transparent").hide();
}

function _makeHistoryItems() {
    histories = db.retrieveObject(constants.LAUNCHING_HISTORY);
    if (histories === undefined) {
        histories = [];
    }
    $("#app-launching-history").empty();
    histories.reverse();
    histories.forEach(function (item) {
        $("#app-launching-history").append('<div class="app-launching-history-item">' + item + '</div>');
    });

    if (histories.length === 0) {
        $("#app-launching-history").append('<div class="app-launching-history-item-empty">History empty</div>');
    }

    $(".app-launching-history-item").unbind('click');
    $(".app-launching-history-item").bind("click", function () {
        $(".omni-bar input").val(histories[$(this).index()]);
        _loadApplication();
        _hideHistory();
    });
}


function _showHistory() {
    _makeHistoryItems();
    $("#app-launching-history").css("width", $(".omni-bar input").width() + 20);
    $("#app-launching-history").show("slide", {direction: "up"}, "fast");
    $(window).bind('resize', function () {
        $("#app-launching-history").css("width", $(".omni-bar input").width() + 20);
        $("#overlayBackground-transparent").css("width", $(window).width());
        $("#overlayBackground-transparent").css("height", $(window).height());
    });

    $("#history-background-overlay").show();
    $("#overlayBackground-transparent").css("width", $(window).width());
    $("#overlayBackground-transparent").css("height", $(window).height());
    $("#overlayBackground-transparent").show();
    $("#overlayBackground-transparent").unbind('click');
    $("#overlayBackground-transparent").bind("click", function () {
        _hideHistory();
    });
}


function _addHistory(uri) {
    var i = 0;
    histories = db.retrieveObject(constants.LAUNCHING_HISTORY);
    if (histories !== undefined) {
        for (i; i < histories.length; i++) {
            if (uri === histories[i]) {
                return;
            }
        }

        if (histories.length >= 20) {
            histories.pop();
        }
    } else {
        histories = [];
    }
    histories.push(uri);
    db.saveObject(constants.LAUNCHING_HISTORY, histories);
}

event.on("FrameHistoryChange", function (url) {
    _omnibar().value = url;
    _persist(url);
    _persistRoot(url);
});

module.exports = {
    initialize: function () {
        var omnibar = _omnibar(),
            position, loc, tmp,
            url, filename, matching,
            xhr;

        jQuery(".logo, .beta, .left, .right, .left-panel-collapse, .right-panel-collapse").css({
            "marginTop": "35px"
        });

        jQuery("#settings-xhr-proxy").parent().parent().hide();

        $(".omni-bar").show();

        position = document.documentURI.indexOf("?url=");
        if (position !== -1) {
            url = document.documentURI.substring(position + 5, document.documentURI.length);
            if (url.match(/^\.[\.]?/) !== null) {
                loc = document.location;
                filename = loc.pathname.replace(/^.*[\\\/]/, '');
                matching = new RegExp(filename, "g");
                tmp = loc.protocol + "//" + loc.hostname + loc.pathname.replace(matching, "") + url;
                url = tmp;
            }
            _persist(url);
            _persistRoot(url);
            require('ripple/widgetConfig').initialize();
            require('ripple/ui/plugins/widgetConfig').initialize();
        }

        omnibar.value = _currentURL();

        omnibar.addEventListener("keydown", function (event) {
            if (event.keyCode === '13' || event.keyCode === 13 || event.keyCode === '0' || event.keyCode === 0) { // enter or return
                if (omnibar.value.trim() !== "") {
                    if (_currentURL().match(/^file:/) && omnibar.value.match(/^file:/)) { // Use ajax to know whether that file exists
                        xhr = new XMLHttpRequest();
                        xhr.onreadystatechange = function () {
                            if (xhr.readyState == 4) {
                                if (xhr.responseText !== '') {
                                    _persist(omnibar.value);
                                    _persistRoot(omnibar.value);
                                    emulatorBridge.window().location.assign(omnibar.value);
                                } else {
                                    alert("File doesn't exist!");
                                    return;
                                }
                            }
                        };
                        xhr.open('GET', omnibar.value, true);
                        xhr.send(null);
                    } else {
                        //default the protocal if not provided
                        omnibar.value = omnibar.value.indexOf("://") < 0 ? "http://" + omnibar.value : omnibar.value;
                        _persist(omnibar.value);
                        _persistRoot(omnibar.value);
                        emulatorBridge.window().location.assign(omnibar.value);
                    }

                    _addHistory(omnibar.value);
                }
            }
        });

        window.addEventListener("keydown", function (event) {
            var hasMetaOrAltPressed = (event.metaKey || event.ctrlKey),
                key = parseInt(event.keyCode, 10);

            if (key === 82 && hasMetaOrAltPressed) { // cmd/ctrl + r
                event.preventDefault();
                _reload();
            }

            if (key === 116) { // F5
                event.preventDefault();
                _reload();
            }
        });

        document.getElementById("history-reload").addEventListener("click", _reload);
        $("#options-button-history").bind("click", function () {
            _showHistory();
        });
    },
    currentURL: function () {
        return _currentURL();
    },
    rootURL: function () {
        return _rootURL();
    }
};

});
define('ripple/ui/plugins/messaging', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var event = require('ripple/event'),
    utils = require('ripple/utils'),
    _type = {
        sms: "SMS",
        mms: "MMS",
        email: "E-mail"
    },
    _filename_suffix = 0,
    _attachments = [];

function _getAttachmentFileName() {
    return "attach" + _filename_suffix + ".txt";
}

module.exports = {
    panel: {
        domId: "messaging-container",
        collapsed: true,
        pane: "left",
        titleName: "Messaging",
        display: true
    },
    initialize: function () {
        document.getElementById("messaging-send")
            .addEventListener("click", function () {
                var number = document.getElementById("messaging-sms-number").value,
                    text = document.getElementById("messaging-text").value,
                    type = document.getElementById("messaging-type").value,
                    message = {
                        type: type,
                        body: text,
                        from: number,
                        time: new Date(),
                        attachments: _attachments
                    };

                event.trigger("MessageReceived", [message]);
                
                _attachments = [];
/* TODO: add back when attachment is finished
                document.getElementById("messaging-attachments").innerHTML = "";
*/
                _filename_suffix = 0;
            }, false);

/* TODO: add back when attachment is finished
        document.getElementById("messaging-attach")
            .addEventListener("click", function () {
                var attachedFile, attachedFileCheckbox, attachedFileName;
                if (_filename_suffix > 0)
                    return;
                _attachments.push({filename: _getAttachmentFileName(), content: document.getElementById("messaging-attachment-content").value});

                attachedFile = document.getElementById("messaging-attachments").insertRow(0);
                attachedFileName = attachedFile.insertCell(0);
                attachedFileCheckbox = attachedFile.insertCell(1);
                attachedFileName.innerHTML = _attachments[_filename_suffix].filename;
//                attachedFileCheckbox.innerHTML = '<input type="checkbox" value="' + _filename_suffix + '">';

                document.getElementById("messaging-attachment-content").value = "";
                _filename_suffix++;
            }, false);

        document.getElementById("messaging-detach")
            .addEventListener("click", function () {
                _attachments = [];
                document.getElementById("messaging-attachments").innerHTML = "";
                _filename_suffix = 0;
            }, false);
*/
        event.on("OutsideMessageReceived", function (message) {
            var numRecipients = 0,
                i = 0,
                recipients = [],
                recipientsStatus = {},
                strRecipients = document.getElementById("messaging-recipients").value;

            recipientsStatus.id = message.id;
            recipientsStatus.msg = message.msg;
            for (i in message.to) {
                recipientsStatus[message.to[i]] = true;
                recipients.push(message.to[i]);
            }
            for (i in message.cc) {
                recipientsStatus[message.cc[i]] = true;
                recipients.push(message.cc[i]);
            }
            for (i in message.bcc) {
                recipientsStatus[message.bcc[i]] = true;
                recipients.push(message.bcc[i]);
            }
            numRecipients = recipients.length;
            strRecipients = recipients.join(",");
            event.trigger("MessageSent", [recipientsStatus]);
            document.getElementById("messaging-received").innerHTML = "" + numRecipients + " recipient(s)" + " delivered";
            document.getElementById("messaging-recipients").value = strRecipients;
            document.getElementById("received-message-box").value = message.body;
        });
        
        document.getElementById("messaging-clear")
            .addEventListener("click", function () {
                document.getElementById("received-message-box").value = "";
                document.getElementById("messaging-received").innerHTML = "";
            }, false);
        
        utils.forEach(_type, function (msgTypeText, msgType) {
            var typeNode = utils.createElement("option", {
                    "innerText": msgTypeText,
                    "value": msgType
                });

            document.getElementById("messaging-type").appendChild(typeNode);
        });
    }
};

});
define('ripple/ui/plugins/about-dialog', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    bus = require('ripple/bus');

module.exports = {
    initialize: function () {
        $("#about-dialog").dialog({
            resizable: false,
            draggable: false,
            modal: true,
            autoOpen: false,
            position: 'center',
            minWidth: '464',
            minHeight: '262'
        });
    },
    show: function () {
        //TODO: Restore this line once framework issue is resolved
        //var port =  window.stagewebview ? stagewebview.serverPort : "9900";
        var port = "9910";

        bus.send("version", null, function (resp) {
            $("#about-dialog-ripple-ui-version").html("(v" + resp + ")");
        });

        bus.ajax(
            "GET",
            "http://127.0.0.1:" + port + "/ripple/about",
            null,
            function (resp) {
                $("#about-dialog-ripple-build-deploy-version").html("(v" + resp.data.version + ")");
            },
            function (error) {
                var version = error.data;
                
                if (error.code === 0 || error.code === 404) {
                    version = "The service is not running";
                }
                $("#about-dialog-ripple-build-deploy-version").html("(" + version + ")");
            }
        );

        $("#about-dialog").dialog("open");
    }
};

});
define('ripple/ui/plugins/themeSwitcher', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    db = require('ripple/db'),
    THEME_KEY = "ui-theme",
    THEME_SELECTOR = "#theme-select",
    _currentTheme;

function _saveAndReload(key, value) {
    jWorkflow.order(function (prev, baton) {
                baton.take();
                db.save(key, value, null, baton.pass);
            }).start(function () {
                window.tinyHipposReload = true;
                location.reload();
            });
}

module.exports = {
    initialize: function () {
        var themeToSet = db.retrieve(THEME_KEY);

	// Hide the theme switcher and always set the theme to light
        jQuery(".theme-switcher").hide();
		if (themeToSet !== "light") {
            _saveAndReload(THEME_KEY, "light");
		}
		return;
    }
};

});
define('ripple/ui/plugins/eulaCheck', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    bus = require('ripple/bus');

function _initializeEulaCheck() {
    var width = jQuery(document).width(),
        p = (width / 2) - 277;


    $(".eula-window").show();
    $(".eula-dialog").show().css({left: p + "px"});

    $("#eula-accept").click(function () {
        bus.send("acceptEula", null, function (result) {
            $(".eula-window").hide();
            $(".eula-dialog").hide();
        });
    });

    $("#eula-decline").click(function () {
        bus.send("disable", null, null);
    });
}

module.exports = {
    initialize: function () {
        //HACK: there has to be a better way!!!
        if ($("#extension-url").val().match(/geelfhphabnejjhdalkjhgipohgpdnoc/)) {
            // do nothing, extension was installed from the Chrome Store
            return;
        }

        bus.send("checkEula", null, function (response) {
            console.log("eula response: ", response);
            if (response === false) {
                _initializeEulaCheck();
            }
        });
    }
};

});
define('ripple/ui/plugins/sensors', function (require, exports, module) {
/*
 * Copyright (c) 2010 Epic Train Hack
 * Copyright (c) 2011 Research In Motion Limited
 * Contributors: Wolfram Kriesing, Dan Silivestru, Brent Lintner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
var event = require('ripple/event'),
    accelerometer = require('ripple/accelerometer'),
    deviceSettings = require('ripple/deviceSettings'),
    Acceleration = require('ripple/platform/w3c/1.0/Acceleration'),
    Rotation = require('ripple/platform/w3c/1.0/Rotation'),
    sensorSettings = require('ripple/sensorSettings'),
    _oldX, _oldY, _oldAlphaX,
    _camera, _scene, _renderer, _mesh,
    _offsets = {
        x: 0,
        y: 0,
        z: -9.81,
    },
    _flag, // whether the browser supports webGL
    _shape =
        //
        // The front side
        //
        // x, y, z      x, y, z         x, y, z
        // for some strange reason for y -100 is top, 100 is bottom
        "-30,30,10,     30,30,10,       30,60,10,       100,100,100,-1,0;" + // top left, top right, bottom right - of the right triangle
        "-30,30,10,     30,60,10,       -30,60,10,      100,100,100,-1,0;" + // top left, right bottom, left bottom - of the left triangle
        // front side "the phone display"
        "-20,-50,11,    20,-50,11,      20,20,11,       100,100,100,-1,0;" +
        "-20,-50,11,    20,20,11,       -20,20,11,      100,100,100,-1,0;" +
        // below the display
        "-30,30,10,     30,20,10,       30,30,10,       0,0,0,-1,0;" +
        "-30,30,10,     -30,20,10,      30,20,10,       0,0,0,-1,0;" +
        // above the display
        "-30,-60,10,    30,-60,10,      30,-50,10,      0,0,0,-1,0;" +
        "-30,-60,10,    30,-50,10,      -30,-50,10,     0,0,0,-1,0;" +
        // left of the display
        "-30,-50,10,    -20,-50,10,     -20,20,10,      0,0,0,-1,0;" +
        "-30,-50,10,    -20,20,10,      -30,20,10,      0,0,0,-1,0;" +
        // right of the display
        "20,-50,10,     30,-50,10,      30,20,10,       0,0,0,-1,0;" +
        "20,-50,10,     30,20,10,       20,20,10,       0,0,0,-1,0;" +


        // back side, opposite side to the above one
        "-30,-60,-10,   30,60,-10,      30,-60,-10,     0,0,0,-1,0;" +
        "-30,-60,-10,   -30,60,-10,     30,60,-10,      0,00,-1,0;" +
        // right side
        "30,-60,-10,    30,60,-10,      30,60,10,       50,50,80,-1,0;" +
        "30,-60,-10,    30,60,10,       30,-60,10,      50,50,80,-1,0;" +
        // left side
        "-30,-60,-10,   -30,60,10,      -30,60,-10,     50,50,80,-1,0;" +
        "-30,-60,-10,   -30,-60,10,     -30,60,10,      50,50,80,-1,0;" +

        // top
        "30,-60,-10,    -30,-60,10, -30,-60,-10,    50,80,50,-1,0;" +
        "30,-60,-10,    30,-60,10,      -30,-60,10, 50,80,50,-1,0;" +
        // bottom
        "30,60,-10, -30,60,-10,     -30,60,10,      80,50,50,-1,0;" +
        "30,60,-10, -30,60,10,      30,60,10,       80,50,50,-1,0";

function _createThreeDModel() {
    var node,
        shader,
        hemiLight,
        dirLight,
        material,
        uniforms,
        container,
        loader,
        directionalLight,
        isDiffuseTextureLoaded,
        isNormalTextureLoaded,
        shiftKeyDown,
        mouseDown,
        ctrlKeyDown = false;

    if (_flag) {
        // create a 3D phone model with three.js if webGL is supported
        node = document.getElementById("accelerometer-div");
        container = document.createElement("div");
        $("#accelerometer-div").append(container);

        _camera = new THREE.PerspectiveCamera(50, 1.5, 0.1, 100);
        _camera.position.set(4.32823, 3.74714, 2.62985);
        _scene = new THREE.Scene();
        _scene.add(new THREE.AmbientLight(0xffffff));
        directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(1, 1, 1).normalize();
        _scene.add(directionalLight);
        hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6);
        hemiLight.color.setHSV(0.6, 0.75, 1);
        hemiLight.groundColor.setHSV(0.095, 0.5, 1);
        hemiLight.position.set(0, 500, 0);
        _scene.add(hemiLight);
        dirLight = new THREE.DirectionalLight(0xffffff, 1);
        dirLight.color.setHSV(0.1, 0.1, 1);
        dirLight.position.set(-1, 1.75, 1);
        dirLight.position.multiplyScalar(50);
        _scene.add(dirLight);
        shader = THREE.ShaderSkin["skin"];
        uniforms = THREE.UniformsUtils.clone(shader.uniforms);
        uniforms["tNormal"].value = THREE.ImageUtils.loadTexture("images/phoneMap_tNormal.png", {}, function () {
            isNormalTextureLoaded = true;
            if (isDiffuseTextureLoaded) {
                _renderer.clear();
                _renderer.render(_scene, _camera);
            }
        });
        uniforms["uNormalScale"].value = 0.75;
        uniforms["tDiffuse"].value = THREE.ImageUtils.loadTexture("images/phoneMap_tDiffuse.png", {}, function () {
            isDiffuseTextureLoaded = true;
            if (isNormalTextureLoaded) {
                _renderer.clear();
                _renderer.render(_scene, _camera);
            }
        });
        uniforms["uDiffuseColor"].value.setHex(0xbbbbbb);
        uniforms["uSpecularColor"].value.setHex(0x070707);
        uniforms["uAmbientColor"].value.setHex(0x111111);
        uniforms["uRoughness"].value = 0.185;
        uniforms["uSpecularBrightness"].value = 0.8;
        material = new THREE.ShaderMaterial({ fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true });
        loader = new THREE.JSONLoader(true);
        document.body.appendChild(loader.statusDomElement);

        loader.load("phoneModel.js", function (geometry) {
            loader.statusDomElement.style.display = "none";
            geometry.computeTangents();
            _mesh = new THREE.Mesh(geometry, material);
            _mesh.position.set(7, 2, -50);
            _mesh.scale.set(18, 12, 18);
            _scene.add(_mesh);
            _renderer.clear();
            _renderer.render(_scene, _camera);
        });

        _renderer = new THREE.WebGLRenderer({antialias: false});
        _renderer.setSize(300, 280);
        _renderer.setClearColorHex(0xffffff, 1);
        _renderer.autoClear = false;

        container.appendChild(_renderer.domElement);
    } else { // create the model with 3d.js
        node = document.querySelector("#accelerometer-canvas");

        jQuery("#accelerometer-div").css("display", "none");
        jQuery("#accelerometer-canvas").css("display", "block");
        ThreeDee.setCenter(150, 100);
        ThreeDee.setLight(-300, -300, 800);
        _updateCanvas(0, 0);
    }

    //change accelerometer and phone by moving the mouse and the key "shift"
    node.addEventListener("mousemove", function (event) {
        var cosX, sinX, cosY, sinY,
            alpha = accelerometer.getInfo().orientation.alpha,
            beta = accelerometer.getInfo().orientation.beta,
            gamma = accelerometer.getInfo().orientation.gamma,
            x = accelerometer.getInfo().acceleration.x,
            y = accelerometer.getInfo().acceleration.y,
            z = accelerometer.getInfo().acceleration.z;

        if (!mouseDown) {
            return;
        }

        // if the shift key is pressed down, only the alpha value will be chagned
        if (!shiftKeyDown) {
            _offsets.x = (_offsets.x + _oldX - event.offsetX) % 360;
            _offsets.y = (_offsets.y + _oldY - event.offsetY) % 360;

            alpha = alpha || 0;

            // enforce gamma in [-90,90] as per w3c spec
            gamma = -_offsets.x;
            if (gamma < -90) {
                gamma = -90;
            }
            if (gamma > 90) {
                gamma = 90;
            }

            // enforce beta in [-180,180] as per w3c spec
            beta = -_offsets.y % 360;
            if (beta < -180) {
                beta += 360;
            }
            else if (beta >= 180) {
                beta -= 360;
            }

            cosX = Math.cos(gamma * (Math.PI / 180));
            sinX = Math.sin(gamma * (Math.PI / 180));
            cosY = Math.cos(beta * (Math.PI / 180));
            sinY = Math.sin(beta * (Math.PI / 180));
            x = 9.81 * cosY * sinX;
            y = -9.81 * sinY;
            z = -9.81 * cosY * cosX;

        } else {
            alpha = (alpha - (_oldAlphaX - event.offsetX) * 2.5) % 360;
        }
        _oldX = event.offsetX;
        _oldY = event.offsetY;
        _oldAlphaX = event.offsetX;
        if (_flag)
            _updatePhoneModel(alpha, beta, gamma);
        else
            _updateCanvas(alpha, -beta, gamma);
        accelerometer.setInfo({
            x: x,
            y: y,
            z: z,
            alpha: alpha,
            beta: beta,
            gamma: gamma
        });
    }, false);

    node.addEventListener("mousedown", function (e) {
        mouseDown = true;
        _oldX = e.offsetX;
        _oldY = e.offsetY;
        if (shiftKeyDown) {
            _oldAlphaX = _oldX;
        }
    });

    node.addEventListener("mouseup", function () {
        mouseDown = false;
    });

    document.addEventListener("mouseup", function () {
        //Catch mouseup events that fire when outside canvas bounds
        mouseDown = false;
    });

    document.addEventListener("keydown", function (e) {
        switch (e.keyCode) {
        case 16:                // Shift Key
            shiftKeyDown = true;
            break;
        case 17:                // Ctrl Key
            ctrlKeyDown = true;
            break;
        case 74:                // J Key
            if (shiftKeyDown && ctrlKeyDown) { //if shift+ctrl+j keydown in the meantime, console comes up rather than shift key down
                shiftKeyDown = false;
                ctrlKeyDown = false;
            }
            break;
        }
    });

    document.addEventListener("keyup", function (e) {
        if (e.keyCode === 16) { // Shift Key
            shiftKeyDown = false;
        }
    });
}

// update the 3d model created by 3d.js
function _updateCanvas(a, b, g) {
    ThreeDee.loadMesh(_shape);
    g = g || 0;
    ThreeDee.rotate(0, g, 0);
    ThreeDee.rotate(b, 0, a);
    ThreeDee.backface();
    ThreeDee.shade();
    ThreeDee.zSort();
    Draw.initialize(document.querySelector("#accelerometer-canvas"));
    Draw.clear(0, 0, 480, 300);
    Draw.drawScene(ThreeDee.getTranslation(), 3);
}

// update the 3d model created by three.js
function _updatePhoneModel(a, b, g) {
    _mesh.rotation.x = b / 90 * 1.5;
    _mesh.rotation.y = g / 90 * 1.5;
    _mesh.rotation.z = a / 90 * 1.5;
    _renderer.clear();
    _renderer.render(_scene, _camera);
}

function _resetAccelerometer() {
    _oldX = 0;
    _oldY = 0;
    _oldAlphaX = 0;
    _offsets = {
        x: 0,
        y: 0,
        z: -9.81
    };
    if (_flag) {
        _mesh.rotation.x = 0;
        _mesh.rotation.y = 0;
        _mesh.rotation.z = 0;
        _renderer.clear();
        _renderer.render(_scene, _camera);
    } else {
        _updateCanvas(0, 0);
    }

    accelerometer.setInfo({
        acceleration: new Acceleration(0, 0, 0),
        accelerationIncludingGravity: new Acceleration(0, 0, -9.81),
        rotationRate: new Rotation(0, 0, 0),
        orientation: new Rotation(0, 0, 0),
        timestamp: new Date().getTime()
    });
}

function _resetMagneticField() {
    jQuery("#magnetic-x").val("100");
    jQuery("#magnetic-y").val("100");
    jQuery("#magnetic-z").val("100");
}

function _resetLightLevel() {
    $("#display-state").children().each(function(){
        if ($(this).val() === "OFF"){
            $(this).attr("selected","true");
            this.selected = true;
        }
        else {
            $(this).attr("selected","false");
            this.selected = false;
        }
    });
}


// set a typical mode for accelerometer simulation, when the phone drops,
// x will become to be 0, y will become to be -9.81 and z will become to be 0
function _setDrop() {
    //duration = 20 * 50 = 1000ms. 20 is ths number of steps and 50 is the duration of steps.
    var alpha = Number(accelerometer.getInfo().orientation.alpha),
        beta = Number(accelerometer.getInfo().orientation.beta),
        gamma = Number(accelerometer.getInfo().orientation.gamma),
        cosX, cosY, sinX, sinY, x, y, z,
        alphaStep = Math.abs(alpha) / 20,
        betaStep = Math.abs(beta - 90) / 20,
        gammaStep = Math.abs(gamma) / 20,
        counts = 0, dropTimeout,
        drop = function () {
            if (counts >= 20) {
                window.clearTimeout(dropTimeout);
                // to avoid showing "-0" or "-0.00"
                if (_flag)
                    _updatePhoneModel(0, 90, 0);
                else
                    _updateCanvas(0, -90, 0);
                accelerometer.setInfo({
                    x: 0,
                    y: -9.81,
                    z: 0,
                    alpha: 0,
                    beta: 90,
                    gamma: 0
                });
            } else {
                dropTimeout = setTimeout(drop, 50);
                step();
                counts++;
            }
        },
        step = function () {
            var _beta;

            alpha = alpha > 0 ? alpha - alphaStep : alpha + alphaStep;
            beta = beta > 90 ? beta - betaStep : beta + betaStep;
            gamma = gamma > 0 ? gamma - gammaStep : gamma + gammaStep;
            _beta = _flag ? beta + betaStep : -(beta + betaStep);
            if (_flag)
                _updatePhoneModel(alpha, _beta, gamma);
            else
                _updateCanvas(alpha, _beta, gamma);

            cosX = Math.cos(gamma * (Math.PI / 180));
            sinX = Math.sin(gamma * (Math.PI / 180));
            cosY = Math.cos(beta * (Math.PI / 180));
            sinY = Math.sin(beta * (Math.PI / 180));
            x = 9.81 * cosY * sinX;
            y = -9.81 * sinY;
            z = -9.81 * cosY * cosX;
            accelerometer.setInfo({
                x: x,
                y: y,
                z: z,
                alpha: alpha,
                beta: beta,
                gamma: gamma
            });
            _offsets.x = -gamma;
            _offsets.y = -beta;
        };

    drop();
}

function _initializeSensorSettings() {
    var sensorsInputID = ["accelerometer-alpha", "accelerometer-beta", "accelerometer-gamma", "magnetic-x", "magnetic-y", "magnetic-z"],
        magneticEvent = ["MagneticField-xChanged", "MagneticField-yChanged", "MagneticField-zChanged"],
         magneticData = ["MagneticField.x", "MagneticField.y", "MagneticField.z"],
        oldValue, oldInputX,
        inputMouseDown,
        triggerFunction;

    triggerFunction = function (val, index) {
        var cosX, cosY, sinX, sinY, x, y, z,
            alpha = accelerometer.getInfo().orientation.alpha,
            beta = accelerometer.getInfo().orientation.beta,
            gamma = accelerometer.getInfo().orientation.gamma;

        //choose which value to change according to index
        switch (index) {
        case 0:
            alpha = val;
            break;
        case 1:
            beta = val;
            break;
        case 2:
            gamma = val;
            break;
        default:
            sensorSettings.persist(magneticData[index - 3], val);
            event.trigger(magneticEvent[index - 3], [val]);
        }

        //change the phone model and values of other inputs when changing a value of input
        if (_flag)
            _updatePhoneModel(alpha, beta, gamma);
        else
            _updateCanvas(alpha, -beta, gamma);
        cosX = Math.cos(gamma * (Math.PI / 180));
        sinX = Math.sin(gamma * (Math.PI / 180));
        cosY = Math.cos(beta * (Math.PI / 180));
        sinY = Math.sin(beta * (Math.PI / 180));
        x = 9.81 * cosY * sinX;
        y = -9.81 * sinY;
        z = -9.81 * cosY * cosX;
        accelerometer.setInfo({
            x: x,
            y: y,
            z: z,
            alpha: alpha,
            beta: beta,
            gamma: gamma
        });
        _offsets.x = -gamma;
        _offsets.y = -beta;
    };

    // make the input elements more powful: drag mouse to left to decrease the value and right to increase it;
    // also change the value with arrow keys.


    sensorsInputID.forEach(function (id, index) {
        jQuery("#" + id).click(function () {
            this.select();
        });

        jQuery("#" + id).blur(function () {
            if (isNaN(this.value)) {
                this.value = 0;
            }
            else if (parseInt(this.value, 10) > parseInt(jQuery(this).attr("maxValue"), 10))
                this.value = jQuery(this).attr("maxValue");
            else if (parseInt(this.value, 10) < parseInt(jQuery(this).attr("minValue"), 10))
                this.value = jQuery(this).attr("minValue");
            else
                this.value = parseInt(this.value, 10);
            triggerFunction(this.value, index);
        });

        jQuery("#" + id).keydown(function (e) {
            switch (e.keyCode) {
            case 38:
                if (parseInt(this.value, 10) < parseInt(jQuery(this).attr("maxValue"), 10)) {
                    this.value = parseInt(this.value, 10) + 1;
                    triggerFunction(this.value, index);
                }
                break;
            case 40:
                if (parseInt(this.value, 10) > parseInt(jQuery(this).attr("minValue"), 10)) {
                    this.value = parseInt(this.value, 10) - 1;
                    triggerFunction(this.value, index);
                }
                break;
            default:
                return;
            }
        });
    });
}

//initialize light settings
function _initializeLightSettings() {
    var displayObj = document.getElementById("display-state"),
        DISPLAY_STATE  = require('ripple/constants').POWER_RESOURCE.DISPLAY.STATE,
        brightness;

    displayObj.addEventListener("change", function () {
        var state = displayObj.value, value;
        value = DISPLAY_STATE[state].VALUE;
        deviceSettings.persist("Display.brightness", value);
        event.trigger("DisplayBrightnessChanged", [value]);
    });

    brightness = deviceSettings.retrieve("Display.brightness");
    if (brightness ===  DISPLAY_STATE.OFF.MAX) {
        displayObj.options[0].selected = true;
    } else if (brightness <= DISPLAY_STATE.DIM.MAX) {
        displayObj.options[1].selected = true;
    } else if (brightness <= DISPLAY_STATE.NORMAL.MAX) {
        displayObj.options[2].selected = true;
    } else {
        displayObj.options[3].selected = true;
    }
}

module.exports = {
    panel: {
        domId: "sensors-container",
        collapsed: true,
        pane: "left",
        titleName: "Sensors",
        display: true
    },
    initialize: function () {
        var gl,
            testCanvas = document.getElementById("accelerometer-canvas");

        try { // check whether the browser supports webGL, returns null if not support
            gl = testCanvas.getContext("experimental-webgl");
            gl.viewport(0, 0, testCanvas.width, testCanvas.height);
        } catch (e) {
            console.log("unsupport webgl");
        }

        _flag = gl ? true : false;

        _createThreeDModel();
        _initializeSensorSettings();
        _initializeLightSettings();

        jQuery("#accelerometer-shake").click(function () {
            window.setTimeout(require('ripple/ui/plugins/goodVibrations').shakeDevice(8), 1);
            accelerometer.shake();
        });

        jQuery("#sensor-reset-all").click(function() {
            _resetAccelerometer();
            _resetMagneticField();
            _resetLightLevel();
        });

        jQuery("#accelerometer-drop").click(_setDrop);

        event.on("AccelerometerInfoChangedEvent", function (motion) {
            jQuery("#accelerometer-x").html(motion.accelerationIncludingGravity.x.toFixed(2));
            jQuery("#accelerometer-y").html(motion.accelerationIncludingGravity.y.toFixed(2));
            jQuery("#accelerometer-z").html(motion.accelerationIncludingGravity.z.toFixed(2));
            jQuery("#accelerometer-alpha").val(Number(motion.orientation.alpha).toFixed(2));
            jQuery("#accelerometer-beta").val(Number(motion.orientation.beta).toFixed(2));
            jQuery("#accelerometer-gamma").val(Number(motion.orientation.gamma).toFixed(2));
        }, this);
    }
};

});
define('ripple/ui/plugins/platform', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var constants = require('ripple/constants'),
    utils = require('ripple/utils'),
    devices = require('ripple/devices'),
    platform = require('ripple/platform'),
    db = require('ripple/db');

function _updatePlatformDeviceSelect(platformID, currentDeviceKey) {
    var devicesSelect = document.getElementById(constants.COMMON.DEVICE_SELECT_ID),
        listOfSortedDevices = devices.getDevicesForPlatform(platformID)
                                        .sort(function (a, b) {
                                            return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);
                                        });

    devicesSelect.innerHTML = "";

    listOfSortedDevices.forEach(function (dev) {
        var deviceNode = utils.createElement("option", {
            "innerText": dev.name,
            "value": dev.id
        });

        if (currentDeviceKey && deviceNode.value === currentDeviceKey) {
            deviceNode.selected = true;
        }

        devicesSelect.appendChild(deviceNode);
    });
}

function checkResolutionSize(evt) {
	var query_str, id_str, len;
	query_str = "#resolution-custom-" + evt.data.msg;
	id_str = "custom_" + evt.data.msg;
	len = jQuery(query_str).val();
	if (len >= 200 && len <= 2000) {
		db.save(id_str, len);
	} else {
		jQuery(query_str).val(db.retrieve(id_str));
	}
}

module.exports = {
    initialize: function () {
        var currentPlatform = platform.current().id,
            currentVersion = platform.current().version,
            platformList = platform.getList(),
            platformSelect = document.getElementById(constants.COMMON.PLATFORM_SELECT_ID),
            versionSelect = document.getElementById("version-select"),
            currentDeviceKey = devices.getCurrentDevice().id,
            platformNode, versionNode;

        jQuery("#platform-select").bind("change", function () {
            var newPlatform = jQuery(this).val(),
                newDevice = jQuery("#device-select").val();

            jQuery(versionSelect).children("option").remove();

            utils.forEach(platformList, function (platform) {
                utils.forEach(platform, function (version, versionNumber) {
                    if (newPlatform === version.id) {
                        versionSelect.appendChild(utils.createElement("option", {
                            "innerText": versionNumber,
                            "value":  versionNumber
                        }));
                    }
                });
            });

            _updatePlatformDeviceSelect(newPlatform, newDevice);

        });

        jQuery("#device-select").bind("focus", function () {
            $('input:radio[name="resolution-type"][value="predefined"]').click();
        });
        jQuery("#resolution-custom-width").bind("focus", function () {
            $('input:radio[name="resolution-type"][value="custom"]').click();
        });
        jQuery("#resolution-custom-height").bind("focus", function () {
            $('input:radio[name="resolution-type"][value="custom"]').click();
        });
        jQuery("#resolution-custom-width").bind("change", {msg: "width"}, checkResolutionSize);
        jQuery("#resolution-custom-height").bind("change", {msg: "height"}, checkResolutionSize);

        utils.forEach(platformList, function (platform, platformKey) {
            platformNode = utils.createElement("option", {
                "innerText": platformKey,
                "value":  platformKey
            });

            utils.forEach(platform, function (version, versionNumber) {
                versionNode = utils.createElement("option", {
                    "innerText": versionNumber,
                    "value":  versionNumber
                });

                if (currentPlatform && version.id === currentPlatform) {
                    if (currentVersion && currentVersion === versionNumber) {
                        platformNode.selected = true;
                        versionNode.selected = true;
                    }
                }
                if (currentPlatform && version.id === currentPlatform) {
                    versionSelect.appendChild(versionNode);
                }
            });
 
            platformSelect.appendChild(platformNode);
        });

        _updatePlatformDeviceSelect(currentPlatform, currentDeviceKey);

    }
};

});
define('ripple/ui/plugins/tooltip', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var utils = require('ripple/utils'),
    _options = {
        track: true,
        delay: 0,
        showURL: false,
        fade: 250,
        extraClass: "ui-state-highlight ui-corner-all"
    };

module.exports = {
    create: function (element, message) {
        var options = utils.copy(_options);

        options.bodyHandler = function () {
            return message;
        };

        return jQuery(element).tooltip(options);
    },

    toggle: function () {
        jQuery.tooltip.block();
        return this.isOff();
    },

    isOff: function () {
        return jQuery.tooltip.blocked;
    }
};

});
define('ripple/ui/plugins/network', function (require, exports, module) {
/*
 *  Copyright 2012 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var db = require('ripple/db'),
    utils = require('ripple/utils'),
    event = require('ripple/event'),
    deviceSettings = require('ripple/deviceSettings'),
    btdevices = require('ripple/platform/tizen/2.0/spec/btdevices'),
    _NFC_TAG = "tizen1.0-nfc-tag",
    _NFC_PEER = "tizen1.0-nfc-peer",
    _NFC_OUTPUT_MESSAGE = "tizen1.0-nfc-output-message",
    _powered = false,
    _polling = false,
    _isConnected = false,
    _tagNDEF = {
        type: "GENERIC_TARGET",
        isSupportedNDEF: true,
        ndefSize: 2,
        ndefs: [{
            recordCount: 2,
            records: [{
                tnf: 1,
                type: "TypeA",
                id: "ID001",
                payload: "This is 1st payload"
            }, {
                tnf: 1,
                type: "TypeA",
                id: "ID002",
                payload: "This is 2nd payload"
            }]
        },
        {
            recordCount: 2,
            records: [{
                tnf: 1,
                type: "TypeA",
                id: "ID001",
                payload: "This is 1st payload"
            }, {
                tnf: 1,
                type: "TypeA",
                id: "ID002",
                payload: "This is 2nd payload"
            }]
        }]
    },
    _tagRaw = {
        type: "GENERIC_TARGET",
        isSupportedNDEF: false,
        rawData : ""
    },
    _peerNDEF = {
        ndef: {
            recordCount: 2,
            records: [{
                tnf: 1,
                type: "TypeA",
                id: "ID001",
                payload: "This is 1st payload"
            }, {
                tnf: 1,
                type: "TypeA",
                id: "ID002",
                payload: "This is 2nd payload"
            }]
        }
    },
    btNodes,
    _btDeviceTemplate = "",
    _btSimulatedDevs = {};

function elementEnableDisableSetting(prop) {
    jQuery("#nfc-attach-msg").text("\xa0");
    jQuery("#nfc-peer-send-msg").text("\xa0");
    if (prop && prop.power !== undefined && prop.power !== null) {
        if (prop.power) {
            $("#nfc-polling").removeAttr("disabled");
            $("#nfc-main-container").show();
        } else {
            $("#nfc-polling").attr("disabled", "disabled");
            $("#nfc-type").removeAttr("disabled");
            $("#nfc-main-container").hide();
        }
    }
    if (prop && prop.connectedState !== undefined && prop.connectedState !== null) {
        if (prop.connectedState) {
            $("#nfc-type").attr("disabled", "disabled");
            $("#nfc-tag-type-text").text($("#nfc-tag-type option:selected").text());
            $("#nfc-tag-type").hide();
            $("#nfc-tag-type-text").show();
            $("#nfc-tag-NDEF-support-text").text($("#nfc-tag-NDEF-support option:selected").text());
            $("#nfc-tag-NDEF-support").hide();
            $("#nfc-tag-NDEF-support-text").show();
            $("#nfc-raw-data").attr("disabled", "disabled");
        } else {
            $("#nfc-type").removeAttr("disabled");
            $("#nfc-tag-type").show();
            $("#nfc-tag-type-text").hide();
            $("#nfc-tag-NDEF-support").show();
            $("#nfc-tag-NDEF-support-text").hide();
            $("#nfc-raw-data").removeAttr("disabled");
        }
    }
}

function _initializeElements() {
    jQuery(function () {
        var stop = false,
        wifiRadio = $("#wifi-radio"),
        isSupportNDEF, type;

        // initialize main menus
        wifiRadio.buttonset();
        $("#network-type-radio").buttonset();
        $("#nfc-radio").buttonset();
        $("#bluetooth-radio").buttonset();

        $("#wifi-radio1").prop('checked', false);
        $("#wifi-radio2").prop('checked', false);
        if (deviceSettings.retrieve("WifiNetwork.status") === "true") {
            $("#wifi-radio1").prop('checked', true);
        }
        else {
            $("#wifi-radio2").prop('checked', true);
        }
        $("#wifi-radio1").button("refresh");
        $("#wifi-radio2").button("refresh");

        $("#network-type1").prop('checked', false);
        $("#network-type2").prop('checked', false);
        $("#network-type3").prop('checked', false);
        if (deviceSettings.retrieve("Network.networkType") === "2G") {
            $("#network-type1").prop('checked', true);
        }
        else if (deviceSettings.retrieve("Network.networkType") === "3G") {
            $("#network-type2").prop('checked', true);
        }
        else {
            $("#network-type3").prop('checked', true);
        }
        $("#network-type1").button("refresh");
        $("#network-type2").button("refresh");
        $("#network-type3").button("refresh");

        $("#wifi-radio1").click(function () {
            deviceSettings.persist("WifiNetwork.status", "true");
            event.trigger("WiFiNetworkStatusChanged", [true]);
        });

        $("#wifi-radio2").click(function () {
            deviceSettings.persist("WifiNetwork.status", "false");
            event.trigger("WiFiNetworkStatusChanged", [false]);
        });

        $("#network-type1").click(function () {
            deviceSettings.persist("Network.networkType", "2G");
            event.trigger("NetworkTypeChanged", ["2G"]);
        });

        $("#network-type2").click(function () {
            deviceSettings.persist("Network.networkType", "3G");
            event.trigger("NetworkTypeChanged", ["3G"]);
        });

        $("#network-type3").click(function () {
            deviceSettings.persist("Network.networkType", "4G");
            event.trigger("NetworkTypeChanged", ["4G"]);
        });

        $("#nfc-radio1").click(function () {
            $("#nfc-main-container").show();
        });

        $("#nfc-radio2").click(function () {
            $("#nfc-main-container").hide();
        });

        $("#bluetooth-radio1").click(function () {
            $("#bluetooth-main-container").show();
        });

        $("#bluetooth-radio2").click(function () {
            $("#bluetooth-main-container").hide();
        });

        // initialize nfc
        jQuery("nfc-tag-ndef-container h3").click(function (event) {
            if (stop) {
                event.stopImmediatePropagation();
                event.preventDefault();
                stop = false;
            }   
        });
        jQuery("#nfc-tag-ndef-container").accordion("destroy").accordion({
            header: "> div > h3",
            autoHeight: false
        });
        jQuery("nfc-nfcpeer h3").click(function (event) {
            if (stop) {
                event.stopImmediatePropagation();
                event.preventDefault();
                stop = false;
            }
        });
        jQuery("#nfc-nfcpeer").accordion("destroy").accordion({
            header: "> div > h3",
            autoHeight: false
        });
        jQuery("#nfc-tag-NDEF-support").bind("change", function () {
            isSupportNDEF = jQuery("#nfc-tag-NDEF-support").val();
            if (isSupportNDEF === "Yes") {
                jQuery("#nfc-tag-ndef-container").fadeIn();
                jQuery("#nfc-tag-raw-container").hide();
            } else {
                jQuery("#nfc-tag-ndef-container").hide();
                jQuery("#nfc-tag-raw-container").fadeIn();
            }
        });
        jQuery("#nfc-type").bind("change", function () {
            type = jQuery("#nfc-type").val();
            if (type === "Tag") {
                jQuery("#nfc-nfctag").fadeIn();
                jQuery("#nfc-nfcpeer").hide();
            } else {
                jQuery("#nfc-nfctag").hide();
                jQuery("#nfc-nfcpeer").fadeIn();
            }
            elementEnableDisableSetting();
        });
        jQuery("#nfc-power").bind("change", function () {
            var status;
            status = jQuery("#nfc-power").val() === "On" ? true : false;
            if (status)
                jQuery("#nfc").show();
            event.trigger("nfc-power-setting", [status]);
        });
        jQuery("#nfc-polling").bind("change", function () {
            var status;
            status = jQuery("#nfc-polling").val() === "On" ? true : false;
            event.trigger("nfc-polling-setting", [status]);
        });
        jQuery("#nfc-attach").bind("click", function () {
            var type, isAttached;
            isAttached = jQuery("#nfc-attach").children().text() === "Attach" ? true : false;
            jQuery("#nfc-attach-msg").text("\xa0");

            if (!_polling && isAttached) {
                jQuery("#nfc-attach-msg").text("Polling:Off, attach won't work");
                return;
            }
            type = jQuery("#nfc-type").val();
            event.trigger("nfc-attach-setting", [type, isAttached]);
        });
        jQuery("#nfc-peer-send").bind("click", function () {
            jQuery("#nfc-peer-send-msg").text("\xa0");
            if (!_isConnected) {
                jQuery("#nfc-peer-send-msg").text("Disconnected. Send won't work");
                return;
            }
            db.saveObject(_NFC_PEER, _peerNDEF);
            event.trigger("nfc-peer-sending-ndef", []);
        });
    });
}

function _btRender() {
    var devicesHTML, btHtmlContent = "";

    utils.forEach(_btSimulatedDevs, function (item) {
        var uuidsHTML = "", firstService = null;

        utils.forEach(item.services, function (s, index) {
            if (!firstService) {
                firstService = s;
            }
            uuidsHTML += '<option value="' + index + '">' + s.name + '</option>';
        });

        devicesHTML = _btDeviceTemplate.replace(/#name/g, item.name)
        .replace(/#address/g, item.address)
        .replace(/#class-major/, item.deviceClass.majorName)
        .replace(/#class-minor/, item.deviceClass.minorName)
        .replace(/#class-service/, item.deviceClass.servicesName.join(","))
        .replace(/#bonded/, "No")
        .replace(/#trusted/, item.isTrusted ? "Yes" : "No")
        .replace(/#connected/, "No")
        .replace(/#uuids/, uuidsHTML)
        .replace(/#service-uuid/, firstService.uuid)
        .replace(/#service-protocol/, firstService.protocol)
        .replace(/#service-state/, firstService.state || "CLOSED")
        .replace(/#id/g, item.address.replace(/:/g, ""));

        btHtmlContent += devicesHTML;
    });

    $("#network-bt-box").accordion("destroy");
    $("#network-bt-box").html(btHtmlContent).accordion({
        active : false,
        collapsible : true,
        autoHeight : false
    });
}
function _btRemove(index) {
    delete _btSimulatedDevs[index];
    db.saveObject("bt-simulated-devices", _btSimulatedDevs);
    event.trigger("bt-simulated-devices-changed", []);
    _btRender();
}

module.exports = {
    panel: {
        domId: "network-container",
        collapsed: true,
        pane: "left",
        titleName: "Network Management",
        display: true
    },
    initialize: function () {
        _initializeElements();

        // Events for nfc module
        event.on("nfc-power-changed", function (status) {
            _powered = status;
            if (_powered === true) {
                $("#nfc-power").val("On");
            } else {
                $("#nfc-power").val("Off");
            }
            elementEnableDisableSetting({power: status});
        });
        event.on("nfc-polling-changed", function (status) {
            _polling = status;
            if (_polling === true) {
                $("#nfc-polling").val("On");
            } else {
                $("#nfc-polling").val("Off");
            }
            elementEnableDisableSetting();
        });
        event.on("nfc-connectedState-changed", function (state) {
            var i, type, isSupportedNDEF, str, bytes = [];
            _isConnected = state;
            elementEnableDisableSetting({connectedState: state});
            type = jQuery("#nfc-type").val();
            if (state) {
                jQuery("#nfc-attach").children().text("Detach");
                jQuery("#nfc-tag-connection").text("Connected");
                jQuery("#nfc-peer-connection").text("Connected");
                if (type === "Tag") {
                    isSupportedNDEF = jQuery("#nfc-tag-NDEF-support").val() === "Yes" ? true : false;
                    if (isSupportedNDEF) {
                        _tagNDEF.type = jQuery("#nfc-tag-type").val();
                        db.saveObject(_NFC_TAG, _tagNDEF);
                    } else {
                        _tagRaw.type = jQuery("#nfc-tag-type").val();
                        str = jQuery("#nfc-raw-data").val();
                        for (i = 0; i < str.length; i++) {
                            bytes.push(str.charCodeAt(i));
                        }
                        _tagRaw.rawData = bytes;
                        db.saveObject(_NFC_TAG, _tagRaw);
                    }
                    event.trigger("nfc-tag-send", [true]);
                } else {
                    event.trigger("nfc-peer-send", [true]);
                }
            } else {
                jQuery("#nfc-attach").children().text("Attach");
                jQuery("#nfc-tag-connection").text("Disconnected");
                jQuery("#nfc-peer-connection").text("Disconnected");
                jQuery("#nfc-output").text("");
                jQuery("#nfc-output-table").hide();
                if (type === "Tag") {
                    event.trigger("nfc-tag-send", [false]);
                } else {
                    event.trigger("nfc-peer-send", [false]);
                }
            }
        });
        event.on("nfc-output-msg", function () {
            var msg;
            msg = db.retrieve(_NFC_OUTPUT_MESSAGE);
            jQuery("#nfc-output").text(msg);
            jQuery("#nfc-output-table").show();
        });

        // Events for bluetooth module
        event.on("bluetoothPowerState", function (state) {
            if (state) {
                $("#bluetooth-radio1").click();
            } else {
                $("#bluetooth-radio2").click();
            }
        });
        event.on("bt-adapter-name-changed", function (name) {
            $("#bt-adapter-name").text(name);
        });
        event.on("bt-adapter-power-changed", function (state) {
            if (state) {
                $("#bt-adapter-power").text("On");
            } else {
                $("#bt-adapter-power").text("Off");
            }
        });
        event.on("bt-adapter-visible-changed", function (state) {
            if (state) {
                $("#bt-adapter-visible").text("On");
            } else {
                $("#bt-adapter-visible").text("Off");
            }
        });
        event.on("bt-device-bonded-changed", function (addr, isBonded) {
            var str = "No";
            if (isBonded) {
                str = "Yes";
            }
            jQuery("#bonded-" + addr.replace(/:/g, "")).html(str);
        });
        event.on("bt-device-connected-changed", function (addr, isConnected) {
            var str = "No";
            if (isConnected) {
                str = "Yes";
            }
            jQuery("#connected-" + addr.replace(/:/g, "")).html(str);
        });
        event.on("bt-service-state-changed", function (addr, uuid, state) {
            var str = "CLOSED";
            if (state) {
                str = "OPEN";
            }
            _btSimulatedDevs[addr].services[uuid].state = str;
            jQuery("#service-state-" + addr.replace(/:/g, "")).html(str);
        });
        event.on("bt-service-write-msg", function (addr, uuid, data) {
            var msg = "", uuidNow;
            utils.forEach(data, function (char) {
                msg += String.fromCharCode(char);
            });
            uuidNow = jQuery("#network-bt-uuid-" + addr.replace(/:/g, "")).html();
            if (uuidNow === uuid) {
                jQuery("#service-receive-textarea-" + addr.replace(/:/g, "")).html(msg);
            }
        });
        $("#bt-adapter-name").text(db.retrieveObject("tizen1-db-bluetooth_adapter-name") || "Tizen BT Adapter");
        _btDeviceTemplate = $("#network-bt-template").html();
        $("#network-bt-box").empty();
        btNodes = jQuery("#network-bt-device-select");
        btNodes.html("");
        utils.forEach(btdevices, function (item, index) {
            btNodes.append(utils.createElement("option", {
                "value": index,
                "innerText": item.name
            }));
        });

        jQuery("#network-bt-nearby-btn").click(function () {
            var index;
            index = jQuery("#network-bt-device-select").val();
            if (_btSimulatedDevs[index]) {
                return;
            }
            _btSimulatedDevs[index] = btdevices[index];
            db.saveObject("bt-simulated-devices", _btSimulatedDevs);
            event.trigger("bt-simulated-devices-changed", []);
            _btRender();
        });
        $(".network-bt-remove-btn").live("click", function () {
            _btRemove(this.id);
        });
        $(".network-bt-send-btn").live("click", function () {
            var msg = jQuery("#service-transfer-textarea-" + this.id.replace(/:/g, "")).val(),
            uuid = jQuery("#network-bt-uuid-" + this.id.replace(/:/g, "")).html();
            event.trigger("bt-service-rawdata-received", [this.id, uuid, msg]);
        });
        $(".network-bt-service-select").live("change", function () {
            var uuid = this.children[this.selectedIndex].value,
            index = this.id,
            addr,
            service;
            addr = index.replace(/:/g, "");
            service = _btSimulatedDevs[index].services[uuid];
            jQuery("#network-bt-uuid-" + index.replace(/:/g, "")).html(service.uuid);
            jQuery("#network-bt-protocol-" + index.replace(/:/g, "")).html(service.protocol);
            jQuery("#service-state-" + index.replace(/:/g, "")).html(service.state || "CLOSED");
            jQuery("#service-transfer-textarea-" + addr).val("");
            jQuery("#service-receive-textarea-" + addr).html("");
        });
    }
};

});
define('ripple/ui/themes', function (require, exports, module) {
/*
 *  Copyright 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module.exports = ["dark", "light"];

});
require('ripple/ui').register('omnibar');require('ripple/bootstrap').bootstrap();