here it is ... the upload-api, script-server, js2 (javascript phase2) branch merge...
authorMichael Dale <dale@users.mediawiki.org>
Tue, 14 Jul 2009 23:52:14 +0000 (23:52 +0000)
committerMichael Dale <dale@users.mediawiki.org>
Tue, 14 Jul 2009 23:52:14 +0000 (23:52 +0000)
Here is a short overview of changes and associated default configuration variables (most everything is off by default) also see ~soon to be updated~: http://www.mediawiki.org/wiki/Media_Projects_Overview

= Upload Improvements =
==Upload API ==
* Based on the early work of Bryan Tong and others it adds the upload option to the api.
* We rewrite Special:Upload page to include use the new refactoring
* Added in token checks in both the SpecialUpload.php page so avoids DOS / xss copy-by-url JavaScript based cross site POST file submissions

== Copy by URL==
$wgAllowCopyUploads = false;
* http class rewrite includes a new http background download see: includes/HttpFunctions.php

* spins off a php process that calls: maintenance/http_session_download.php
* pushes updates to the session and gives the user a progress bar on http copy uploads from other server progress (using js2 upload interface) (if not using the js2 upload interface it does the request in-place but the download is limited to the php ini timeout time)

== Firefogg ==
* Firefogg enables resumable upload by chunks
* progress indicators and conditional invokation (js2 system)
* and of-course client side transcoding.

= Script Server =
$wgEnableScriptLoader = false;
* off by default if $wgEnableScriptLoader is turned on script files are grouped, gziped, cached etc.
for more info see: http://www.mediawiki.org/wiki/Extension:ScriptLoader

* Includes some early skin js include fixes (skin/script system still lots of love)
* Includes a "javascript class autoloader" this is packaged into mwEmbed so that the mwEmbed library can work in stand alone mode (while retaining localization and script serving) (one such application is the make page for firefogg.org : http://www.firefogg.org/make/index.html  )
* The file that contains the autojavascript loading classes is: js2/php/jsAutoloadLocalClasses.php
* One can use this auto class loading dependency system with extensions and add-ons but I need to better document that.

= js2 system  / mwEmbed=
$wgEnableJS2system = false

* includes initial rewrite towards more jquery based javascript code
* especially for the Special:Upload page.
* Also the edit page include support for the "add-media-wizard"
* includes dependency loader for javascript that optionally takes advantage of the script-loader
* remote embedding of javascript interfaces (like embedding video, or commons media searching)

* $wgDebugJavaScript = false; .. .this variable lets you always get "always fresh javascript". When used with the script-loader it does not minify the script-loader output.

= mwEmbed =
* Will commit a separate patch to oggHandler that conditionally outputs  <video tag> to use the new javascript video player.
** mv_embed player includes: play-head, volume control, remote embedding, oggz-chop support across plugins.
* add-media-wizard adds easy inserts of media to pages (with import)

== jQuery==
* we include a base install of jQuery, jQuery ui and some plugins.
* all the javascript classes are in the scriptloader so its easy to load any set of jquery ui components that you may need using the script-server. You get a callback so you can then execute js with dependencies loaded.

== other stuff ==
there is a bit more code in js2 that pertains to sequence editing, timed text display and basic image editing. We include a base import of pixastic-lib & pixastic-editor... will work with the pixastic developer to try and ensure upstream compatibility on our usage of the library for in-browser photo and sequence manipulation.

533 files changed:
RELEASE-NOTES
config/index.php
docs/upload.txt
includes/AutoLoader.php
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/HttpFunctions.php
includes/OutputPage.php
includes/QueryPage.php
includes/Skin.php
includes/SkinTemplate.php
includes/StreamFile.php
includes/api/ApiBase.php
includes/api/ApiFormatJson.php
includes/api/ApiMain.php
includes/api/ApiUpload.php [new file with mode: 0644]
includes/filerepo/FSRepo.php
includes/specials/SpecialUpload.php
includes/upload/UploadBase.php [new file with mode: 0644]
includes/upload/UploadFromChunks.php [new file with mode: 0644]
includes/upload/UploadFromFile.php [new file with mode: 0644]
includes/upload/UploadFromStash.php [new file with mode: 0644]
includes/upload/UploadFromUrl.php [new file with mode: 0644]
js2/README [new file with mode: 0644]
js2/editPage.js [new file with mode: 0644]
js2/mwEmbed/README [new file with mode: 0644]
js2/mwEmbed/binPlayers/cortado/README [new file with mode: 0644]
js2/mwEmbed/binPlayers/cortado/cortado.jar [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/LICENSE.txt [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/README.txt [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.js [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.min.js [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc4.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.1.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta5.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta7.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.1.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/flowplayer/flowplayer.pseudostreaming-3.0.0-beta3.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/LICENSE.txt [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/README.txt [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/hxmdct.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/omtkp.swf [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/Player.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/EndOfOggStreamError.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/LogicalOggStream.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPacket.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPage.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/UncachedUrlStream.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/BitByteArray.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/HuffmanNode.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/AudioPacket.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CodeBook.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CommentHeader.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor0.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor1.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/IdentificationHeader.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Look.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping0.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mdct.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mode.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue2.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/SetupHeader.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Util.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisSound.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisStream.as [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/haXe/build.hxml [new file with mode: 0644]
js2/mwEmbed/binPlayers/omtk-fx/src/haXe/org/omtk/vorbis/MdctHX.hx [new file with mode: 0644]
js2/mwEmbed/example_usage/Add_Media_Wizard.html [new file with mode: 0644]
js2/mwEmbed/example_usage/Firefogg_Make_Advanced.html [new file with mode: 0644]
js2/mwEmbed/example_usage/Firefogg_Make_Simple.html [new file with mode: 0644]
js2/mwEmbed/example_usage/Firefogg_ReWriteForm.php [new file with mode: 0644]
js2/mwEmbed/example_usage/Player_Remote_Content_ogg_flv.html [new file with mode: 0644]
js2/mwEmbed/example_usage/Player_Simple_Video_Tag.html [new file with mode: 0644]
js2/mwEmbed/example_usage/Player_Themable.html [new file with mode: 0644]
js2/mwEmbed/example_usage/Player_Timed_Text.html [new file with mode: 0644]
js2/mwEmbed/example_usage/README [new file with mode: 0644]
js2/mwEmbed/example_usage/Sequence_Editor.html [new file with mode: 0644]
js2/mwEmbed/example_usage/SequencerPlayer_Seeking.html [new file with mode: 0644]
js2/mwEmbed/example_usage/SequencerPlayer_Simple.html [new file with mode: 0644]
js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-cs.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-ru.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/princess_iron_fan-cs.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/sample_eclipse.jpg [new file with mode: 0644]
js2/mwEmbed/example_usage/media/sample_fish.jpg [new file with mode: 0644]
js2/mwEmbed/example_usage/media/sample_fish_text_en.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/sample_fish_text_es.srt [new file with mode: 0644]
js2/mwEmbed/example_usage/media/sample_jellyfish.jpg [new file with mode: 0644]
js2/mwEmbed/example_usage/media/sample_smil.xml [new file with mode: 0644]
js2/mwEmbed/example_usage/media/simple_smil_example_script_loader.html [new file with mode: 0644]
js2/mwEmbed/jquery/jquery-1.3.2.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery-1.3.2.min.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/AUTHORS.txt [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/GPL-LICENSE.txt [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/MIT-LICENSE.txt [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/ChangeLog.txt [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/META.json [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/docs/index.html [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.min.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.pack.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/test/index.html [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.min.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.pack.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.zip [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/jsdiff/jsdiff.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/qunit/testrunner.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/qunit/testsuite.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/external/simulate/jquery.simulate.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_65_ffffff_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_dadada_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_ffffff_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_222222_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_2e83ff_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_454545_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_888888_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_cd0a0a_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.accordion.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.all.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.base.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.core.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.datepicker.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.dialog.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.progressbar.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.resizable.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.slider.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.tabs.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.theme.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_217bc0_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_2e83ff_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_469bdd_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_6da8d5_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_cd0a0a_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_d8e7f3_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_f9bd01_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/jquery-ui-1.7.1.custom.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_222222_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_2e83ff_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_454545_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_888888_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_cd0a0a_256x240.png [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/jquery-ui-1.7.1.custom.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.accordion.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.all.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.base.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.core.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.datepicker.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.dialog.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.progressbar.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.resizable.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.slider.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.tabs.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.theme.css [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.blind.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.bounce.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.clip.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.core.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.drop.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.explode.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.fold.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.highlight.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.pulsate.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.scale.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.shake.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.slide.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.transfer.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/jquery-ui-i18n.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ar.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-bg.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ca.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-cs.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-da.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-de.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-el.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-eo.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-es.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fa.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fi.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fr.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-he.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hr.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hu.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hy.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-id.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-is.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-it.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ja.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ko.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-lt.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-lv.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ms.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-nl.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-no.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-pl.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-pt-BR.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ro.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ru.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sk.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sl.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sq.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sr-SR.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sr.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sv.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-th.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-tr.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-uk.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-zh-CN.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-zh-TW.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/jquery-ui-1.7.1.custom.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.accordion.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.core.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.datepicker.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.dialog.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.draggable.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.droppable.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.progressbar.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.resizable.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.selectable.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.slider.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.sortable.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.tabs.js [new file with mode: 0644]
js2/mwEmbed/jquery/jquery.ui-1.7.1/version.txt [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/date.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/images/cut.png [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/images/door.png [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/images/page_white_copy.png [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/images/page_white_delete.png [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/images/page_white_edit.png [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/images/page_white_paste.png [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/indicator.gif [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.autocomplete.css [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.autocomplete.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.bgiframe.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.contextMenu.css [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.contextMenu.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.cookie.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.datePicker.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.dimensions.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.highlight.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.hoverIntent.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.json-1.3.js [new file with mode: 0755]
js2/mwEmbed/jquery/plugins/jquery.pngFix.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.secureEvalJSON.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jquery.timers.js [new file with mode: 0644]
js2/mwEmbed/jquery/plugins/jqueryContextMenu.html [new file with mode: 0644]
js2/mwEmbed/jsScriptLoader.php [new file with mode: 0644]
js2/mwEmbed/libAddMedia/mediaWikiUploadHelper.OFF.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/mvAdvFirefogg.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/mvFirefogg.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/remoteSearchDriver.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js [new file with mode: 0644]
js2/mwEmbed/libAddMedia/seqRemoteSearchDriver.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/css/Jcrop.gif [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/css/jquery.Jcrop.css [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/crop.php [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/demos.css [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/flowers.jpg [new file with mode: 0755]
js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sago.jpg [new file with mode: 0755]
js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.jpg [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial1.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial2.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial3.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial4.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial5.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/index.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/js/jquery.Jcrop.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/Jcrop/js/jquery.Jcrop.min.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/css/colorpicker.css [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/css/layout.css [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/Thumbs.db [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/blank.gif [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_background.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hex.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_b.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_h.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_s.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_indic.gif [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_overlay.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_b.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_g.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_r.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_select.gif [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_submit.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_background.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_hex.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_b.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_h.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_s.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_indic.gif [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_b.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_g.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_r.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/custom_submit.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/select.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/select2.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/images/slider.png [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/index.html [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/js/colorpicker.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/js/eye.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/js/layout.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/colorpicker/js/utils.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/mvClipEdit.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-editor/editor.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.all.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.css [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-editor/ui.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-editor/uidata.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/blend.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/blur.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/blurfast.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/brightness.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/coloradjust.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/crop.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/desaturate.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/edges.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/edges2.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/emboss.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/fliph.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/flipv.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/glow.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/histogram.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/hsl.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/invert.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/laplace.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/lighten.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/mosaic.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/noise.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/pointillize.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/posterize.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/removenoise.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/sepia.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/sharpen.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/solarize.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/actions/unsharpmask.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/editor.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.all.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.css [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/ui.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/uidata.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic.core.js [new file with mode: 0644]
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic.jquery.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/embedVideo.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/flashEmbed.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/genericEmbed.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/htmlEmbed.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/javaEmbed.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/nativeEmbed.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/omtkEmbed.js [new file with mode: 0644]
js2/mwEmbed/libEmbedVideo/vlcEmbed.js [new file with mode: 0644]
js2/mwEmbed/libSequencer/mvPlayList.js [new file with mode: 0644]
js2/mwEmbed/libSequencer/mvSequencer.js [new file with mode: 0644]
js2/mwEmbed/libSequencer/mvTimedEffectsEdit.js [new file with mode: 0644]
js2/mwEmbed/libTimedText/mvTextInterface.js [new file with mode: 0644]
js2/mwEmbed/mv_embed.js [new file with mode: 0644]
js2/mwEmbed/php/cortado_iframe.php [new file with mode: 0644]
js2/mwEmbed/php/jsAutoloadLocalClasses.php [new file with mode: 0644]
js2/mwEmbed/php/languages/mwEmbed.i18n.php [new file with mode: 0644]
js2/mwEmbed/php/maintenance/mergeJavascriptMsg.php [new file with mode: 0644]
js2/mwEmbed/php/minify/JSMin.php [new file with mode: 0644]
js2/mwEmbed/php/mv_embed_iframe.php [new file with mode: 0644]
js2/mwEmbed/php/noMediaWikiConfig.php [new file with mode: 0644]
js2/mwEmbed/php/script-cache/README [new file with mode: 0755]
js2/mwEmbed/skins/mvpcf/ie_styles.css [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/Button_add_media.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/Jcrop.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/archive_org_bw.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/archive_org_color.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/box_layout_icon.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/box_layout_icon_dark.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/button_grey_left.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/button_grey_right.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/button_play.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/button_subscribe.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/button_to_clipboard.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/carousel_left.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/carousel_right.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/carousel_top_left.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/carousel_top_right.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/clip_thumb_overlay.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/embed_arrow.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_bw.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_color.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/flash_carousel.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/flash_icon_bw.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/flash_icon_color.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/flash_player.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/font_truetype.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/html_page_icon.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/ico_mail.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/ico_rss.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/image_layout_left.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/image_layout_right.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/image_thumb_overlay.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/img1.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/img2.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/kaltura_logo_sm.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/list_layout_icon.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/list_layout_icon_dark.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/loading_ani.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/loading_bar_ani.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/logo.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/logo2.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/metavid_logo_100.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/opened.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/other_results_bg.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/other_results_top.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/other_results_top2.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/pbar-ani.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/pelosi.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/person1.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_big_play_button.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_bottom_left.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_bottom_right.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_button_cc.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_button_fullscreen.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_button_options.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_button_pause.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_button_play.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_options_bg.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_options_bottom.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_options_top.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_seek_bg_loaded.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_seek_bg_normal.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_seek_left.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_seek_right.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_slider.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_video.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_video_options_bg.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_volume_seek.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_volume_tag.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/player_volume_tag_off.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/plugin.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/plugin_disabled.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/plugin_edit.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_17.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_80.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_tab.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/cc-flickr.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/combined_tab.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_logo_17.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_tab.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_logo_17.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_tab.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_17.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_80.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_tab.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/search_suggest_bg.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/search_suggest_bottom.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/search_suggest_top.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/selector.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/slider_handle.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/slider_handle_green.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/slider_handle_red.gif [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/sound_music_icon-60.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/sound_music_icon-80.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/sound_music_icon.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24_over.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop_over.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale_over.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/stock_icon_over.xcf [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/tab-bg.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/thumb1.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/thumb2.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/thumb3.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/thumb4.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/tracker.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/transition_icon.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/transparent_bg.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/ui-bg_diagonals-thick_20_666666_40x40.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/uni_edit_bw.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/uni_edit_color.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/vid_default_thumb.jpg [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/vid_next_sm.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/vid_prev_sm.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/images/wiki_commons_logo_80.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/mv_sequence.css [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/styles.css [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/transition_images/fade_crossfade.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/transition_images/fade_fadeFromColor.png [new file with mode: 0644]
js2/mwEmbed/skins/mvpcf/transition_images/transition_wipe.png [new file with mode: 0644]
js2/remoteMwEmbed.js [new file with mode: 0644]
js2/uploadPage.js [new file with mode: 0644]
languages/messages/MessagesEn.php
languages/messages/MessagesLzh.php
languages/messages/MessagesTk.php
languages/messages/MessagesYue.php
languages/messages/MessagesZh_hans.php
languages/messages/MessagesZh_hant.php
maintenance/http_session_download.php [new file with mode: 0644]
mwScriptLoader.php [new file with mode: 0644]
skins/MonoBook.php
skins/Standard.php
skins/common/upload.js
skins/common/wikibits.js
skins/monobook/KHTMLFixes.css [new file with mode: 0644]

index bda0031..bcc2c47 100644 (file)
@@ -52,9 +52,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
   functionality is now available via $wgLocalisationCacheConf.
 * $wgMessageCache->addMessages() is deprecated. Messages added via this 
   interface will not appear in Special:AllMessages.
-* $wgRegisterInternalExternals can be used to record external links pointing 
-  to same server
-* $wgHtml5 outputs an HTML 5 doctype instead of XHTML 1.0 Transitional.
 
 === New features in 1.16 ===
 
@@ -116,13 +113,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * Added a feature to allow per-article process pool size control for the parsing 
   task, to limit resource usage when the cache for a heavily-viewed article is
   invalidated. Requires an external daemon. 
-* Leading > is now syntax for <blockquote>.
-* (bug 19576) Moved id attribues from anchors accompanying section headers to
-  the section headers themselves, removing the redundant anchor elements.
-* Parser::setFunctionTagHook now can be used to add a new tag which is parsed at
-  preprocesor level.
-* Added $wgShowArchiveThumbnails, allowing sysadmins to disable thumbnail 
-  display for old versions of images.
 
 === Bug fixes in 1.16 ===
 
@@ -242,14 +232,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
    extension (since 0.ext is perfectly valid)
 * (bug 19468) Enotif preferences are now only displayed when they are turned on
 * (bug 19442) Show/hide options on watchlist only work once
-* (bug 19602) PubMed Magic links now use updated NIH url
-* (bug 19637) externallinks have links to self
-* Don't load Opera 9.5 RTL fixes for Opera 9.6
-* Remove five-year-old KHTMLFixes.css, which is unlikely to be relevant anymore
-  and was causing problems.
-* Removed repetition of URIs in the title attributes of external links.
-* (bug 19693) User name is now escaped in "Contributions for ..." link on
-  Special:BlockIP
 * (bug 19571) Override buildConcat for SQLite.
 * Log in and log out links no longer return to page view when clicked from
   history view, edit page, or something similar
@@ -294,8 +276,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 19423) The initial file description page used caption in user lang
   rather than UI lang
 * Added snippet field to list=search output
-* (bug 17809) Add number of users in user groups to meta=siteinfo
-* (bug 18533) Add readonly reason to readonly exception
 * (bug 19528) Added XSLT parameter to API queries in format=xml
 * (bug 19040) Fix prependtext and appendtext in combination with section 
   parameter in action=edit
@@ -322,7 +302,6 @@ changes to languages because of MediaZilla reports.
 * (bug 19080) Added ăâîşţșțĂÂÎŞŢȘȚ to Romanion (ro) linktrail
 * (bug 19286) Correct commafying function in Polish (pl)
 * (bug 19441) Updated date formatting for Lithuanian
-* (bug 19630) Added ÄäÇçĞğŇňÖöŞşÜüÝýŽž to Turkmen (tk) linktrail
 
 == Compatibility ==
 
index 3a82ed7..0e8ab0d 100644 (file)
@@ -516,6 +516,24 @@ if( !( $conf->turck || $conf->eaccel || $conf->apc || $conf->xcache ) ) {
                cannot use these for object caching.</li>' );
 }
 
+$conf->phpCliPath = false;
+$phpClilocations = array_merge(
+       array(
+               "/usr/bin",
+               "/usr/local/bin",
+               "/opt/csw/bin",
+               "/usr/gnu/bin",
+               "/usr/sfw/bin" ),
+       explode( PATH_SEPARATOR, getenv( "PATH" ) ) );
+$phpClinames = array( "php", "php.exe" );
+foreach ($phpClilocations as $loc) {
+       $exe = locate_executable($loc, $phpClinames);
+       if ($exe !== false) {
+               $conf->phpCliPath= $exe;
+               break;
+       }
+}
+
 $conf->diff3 = false;
 $diff3locations = array_merge(
        array(
@@ -1953,6 +1971,8 @@ if ( \$wgCommandLineMode ) {
 
 \$wgDiff3 = \"{$slconf['diff3']}\";
 
+\$wgPhpCliPath = \"{$slconf['phpCliPath']}\";
+
 # When you make changes to this configuration file, this will make
 # sure that cached pages are cleared.
 \$wgCacheEpoch = max( \$wgCacheEpoch, gmdate( 'YmdHis', @filemtime( __FILE__ ) ) );
index e92ca78..7c20c69 100644 (file)
@@ -21,6 +21,7 @@ wfSpecialUpload
                                        empty(mFileSize)
                                        getTitle()
                                        checkOverwrite()
+                                       fetchFile()
                                        verifyFile()
                                                checkMacBinary()
                                        wfRunHooks(UploadVerification)
index 6174b36..f382d8f 100644 (file)
@@ -114,6 +114,8 @@ $wgAutoloadLocalClasses = array(
        'IndexPager' => 'includes/Pager.php',
        'Interwiki' => 'includes/Interwiki.php',
        'IP' => 'includes/IP.php',
+       'JSMin' => 'js2/mwEmbed/php/minify/JSMin.php',
+       'jsScriptLoader' => 'js2/mwEmbed/jsScriptLoader.php',
        'Job' => 'includes/JobQueue.php',
        'LCStore_DB' => 'includes/LocalisationCache.php',
        'LCStore_CDB' => 'includes/LocalisationCache.php',
@@ -220,6 +222,11 @@ $wgAutoloadLocalClasses = array(
        'TransformParameterError' => 'includes/MediaTransformOutput.php',
        'TurckBagOStuff' => 'includes/BagOStuff.php',
        'UnlistedSpecialPage' => 'includes/SpecialPage.php',
+       'UploadBase' => 'includes/upload/UploadBase.php',
+       'UploadFromStash' => 'includes/upload/UploadFromStash.php',
+       'UploadFromFile' => 'includes/upload/UploadFromFile.php',
+       'UploadFromUrl' => 'includes/upload/UploadFromUrl.php',
+       'UploadFromChunks' => 'includes/upload/UploadFromChunks.php',
        'User' => 'includes/User.php',
        'UserArray' => 'includes/UserArray.php',
        'UserArrayFromResult' => 'includes/UserArray.php',
@@ -317,6 +324,7 @@ $wgAutoloadLocalClasses = array(
        'ApiUnblock' => 'includes/api/ApiUnblock.php',
        'ApiUndelete' => 'includes/api/ApiUndelete.php',
        'ApiUserrights' => 'includes/api/ApiUserrights.php',
+       'ApiUpload' => 'includes/api/ApiUpload.php',
        'ApiWatch' => 'includes/api/ApiWatch.php',
        'Services_JSON' => 'includes/api/ApiFormatJson_json.php',
        'Services_JSON_Error' => 'includes/api/ApiFormatJson_json.php',
@@ -352,7 +360,7 @@ $wgAutoloadLocalClasses = array(
        'PostgresField' => 'includes/db/DatabasePostgres.php',
        'ResultWrapper' => 'includes/db/Database.php',
        'SQLiteField' => 'includes/db/DatabaseSqlite.php',
-       
+
        'DatabaseIbm_db2' => 'includes/db/DatabaseIbm_db2.php',
        'IBM_DB2Field' => 'includes/db/DatabaseIbm_db2.php',
        'IBM_DB2SearchResultSet' => 'includes/SearchIBM_DB2.php',
@@ -550,6 +558,7 @@ $wgAutoloadLocalClasses = array(
        'WantedFilesPage' => 'includes/specials/SpecialWantedfiles.php',
        'WantedPagesPage' => 'includes/specials/SpecialWantedpages.php',
        'WantedTemplatesPage' => 'includes/specials/SpecialWantedtemplates.php',
+       'WhatLinksHerePage' => 'includes/specials/SpecialWhatlinkshere.php',
        'WikiImporter' => 'includes/Import.php',
        'WikiRevision' => 'includes/Import.php',
        'WithoutInterwikiPage' => 'includes/specials/SpecialWithoutinterwiki.php',
@@ -571,6 +580,39 @@ $wgAutoloadLocalClasses = array(
 
 );
 
+//autoloader for javascript files (path is from the mediawiki folder
+global $wgJSAutoloadLocalClasses;
+$wgJSAutoloadLocalClasses = array(
+       'ajax' =>  'skins/common/ajax.js',
+    'ajaxwatch' => 'skins/common/ajaxwatch.js',
+    'allmessages' => 'skins/common/allmessages.js',
+       'block' => 'skins/common/block.js',
+       'changepassword' => 'skins/common/changepassword.js',
+       'diff' => 'skins/common/diff.js',
+       'edit' => 'skins/common/edit.js',
+       'enhancedchanges.js' => 'skins/common/enhancedchanges.js',
+       'history' => 'skins/common/history.js',
+       'IEFixes' => 'skins/common/IEFixes.js',
+       'metadata' => 'skins/common/metadata.js',
+       'mwsuggest' => 'skins/common/mwsuggest.js',
+       'prefs' => 'skins/common/prefs.js',
+       'preview' => 'skins/common/preview.js',
+       'protect' => 'skins/common/protect.js',
+       'rightclickedit' => 'skins/common/rightclickedit.js',
+       'sticky'        => 'skins/common/sticky.js',
+       'upload' => 'skins/common/upload.js',
+       'wikibits' => 'skins/common/wikibits.js',
+
+       //phase 2 javascript:
+       'uploadPage' => 'js2/uploadPage.js',
+       'editPage'      =>      'js2/editPage.js',
+);
+
+//Include the js2 autoLoadClasses
+//@@todo move jsAutoloadLocalClasses.php to post Setup so we have default values and can check the $wgEnableJS2system var
+$wgMwEmbedDirectory = "js2/mwEmbed/";
+require_once("$IP/js2/mwEmbed/php/jsAutoloadLocalClasses.php");
+
 class AutoLoader {
        /**
         * autoload - take a class name and attempt to load it
@@ -598,7 +640,7 @@ class AutoLoader {
                                }
                        }
                        if ( !$filename ) {
-                               if( function_exists( 'wfDebug' ) )      
+                               if( function_exists( 'wfDebug' ) )
                                        wfDebug( "Class {$className} not found; skipped loading\n" );
                                # Give up
                                return false;
index 0d52c13..288778c 100644 (file)
@@ -438,9 +438,11 @@ $wgSharedUploadDBname = false;
 $wgSharedUploadDBprefix = '';
 /** Cache shared metadata in memcached. Don't do this if the commons wiki is in a different memcached domain */
 $wgCacheSharedUploads = true;
-/** Allow for upload to be copied from an URL. Requires Special:Upload?source=web */
+/**
+* Allow for upload to be copied from an URL. Requires Special:Upload?source=web
+* timeout for Copy Uploads is set by wgAsyncHTTPTimeout & wgSyncHTTPTimeout
+*/
 $wgAllowCopyUploads = false;
-$wgCopyUploadTimeout = 30; // 30 seconds default timeout for upload-by-URL
 
 /**
  * Max size for uploads, in bytes.  Currently only works for uploads from URL
@@ -449,6 +451,25 @@ $wgCopyUploadTimeout = 30; // 30 seconds default timeout for upload-by-URL
  */
 $wgMaxUploadSize = 1024*1024*100; # 100MB
 
+
+/**
+* Enable firefogg support
+* add support for in-browser transcoding to ogg theora
+* add support for chunk uploads for large image files
+* add support for client side hash checks
+*
+* (requires the js2 code for the interface)
+*/
+$wgEnableFirefogg = true;
+
+
+/**
+ * enable oggz_chop support
+ * if enabled the mv_embed player will use temporal urls
+ * for helping with seeking with some plugin types
+ */
+$wgEnableTemporalOggUrls = false;
+
 /**
  * Point the upload navigation link to an external URL
  * Useful if you want to use a shared repository by default
@@ -483,7 +504,7 @@ $wgHashedSharedUploadDirectory = true;
  *
  * Please specify the namespace, as in the example below.
  */
-$wgRepositoryBaseUrl = "http://commons.wikimedia.org/wiki/Image:";
+$wgRepositoryBaseUrl = "http://commons.wikimedia.org/wiki/File:";
 
 #
 # Email settings
@@ -765,36 +786,33 @@ $wgMemCachedPersistent = false;
 /**@}*/
 
 /**
- * Set this to true to make a local copy of the message cache, for use in 
- * addition to memcached. The files will be put in $wgCacheDirectory. 
+ * Directory for local copy of message cache, for use in addition to memcached
  */
-$wgUseLocalMessageCache = false;
-
+$wgLocalMessageCache = false;
 /**
  * Defines format of local cache
  * true - Serialized object
  * false - PHP source file (Warning - security risk)
  */
 $wgLocalMessageCacheSerialized = true;
-
 /**
  * Localisation cache configuration. Associative array with keys:
  *     class:       The class to use. May be overridden by extensions.
  *
- *     store:       The location to store cache data. May be 'files', 'db' or 
- *                  'detect'. If set to "files", data will be in CDB files. If set 
- *                  to "db", data will be stored to the database. If set to 
- *                  "detect", files will be used if $wgCacheDirectory is set, 
+ *     store:       The location to store cache data. May be 'files', 'db' or
+ *                  'detect'. If set to "files", data will be in CDB files. If set
+ *                  to "db", data will be stored to the database. If set to
+ *                  "detect", files will be used if $wgCacheDirectory is set,
  *                  otherwise the database will be used.
  *
- *     storeClass:  The class name for the underlying storage. If set to a class 
+ *     storeClass:  The class name for the underlying storage. If set to a class
  *                  name, it overrides the "store" setting.
  *
- *     storeDirectory:  If the store class puts its data in files, this is the 
+ *     storeDirectory:  If the store class puts its data in files, this is the
  *                      directory it will use. If this is false, $wgCacheDirectory
  *                      will be used.
  *
- *     manualRecache:   Set this to true to disable cache updates on web requests. 
+ *     manualRecache:   Set this to true to disable cache updates on web requests.
  *                      Use maintenance/rebuildLocalisationCache.php instead.
  */
 $wgLocalisationCacheConf = array(
@@ -805,7 +823,6 @@ $wgLocalisationCacheConf = array(
        'manualRecache' => false,
 );
 
-
 # Language settings
 #
 /** Site language code, should be one of ./languages/Language(.*).php */
@@ -874,14 +891,6 @@ $wgDocType                 = '-//W3C//DTD XHTML 1.0 Transitional//EN';
 $wgDTD                         = 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd';
 $wgXhtmlDefaultNamespace       = 'http://www.w3.org/1999/xhtml';
 
-/**
- * Should we output an HTML 5 doctype?  This mode is still experimental, but
- * all indications are that it should be usable, so it's enabled by default.
- * If all goes well, it will be removed and become always true before the 1.16
- * release.
- */
-$wgHtml5 = true;
-
 /**
  * Permit other namespaces in addition to the w3.org default.
  * Use the prefix for the key and the namespace for the value. For
@@ -921,6 +930,20 @@ $wgMsgCacheExpiry  = 86400;
  */
 $wgMaxMsgCacheEntrySize = 10000;
 
+/**
+ * If true, serialized versions of the messages arrays will be
+ * read from the 'serialized' subdirectory if they are present.
+ * Set to false to always use the Messages files, regardless of
+ * whether they are up to date or not.
+ */
+$wgEnableSerializedMessages = true;
+
+/**
+ * Set to false if you are thorough system admin who always remembers to keep
+ * serialized files up to date to save few mtime calls.
+ */
+$wgCheckSerialized = true;
+
 /** Whether to enable language variant conversion. */
 $wgDisableLangConversion = false;
 
@@ -1433,7 +1456,6 @@ $wgAutoConfirmCount = 0;
  *   array( APCOND_ISIP, ip ), *OR*
  *   array( APCOND_IPINRANGE, range ), *OR*
  *   array( APCOND_AGE_FROM_EDIT, seconds since first edit ), *OR*
- *   array( APCOND_BLOCKED ), *OR*
  *   similar constructs defined by extensions.
  *
  * If $wgEmailAuthentication is off, APCOND_EMAILCONFIRMED will be true for any
@@ -1544,7 +1566,7 @@ $wgStyleVersion = '231';
 $wgUseFileCache = false;
 
 /** Directory where the cached page will be saved */
-$wgFileCacheDirectory = false; ///< defaults to "$wgCacheDirectory/html";
+$wgFileCacheDirectory = false; ///< defaults to "{$wgUploadDirectory}/cache";
 
 /**
  * When using the file cache, we can store the cached HTML gzipped to save disk
@@ -1918,7 +1940,6 @@ $wgRemoteUploads = false;
  * pages like page history, Special:Recentchanges, etc.
  */
 $wgDisableAnonTalk = false;
-
 /**
  * Do DELETE/INSERT for link updates instead of incremental
  */
@@ -1951,6 +1972,11 @@ $wgDiff3 = '/usr/bin/diff3';
  */
 $wgDiff = '/usr/bin/diff';
 
+/**
+ * Path to php-cli for spining up background php proccesses
+ */
+$wgPhpCliPath = '/usr/bin/php';
+
 /**
  * We can also compress text stored in the 'text' table. If this is set on, new
  * revisions will be compressed on page save if zlib support is available. Any
@@ -2041,6 +2067,7 @@ $wgNamespacesToBeSearchedHelp = array(
        NS_HELP           => true,
 );
 
+
 $wgUseOldSearchUI = true; // temp testing variable
 
 /**
@@ -2054,9 +2081,8 @@ $wgSearchEverythingOnlyLoggedIn = false;
  * Site notice shown at the top of each page
  *
  * This message can contain wiki text, and can also be set through the
- * MediaWiki:Sitenotice page, which will override this. You can also 
- * provide a separate message for logged-out users using the 
- * MediaWiki:Anonnotice page.
+ * MediaWiki:Sitenotice page. You can also provide a separate message for
+ * logged-out users using the MediaWiki:Anonnotice page.
  */
 $wgSiteNotice = '';
 
@@ -2150,16 +2176,6 @@ $wgMaxImageArea = 1.25e7;
  * Defaulting to 1 megapixel (1000x1000)
  */
 $wgMaxAnimatedGifArea = 1.0e6;
-/**
- * Browsers don't support TIFF inline generally...
- * For inline display, we need to convert to PNG or JPEG.
- * Note scaling should work with ImageMagick, but may not with GD scaling.
- *  // PNG is lossless, but inefficient for photos
- *  $wgTiffThumbnailType = array( 'png', 'image/png' );
- *  // JPEG is good for photos, but has no transparency support. Bad for diagrams.
- *  $wgTiffThumbnailType = array( 'jpg', 'image/jpeg' );
- */
-$wgTiffThumbnailType = false;
 /**
  * If rendered thumbnail files are older than this timestamp, they
  * will be rerendered on demand as if the file didn't already exist.
@@ -2190,14 +2206,10 @@ $wgIgnoreImageErrors = false;
  */
 $wgGenerateThumbnailOnParse = true;
 
-/**
- * Show thumbnails for old images on the image description page
- */
-$wgShowArchiveThumbnails = true;
-
-/** Whether or not to use image resizing */
+/** Obsolete, always true, kept for compatibility with extensions */
 $wgUseImageResize = true;
 
+
 /** Set $wgCommandLineMode if it's not set already, to avoid notices */
 if( !isset( $wgCommandLineMode ) ) {
        $wgCommandLineMode = false;
@@ -2216,7 +2228,7 @@ $wgPutIPinRC = true;
 /**
  * Recentchanges items are periodically purged; entries older than this many
  * seconds will go.
- * Default: 13 weeks = about three months
+ * Default: 13 weeks = about three monts
  */
 $wgRCMaxAge = 13 * 7 * 24 * 3600;
 
@@ -2363,9 +2375,6 @@ $wgExportAllowHistory = true;
  */
 $wgExportMaxHistory = 0;
 
-/**
- * Return distinct author list (when not returning full history)
- */
 $wgExportAllowListContributors = false ;
 
 /**
@@ -2374,33 +2383,21 @@ $wgExportAllowListContributors = false ;
  * pages linked to from the pages you specify. Since this number
  * can become *insanely large* and could easily break your wiki,
  * it's disabled by default for now.
- *
- * There's a HARD CODED limit of 5 levels of recursion to prevent a
- * crazy-big export from being done by someone setting the depth
- * number too high. In other words, last resort safety net.
  */
 $wgExportMaxLinkDepth = 0;
 
-/**
- * Whether to allow the "export all pages in namespace" option
- */
-$wgExportFromNamespaces = false;
 
 /**
- * Edits matching these regular expressions in body text
+ * Edits matching these regular expressions in body text or edit summary
  * will be recognised as spam and rejected automatically.
  *
  * There's no administrator override on-wiki, so be careful what you set. :)
  * May be an array of regexes or a single string for backwards compatibility.
  *
  * See http://en.wikipedia.org/wiki/Regular_expression
- * Note that each regex needs a beginning/end delimiter, eg: # or /
  */
 $wgSpamRegex = array();
 
-/** Same as the above except for edit summaries */
-$wgSummarySpamRegex = array();
-
 /** Similarly you can get a function to do the job. The function will be given
  * the following args:
  *   - a Title object for the article the edit is made on
@@ -2592,15 +2589,10 @@ $wgExtensionFunctions = array();
 $wgSkinExtensionFunctions = array();
 
 /**
- * Extension messages files.
- *
- * Associative array mapping extension name to the filename where messages can be 
- * found. The file should contain variable assignments. Any of the variables 
- * present in languages/messages/MessagesEn.php may be defined, but $messages
- * is the most common.
- *
- * Variables defined in extensions will override conflicting variables defined 
- * in the core.
+ * Extension messages files
+ * Associative array mapping extension name to the filename where messages can be found.
+ * The file must create a variable called $messages.
+ * When the messages are needed, the extension should call wfLoadExtensionMessages().
  *
  * Example:
  *    $wgExtensionMessagesFiles['ConfirmEdit'] = dirname(__FILE__).'/ConfirmEdit.i18n.php';
@@ -2610,7 +2602,13 @@ $wgExtensionMessagesFiles = array();
 
 /**
  * Aliases for special pages provided by extensions.
- * @deprecated Use $specialPageAliases in a file referred to by $wgExtensionMessagesFiles
+ * Associative array mapping special page to array of aliases. First alternative
+ * for each special page will be used as the normalised name for it. English
+ * aliases will be added to the end of the list so that they always work. The
+ * file must define a variable $aliases.
+ *
+ * Example:
+ *    $wgExtensionAliasesFiles['Translate'] = dirname(__FILE__).'/Translate.alias.php';
  */
 $wgExtensionAliasesFiles = array();
 
@@ -2647,6 +2645,56 @@ $wgSpecialPages = array();
  */
 $wgAutoloadClasses = array();
 
+
+/*
+ * Array mapping javascript class to web path for autoloading js
+ * this var is populated in AutoLoader.php
+ */
+$wgJSAutoloadClasses = array();
+
+/*
+ * boolean; if the script loader should be used to group all javascript requests.
+ * more about the script loader: http://www.mediawiki.org/wiki/ScriptLoader
+ *
+ * (its recommended you DO NOT enable the script loader without also enabling $wgUseFileCache
+ * (or have mediaWiki behind a proxy) otherwise all new js requests will result in script server js processing.
+ */
+$wgEnableScriptLoader = false;
+
+/*
+ * enable js2 Script System
+ * if enabled we include jquery, mv_embed and js2 versions of editPage.js
+ */
+$wgEnableJS2system = false;
+
+/*
+ * boolean; if relative file paths can be used (in addition to the autoload js classes listed in: $wgJSAutoloadClasses
+ */
+$wgEnableScriptLoaderJsFile = false;
+
+/*
+ * boolean; if we should minify the output. (note if you send ?debug=true in the page request it will automatically not group and not minify)
+ */
+$wgEnableScriptMinify = true;
+
+/*
+ * boolean; if we should enable javascript localization (it loads loadGM json call with mediaWiki msgs)
+ */
+$wgEnableScriptLocalization = true;
+
+/*
+ * path for mwEmbed normally js2/mwEmbed/
+ */
+$wgMwEmbedDirectory = "js2/mwEmbed/";
+
+/*
+ * wgDebugJavaScript used to turn on debuging for the javascript script-loader
+ * & forces fresh copies of javascript
+ */
+
+$wgDebugJavaScript = false;
+
+
 /**
  * An array of extension types and inside that their names, versions, authors,
  * urls, descriptions and pointers to localized description msgs. Note that
@@ -2654,12 +2702,12 @@ $wgAutoloadClasses = array();
  *
  * <code>
  * $wgExtensionCredits[$type][] = array(
- *     'name'           => 'Example extension',
- *  'version'        => 1.9,
- *  'path'           => __FILE__,
- *     'author'         => 'Foo Barstein',
- *     'url'            => 'http://wwww.example.com/Example%20Extension/',
- *     'description'    => 'An example extension',
+ *     'name' => 'Example extension',
+ *  'version' => 1.9,
+ *  'svn-revision' => '$LastChangedRevision$',
+ *     'author' => 'Foo Barstein',
+ *     'url' => 'http://wwww.example.com/Example%20Extension/',
+ *     'description' => 'An example extension',
  *     'descriptionmsg' => 'exampleextension-desc',
  * );
  * </code>
@@ -3013,7 +3061,7 @@ $wgLogNames = array(
        'import'  => 'importlogpage',
        'patrol'  => 'patrol-log-page',
        'merge'   => 'mergelog',
-       'suppress' => 'suppressionlog',
+       'suppress' => 'suppressionlog'
 );
 
 /**
@@ -3130,7 +3178,6 @@ $wgSpecialPageGroups = array(
        'Filepath'                  => 'media',
 
        'Listusers'                 => 'users',
-       'Activeusers'               => 'users',
        'Listgrouprights'           => 'users',
        'Ipblocklist'               => 'users',
        'Contributions'             => 'users',
@@ -3455,20 +3502,18 @@ $wgTrustedMediaFormats= array(
 $wgAllowSpecialInclusion = true;
 
 /**
- * Timeout for HTTP requests done via CURL
+ * Timeout for HTTP requests done at script execution time
+ * default is (default php.ini script time 30s - 5s for everythign else)
  */
-$wgHTTPTimeout = 3;
+$wgSyncHTTPTimeout = 25;
+/**
+* Timeout for asynchronous http request that run in a backgournd php proccess
+* default set to 20 min
+*/
+$wgAsyncHTTPTimeout = 60*20;
 
 /**
- * Servers placed behind an internal firewall may need an HTTP proxy
- * to reach external resources such as remote image repositories and
- * spam blacklist updates.
- *
- * If set, this HTTP proxy setting will be used for CURL requests.
- * Currently this setting has no effect if CURL is unavailable.
- *
- * Include the IP or hostname and port number of the proxy,
- * something like "proxy-address.example.com:8080"
+ * Proxy to use for CURL requests.
  */
 $wgHTTPProxy = false;
 
@@ -3533,6 +3578,11 @@ $wgAjaxWatch = true;
  */
 $wgAjaxUploadDestCheck = true;
 
+/**
+ * Enable AJAX upload interface (need for large http uploads & to display progress on uploads for browsers that support it)
+ */
+$wgAjaxUploadInterface = true;
+
 /**
  * Enable previewing licences via AJAX
  */
@@ -3598,6 +3648,11 @@ $wgMaxShellTime = 180;
 */
 $wgPhpCli = 'php';
 
+/**
+ * the full path to shell out to php scripts:
+ */
+$wgPhpCliPath = '/usr/bin/php';
+
 /**
  * DJVU settings
  * Path of the djvudump executable
@@ -3757,12 +3812,6 @@ $wgParserConf = array(
  */
 $wgLinkHolderBatchSize = 1000;
 
-/**
- * By default MediaWiki does not register links pointing to same server in externallinks dataset,
- * use this value to override:
- */
-$wgRegisterInternalExternals = false;
-
 /**
  * Hooks that are used for outputting exceptions.  Format is:
  *   $wgExceptionHooks[] = $funcname
@@ -3869,13 +3918,6 @@ $wgEnforceHtmlIds = true;
  */
 $wgUseTwoButtonsSearchForm = true;
 
-/**
- * Search form behavior for Vector skin only
- * true = use an icon search button
- * false = use Go & Search buttons
- */
-$wgVectorUseSimpleSearch = false;
-
 /**
  * Preprocessor caching threshold
  */
@@ -3910,20 +3952,3 @@ $wgInvalidUsernameCharacters = '@';
  * modify the user rights of those users via Special:UserRights
  */
 $wgUserrightsInterwikiDelimiter = '@';
-
-/**
- * Configuration for processing pool control, for use in high-traffic wikis. 
- * An implementation is provided in the PoolCounter extension.
- * 
- * This configuration array maps pool types to an associative array. The only
- * defined key in the associative array is "class", which gives the class name.
- * The remaining elements are passed through to the class as constructor 
- * parameters. Example:
- *
- *   $wgPoolCounterConf = array( 'Article::view' => array( 
- *     'class' => 'PoolCounter_Client',
- *     ... any extension-specific options...
- *   );
- */
-$wgPoolCounterConf = null;
-
index 2d2b858..8a43479 100644 (file)
@@ -111,6 +111,7 @@ class EditPage {
                return $this->mArticle;
        }
 
+
        /**
         * Fetch initial editing page content.
         * @private
@@ -360,7 +361,7 @@ class EditPage {
         * the newly-edited page.
         */
        function edit() {
-               global $wgOut, $wgRequest;
+               global $wgOut, $wgRequest, $wgEnableJS2system;
                // Allow extensions to modify/prevent this form or submission
                if ( !wfRunHooks( 'AlternateEdit', array( &$this ) ) ) {
                        return;
@@ -388,6 +389,10 @@ class EditPage {
                }
 
                $wgOut->addScriptFile( 'edit.js' );
+
+               if($wgEnableJS2system)
+                   $wgOut->addScriptClass( 'editPage' );
+
                $permErrors = $this->getEditPermissionErrors();
                if ( $permErrors ) {
                        wfDebug( __METHOD__.": User can't edit\n" );
@@ -1070,7 +1075,7 @@ class EditPage {
                }
                return true;
        }
-       
+
        /**
         * Check given input text against $wgSpamRegex, and return the text of the first match.
         * @return mixed -- matching string or false
@@ -1331,6 +1336,7 @@ class EditPage {
                        $toolbar = '';
                }
 
+
                // activate checkboxes if user wants them to be always active
                if ( !$this->preview && !$this->diff ) {
                        # Sort out the "watch" checkbox
@@ -1344,7 +1350,7 @@ class EditPage {
                                # Already watched
                                $this->watchthis = true;
                        }
-                       
+
                        # May be overriden by request parameters
                        if( $wgRequest->getBool( 'watchthis' ) ) {
                                $this->watchthis = true;
@@ -2180,9 +2186,9 @@ END
 
                $toolbar.="/*]]>*/\n</script>";
                $toolbar.="\n</div>";
-               
+
                wfRunHooks( 'EditPageBeforeEditToolbar', array( &$toolbar ) );
-               
+
                return $toolbar;
        }
 
index e75786b..ddbe939 100644 (file)
@@ -2281,7 +2281,39 @@ function wfShellExec( $cmd, &$retval=null ) {
        }
        return $output;
 }
-
+/**
+ * Executes a shell command in the background. Passes back the PID of the operation 
+ *
+ * @param string $cmd
+ */
+function wfShellBackgroundExec( $cmd ){        
+       wfDebug( "wfShellBackgroundExec: $cmd\n" );
+       
+       if ( ! wfShellExecEnabled() ) {
+               return "Unable to run external programs";
+       }
+       
+       $pid = shell_exec( "nohup $cmd > /dev/null & echo $!" );
+       return $pid;
+}
+/**
+ * Checks if the current instance can execute a shell command
+ *
+ */
+function wfShellExecEnabled(){                 
+       if( wfIniGetBool( 'safe_mode' ) ) {
+               wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
+               return false;
+       }
+       $functions = explode( ',', ini_get( 'disable_functions' ) );
+       $functions = array_map( 'trim', $functions );
+       $functions = array_map( 'strtolower', $functions );
+       if ( in_array( 'passthru', $functions ) ) {
+               wfDebug( "passthru is in disabled_functions\n" );
+               return false;
+       }
+       return true;
+}
 /**
  * Workaround for http://bugs.php.net/bug.php?id=45132
  * escapeshellarg() destroys non-ASCII characters if LANG is not a UTF-8 locale
@@ -2679,9 +2711,12 @@ function wfCreateObject( $name, $p ){
  * Alias for modularized function
  * @deprecated Use Http::get() instead
  */
-function wfGetHTTP( $url, $timeout = 'default' ) {
+function wfGetHTTP( $url ) {
        wfDeprecated(__FUNCTION__);
-       return Http::get( $url, $timeout );
+       $status = Http::get( $url );
+       if( $status->isOK() )
+               return $status->value;          
+       return null;
 }
 
 /**
@@ -2705,7 +2740,7 @@ function wfHttpOnlySafe() {
                        }
                }
        }
-
+       
        return true;
 }
 
index 269d45f..da8f92c 100644 (file)
 <?php
-
 /**
- * @defgroup HTTP HTTP
- * @file
- * @ingroup HTTP
+ * HTTP handling class
+ *
  */
 
-/**
- * Various HTTP related functions
- * @ingroup HTTP
- */
+
 class Http {
+       const SYNC_DOWNLOAD = 1;  //syncronys upload (in a single request)
+       const ASYNC_DOWNLOAD = 2; //asynchronous upload we should spawn out another process and monitor progress if possible)
 
+       var $body = '';
+       public static function request( $url, $opts = array() ) {
+       $req = new HttpRequest( $url, $opts );
+       $status = $req->doRequest();
+       if( $status->isOK() ){
+           return $status->value;
+       }else{
+           return false;
+       }
+    }
        /**
         * Simple wrapper for Http::request( 'GET' )
-        * @see Http::request()
         */
-       public static function get( $url, $timeout = 'default', $opts = array() ) {
-               return Http::request( "GET", $url, $timeout, $opts );
+       public static function get( $url, $opts = array() ) {
+               $opt['method'] = 'GET';
+               return Http::request($url, $opts);
        }
-
        /**
         * Simple wrapper for Http::request( 'POST' )
-        * @see Http::request()
         */
-       public static function post( $url, $timeout = 'default', $opts = array() ) {
-               return Http::request( "POST", $url, $timeout, $opts );
+       public static function post( $url, $opts = array() ) {
+               $opts['method']='POST';
+               return Http::request($url, $opts);
        }
 
+       public static function doDownload( $url, $target_file_path , $dl_mode = self::SYNC_DOWNLOAD , $redirectCount=0){
+               global $wgPhpCliPath, $wgMaxUploadSize, $wgMaxRedirects;
+               //do a quick check to HEAD to insure the file size is not > $wgMaxUploadSize
+               $head = get_headers($url, 1);
+
+               //check for redirects:
+               if( isset( $head['Location'] ) && strrpos($head[0], '302')!==false ){
+                       if($redirectCount < $wgMaxRedirects){
+                               if( UploadFromUrl::isValidURI( $head['Location'] )){
+                                       return self::doDownload ( $head['Location'], $target_file_path , $dl_mode, $redirectCount++);
+                               }else{
+                                       return Status::newFatal('upload-proto-error');
+                               }
+                       }else{
+                               return Status::newFatal('upload-too-many-redirects');
+                       }
+               }
+               //we did not get a 200 ok response:
+               if( strrpos($head[0], '200 OK') === false){
+                       return Status::newFatal( 'upload-http-error', htmlspecialchars($head[0]) );
+               }
+
+
+               $content_length = (isset($head['Content-Length']))?$head['Content-Length']:null;
+               if($content_length){
+                       if($content_length > $wgMaxUploadSize){
+                               return Status::newFatal('requested file length ' . $content_length . ' is greater than $wgMaxUploadSize: ' . $wgMaxUploadSize);
+                       }
+               }
+
+               //check if we can find phpCliPath (for doing a background shell request to php to do the download:
+               if( $wgPhpCliPath && wfShellExecEnabled() && $dl_mode == self::ASYNC_DOWNLOAD){
+                       wfDebug("\ASYNC_DOWNLOAD\n");
+                       //setup session and shell call:
+                       return self::initBackgroundDownload( $url, $target_file_path, $content_length );
+               }else if( $dl_mode== self::SYNC_DOWNLOAD ){
+                       wfDebug("\nSYNC_DOWNLOAD\n");
+                       //SYNC_DOWNLOAD download as much as we can in the time we have to execute
+                       $opts['method']='GET';
+                       $opts['target_file_path'] = $target_file_path;
+                       $req = new HttpRequest($url, $opts );
+                       return $req->doRequest();
+               }
+       }
        /**
-        * Get the contents of a file by HTTP
-        * @param $method string HTTP method. Usually GET/POST
-        * @param $url string Full URL to act on
-        * @param $timeout int Seconds to timeout. 'default' falls to $wgHTTPTimeout
-        * @param $curlOptions array Optional array of extra params to pass 
-        * to curl_setopt()
+        * a non blocking request (generally an exit point in the application)
+        * should write to a file location and give updates
+        *
         */
-       public static function request( $method, $url, $timeout = 'default', $curlOptions = array() ) {
-               global $wgHTTPTimeout, $wgHTTPProxy, $wgTitle;
+       private function initBackgroundDownload( $url, $target_file_path, $content_length = null ){
+               global $wgMaxUploadSize, $IP, $wgPhpCliPath;
+               $status = Status::newGood();
+
+               //generate a session id with all the details for the download (pid, target_file_path )
+               $upload_session_key = self::getUploadSessionKey();
+               $session_id = session_id();
+
+               //store the url and target path:
+               $_SESSION[ 'wsDownload' ][$upload_session_key]['url'] = $url;
+               $_SESSION[ 'wsDownload' ][$upload_session_key]['target_file_path'] = $target_file_path;
 
-               // Go ahead and set the timeout if not otherwise specified
-               if ( $timeout == 'default' ) {
-                       $timeout = $wgHTTPTimeout;
+               if($content_length)
+                       $_SESSION[ 'wsDownload' ][$upload_session_key]['content_length'] = $content_length;
+
+               //set initial loaded bytes:
+               $_SESSION[ 'wsDownload' ][$upload_session_key]['loaded'] = 0;
+
+
+               //run the background download request:
+               $cmd = $wgPhpCliPath . ' ' . $IP . "/maintenance/http_session_download.php --sid {$session_id} --usk {$upload_session_key}";
+               $pid = wfShellBackgroundExec($cmd , $retval);
+               //the pid is not of much use since we won't be visiting this same apache any-time soon.
+               if(!$pid)
+                       return Status::newFatal('could not run background shell exec');
+
+               //update the status value with the $upload_session_key (for the user to check on the status of the upload)
+               $status->value = $upload_session_key;
+
+               //return good status
+               return $status;
+       }
+       function getUploadSessionKey(){
+               $key = mt_rand( 0, 0x7fffffff );
+               $_SESSION['wsUploadData'][$key] = array();
+               return $key;
+       }
+       /**
+        * used to run a session based download. Is initiated via the shell.
+        *
+        * @param string $session_id  // the session id to grab download details from
+        * @param string $upload_session_key //the key of the given upload session
+        *                      (a given client could have started a few http uploads at once)
+        */
+       public static function doSessionIdDownload( $session_id, $upload_session_key ){
+               global $wgUser, $wgEnableWriteAPI, $wgAsyncHTTPTimeout;
+               wfDebug("\n\ndoSessionIdDownload\n\n");
+               //set session to the provided key:
+               session_id($session_id);
+               //start the session
+               if( session_start() === false){
+                       wfDebug( __METHOD__ . ' could not start session');
+               }
+               //get all the vars we need from session_id
+               if(!isset($_SESSION[ 'wsDownload' ][$upload_session_key])){
+                       wfDebug(  __METHOD__ .' Error:could not find upload session');
+                       exit();
                }
+               //setup the global user from the session key we just inherited
+               $wgUser = User::newFromSession();
 
-               wfDebug( __METHOD__ . ": $method $url\n" );
-               # Use curl if available
-               if ( function_exists( 'curl_init' ) ) {
-                       $c = curl_init( $url );
-                       if ( self::isLocalURL( $url ) ) {
-                               curl_setopt( $c, CURLOPT_PROXY, 'localhost:80' );
-                       } else if ($wgHTTPProxy) {
-                               curl_setopt($c, CURLOPT_PROXY, $wgHTTPProxy);
-                       }
+               //grab the session data to setup the request:
+               $sd =& $_SESSION[ 'wsDownload' ][$upload_session_key];
+               //close down the session so we can other http queries can get session updates:
+               session_write_close();
 
-                       curl_setopt( $c, CURLOPT_TIMEOUT, $timeout );
-                       curl_setopt( $c, CURLOPT_USERAGENT, self :: userAgent() );
-                       if ( $method == 'POST' ) {
-                               curl_setopt( $c, CURLOPT_POST, true );
-                               curl_setopt( $c, CURLOPT_POSTFIELDS, '' );
-                       }
-                       else
-                               curl_setopt( $c, CURLOPT_CUSTOMREQUEST, $method );
-
-                       # Set the referer to $wgTitle, even in command-line mode
-                       # This is useful for interwiki transclusion, where the foreign
-                       # server wants to know what the referring page is.
-                       # $_SERVER['REQUEST_URI'] gives a less reliable indication of the
-                       # referring page.
-                       if ( is_object( $wgTitle ) ) {
-                               curl_setopt( $c, CURLOPT_REFERER, $wgTitle->getFullURL() );
-                       }
-                       
-                       if ( is_array( $curlOptions ) ) {
-                               foreach( $curlOptions as $option => $value ) {
-                                       curl_setopt( $c, $option, $value );
-                               }
-                       }
+               $req = new HttpRequest( $sd['url'], array(
+                       'target_file_path'      => $sd['target_file_path'],
+                       'upload_session_key'=> $upload_session_key,
+                       'timeout'                       => $wgAsyncHTTPTimeout
+               ) );
+               //run the actual request .. (this can take some time)
+               wfDebug("do Request: " . $sd['url'] . ' tf: ' . $sd['target_file_path'] );
+               $status = $req->doRequest();
+               //wfDebug("done with req status is: ". $status->isOK(). ' '.$status->getWikiText(). "\n");
 
-                       ob_start();
-                       curl_exec( $c );
-                       $text = ob_get_contents();
-                       ob_end_clean();
+               //start up the session again:
+               if( session_start() === false){
+                       wfDebug( __METHOD__ . ' ERROR:: Could not start session');
+               }
+               //grab the updated session data pointer
+               $sd =& $_SESSION[ 'wsDownload' ][$upload_session_key];
+               //if error update status:
+               if( !$status->isOK() ){
+                       $sd['apiUploadResult']= ApiFormatJson::getJsonEncode(
+                                                                               array( 'error' => $status->getWikiText() )
+                                                                       );
+               }
+               //if status oky process upload using fauxReq to api:
+               if( $status->isOK() ){
+                       //setup the faxRequest
+                       $fauxReqData = $sd['mParams'];
+                       $fauxReqData['action'] = 'upload';
+                       $fauxReqData['format'] = 'json';
+                       $fauxReqData['internalhttpsession'] = $upload_session_key;
+                       //evil but no other clean way about it:
 
-                       # Don't return the text of error messages, return false on error
-                       $retcode = curl_getinfo( $c, CURLINFO_HTTP_CODE );
-                       if ( $retcode != 200 ) {
-                               wfDebug( __METHOD__ . ": HTTP return code $retcode\n" );
-                               $text = false;
-                       }
-                       # Don't return truncated output
-                       $errno = curl_errno( $c );
-                       if ( $errno != CURLE_OK ) {
-                               $errstr = curl_error( $c );
-                               wfDebug( __METHOD__ . ": CURL error code $errno: $errstr\n" );
-                               $text = false;
-                       }
-                       curl_close( $c );
-               } else {
-                       # Otherwise use file_get_contents...
-                       # This doesn't have local fetch capabilities...
-
-                       $headers = array( "User-Agent: " . self :: userAgent() );
-                       if( strcasecmp( $method, 'post' ) == 0 ) {
-                               // Required for HTTP 1.0 POSTs
-                               $headers[] = "Content-Length: 0";
-                       }
-                       $opts = array(
-                               'http' => array(
-                                       'method' => $method,
-                                       'header' => implode( "\r\n", $headers ),
-                                       'timeout' => $timeout ) );
-                       $ctx = stream_context_create($opts);
+                       $faxReq = new FauxRequest($fauxReqData, true);
+                       $processor = new ApiMain($faxReq, $wgEnableWriteAPI);
+
+                       //init the mUpload var for the $processor
+                       $processor->execute();
+                       $processor->getResult()->cleanUpUTF8();
+                       $printer = $processor->createPrinterByName('json');
+                       $printer->initPrinter(false);
+                       ob_start();
+                       $printer->execute();
+                       $apiUploadResult = ob_get_clean();
 
-                       $text = file_get_contents( $url, false, $ctx );
+                       wfDebug("\n\n got api result:: $apiUploadResult \n" );
+                       //the status updates runner will grab the result form the session:
+                       $sd['apiUploadResult'] = $apiUploadResult;
                }
-               return $text;
+               //close the session:
+               session_write_close();
        }
 
        /**
@@ -151,7 +233,7 @@ class Http {
                }
                return false;
        }
-       
+
        /**
         * Return a standard user-agent we can use for external requests.
         */
@@ -160,3 +242,227 @@ class Http {
                return "MediaWiki/$wgVersion";
        }
 }
+class HttpRequest{
+       var $target_file_path;
+       var $upload_session_key;
+       function __construct($url, $opt){
+               global $wgSyncHTTPTimeout;
+               $this->url = $url;
+               //set the timeout to default sync timeout (unless the timeout option is provided)
+               $this->timeout = (isset($opt['timeout']))?$opt['timeout']:$wgSyncHTTPTimeout;
+               $this->method = (isset($opt['method']))?$opt['method']:'GET';
+               $this->target_file_path = (isset($opt['target_file_path']))?$opt['target_file_path']:false;
+               $this->upload_session_key = (isset($opt['upload_session_key']))?$opt['upload_session_key']:false;
+       }
+/**
+        * Get the contents of a file by HTTP
+        * @param $url string Full URL to act on
+        * @param $Opt associative array Optional array of options:
+        *              'method'          => 'GET', 'POST' etc.
+        *              'target_file_path' => if curl should output to a target file
+        *              'adapter'         => 'curl', 'soket'
+        */
+        public function doRequest() {
+               # Use curl if available
+               if ( function_exists( 'curl_init' ) ) {
+                       return $this->doCurlReq();
+               }else{
+                       return $this->doPhpReq();
+               }
+        }
+        private function doCurlReq(){
+               global $wgHTTPProxy, $wgTitle;
+
+               $status = Status::newGood();
+               $c = curl_init( $this->url );
+
+               //proxy setup:
+               if ( Http::isLocalURL( $this->url ) ) {
+                       curl_setopt( $c, CURLOPT_PROXY, 'localhost:80' );
+               } else if ($wgHTTPProxy) {
+                       curl_setopt($c, CURLOPT_PROXY, $wgHTTPProxy);
+               }
+
+               curl_setopt( $c, CURLOPT_TIMEOUT, $this->timeout );
+
+
+               curl_setopt( $c, CURLOPT_USERAGENT, Http::userAgent() );
+
+               if ( $this->method == 'POST' ) {
+                       curl_setopt( $c, CURLOPT_POST, true );
+                       curl_setopt( $c, CURLOPT_POSTFIELDS, '' );
+               }else{
+                       curl_setopt( $c, CURLOPT_CUSTOMREQUEST, $this->method );
+               }
+
+               # Set the referer to $wgTitle, even in command-line mode
+               # This is useful for interwiki transclusion, where the foreign
+               # server wants to know what the referring page is.
+               # $_SERVER['REQUEST_URI'] gives a less reliable indication of the
+               # referring page.
+               if ( is_object( $wgTitle ) ) {
+                       curl_setopt( $c, CURLOPT_REFERER, $wgTitle->getFullURL() );
+               }
+
+               //set the write back function (if we are writing to a file)
+               if( $this->target_file_path ){
+                       $cwrite = new simpleFileWriter( $this->target_file_path, $this->upload_session_key );
+                       if(!$cwrite->status->isOK()){
+                               wfDebug("ERROR in setting up simpleFileWriter\n");
+                               $status = $cwrite->status;
+                       }
+                       curl_setopt( $c, CURLOPT_WRITEFUNCTION, array($cwrite, 'callbackWriteBody') );
+               }
+
+               //start output grabber:
+               if(!$this->target_file_path)
+                       ob_start();
+
+               //run the actual curl_exec:
+               try {
+            if (false === curl_exec($c)) {
+               $error_txt ='Error sending request: #' . curl_errno($c) .' '. curl_error($c);
+               wfDebug($error_txt . "\n");
+                $status = Status::newFatal( $error_txt);
+            }
+        } catch (Exception $e) {
+               //do something with curl exec error?
+        }
+               //if direct request output the results to the stats value:
+               if( !$this->target_file_path && $status->isOK() ){
+               $status->value = ob_get_contents();
+                       ob_end_clean();
+               }
+               //if we wrote to a target file close up or return error
+               if( $this->target_file_path ){
+                       $cwrite->close();
+                       if( ! $cwrite->status->isOK() ){
+                               return $cwrite->status;
+                       }
+               }
+
+               # Don't return the text of error messages, return false on error
+               $retcode = curl_getinfo( $c, CURLINFO_HTTP_CODE );
+               if ( $retcode != 200 ) {
+                       wfDebug( __METHOD__ . ": HTTP return code $retcode\n" );
+                       $status = Status::newFatal( "HTTP return code $retcode\n" );
+               }
+               # Don't return truncated output
+               $errno = curl_errno( $c );
+               if ( $errno != CURLE_OK ) {
+                       $errstr = curl_error( $c );
+                       wfDebug( __METHOD__ . ": CURL error code $errno: $errstr\n" );
+                               $status = Status::newFatal( " CURL error code $errno: $errstr\n" );
+               }
+               curl_close( $c );
+
+               //return the result obj
+               return $status;
+       }
+       public function doPhpReq(){
+               #$use file_get_contents...
+               # This doesn't have local fetch capabilities...
+
+               $headers = array( "User-Agent: " . self :: userAgent() );
+               if( strcasecmp( $method, 'post' ) == 0 ) {
+                       // Required for HTTP 1.0 POSTs
+                       $headers[] = "Content-Length: 0";
+               }
+               $opts = array(
+                       'http' => array(
+                               'method' => $method,
+                               'header' => implode( "\r\n", $headers ),
+                               'timeout' => $timeout ) );
+               $ctx = stream_context_create( $opts );
+
+               $status->value = file_get_contents( $url, false, $ctx );
+               if(!$status->value){
+                       $status->error('file_get_contents-failed');
+               }
+               return $status;
+       }
+}
+/**
+ * a simpleFileWriter with session id updates
+ *
+ */
+class simpleFileWriter{
+       var $target_file_path;
+       var $status = null;
+       var $session_id = null;
+       var $session_update_interval = 0; //how offten to update the session while downloading
+
+       function simpleFileWriter($target_file_path, $upload_session_key){
+               $this->target_file_path = $target_file_path;
+               $this->upload_session_key = $upload_session_key;
+               $this->status = Status::newGood();
+               //open the file:
+               $this->fp = fopen( $this->target_file_path, 'w');
+               if( $this->fp === false ){
+                       $this->status = Status::newFatal('HTTP::could-not-open-file-for-writing');
+               }
+               //true start time
+               $this->prevTime = time();
+       }
+       public function callbackWriteBody($ch, $data_packet){
+               global $wgMaxUploadSize;
+
+               //write out the content
+               if( fwrite($this->fp, $data_packet) === false){
+                       wfDebug(__METHOD__ ." ::could-not-write-to-file\n");
+                       $this->status = Status::newFatal('HTTP::could-not-write-to-file');
+                       return 0;
+               }
+
+               //check file size:
+               clearstatcache();
+               $this->current_fsize = filesize( $this->target_file_path);
+
+               if( $this->current_fsize > $wgMaxUploadSize){
+                       wfDebug( __METHOD__ . " ::http download too large\n");
+                       $this->status = Status::newFatal('HTTP::file-has-grown-beyond-upload-limit-killing: downloaded more than ' .
+                               Language::formatSize($wgMaxUploadSize) . ' ');
+                       return 0;
+               }
+
+               //if more than session_update_interval second have passed update_session_progress
+               if($this->upload_session_key && ( (time() - $this->prevTime) > $this->session_update_interval )) {
+                       $this->prevTime = time();
+                       $session_status = $this->update_session_progress();
+                       if( !$session_status->isOK() ){
+                               $this->status = $session_status;
+                               wfDebug( __METHOD__ . ' update session failed or was canceled');
+                               return 0;
+                       }
+               }
+               return strlen( $data_packet );
+       }
+       public function update_session_progress(){
+               $status = Status::newGood();
+               //start the session
+               if( session_start() === false){
+                       wfDebug( __METHOD__ . ' could not start session');
+                       exit(0);
+               }
+               $sd =& $_SESSION[ 'wsDownload' ][ $this->upload_session_key ];
+               //check if the user canceled the request:
+               if( $sd['user_cancel'] == true ){
+                       //kill the download
+                       return Status::newFatal('user-canceled-request');
+               }
+               //update the progress bytes download so far:
+               $sd['loaded'] = $this->current_fsize;
+               wfDebug('set session loaded amount to: ' . $sd['loaded'] . "\n");
+               //close down the session so we can other http queries can get session updates:
+               session_write_close();
+               return $status;
+       }
+       public function close(){
+               //do a final session update:
+               $this->update_session_progress();
+               //close up the file handle:
+               if(false === fclose( $this->fp )){
+                       $this->status = Status::newFatal('HTTP::could-not-close-file');
+               }
+       }
+}
\ No newline at end of file
index a0d8790..ab575c9 100644 (file)
@@ -13,6 +13,11 @@ class OutputPage {
        var $mSubtitle = '', $mRedirect = '', $mStatusCode;
        var $mLastModified = '', $mETag = false;
        var $mCategoryLinks = array(), $mLanguageLinks = array();
+
+       var $mScriptLoaderClassList = array();
+       //the most recent id of any script that is grouped in the script request
+       var $mLatestScriptRevID = 0; 
+
        var $mScripts = '', $mLinkColours, $mPageLinkTitle = '', $mHeadItems = array();
        var $mTemplateIds = array();
 
@@ -93,8 +98,8 @@ class OutputPage {
                        array_push( $this->mKeywords, $text );
                }
        }
-       function addScript( $script ) { $this->mScripts .= "\t" . $script . "\n"; }
-       
+       function addScript( $script ) { $this->mScripts .= "\t\t" . $script . "\n"; }
+
        function addExtensionStyle( $url ) {
                $linkarr = array( 'rel' => 'stylesheet', 'href' => $url, 'type' => 'text/css' );
                array_push( $this->mExtStyles, $linkarr );
@@ -105,23 +110,169 @@ class OutputPage {
         * @param string $file filename in skins/common or complete on-server path (/foo/bar.js)
         */
        function addScriptFile( $file ) {
-               global $wgStylePath, $wgStyleVersion, $wgJsMimeType;
+               global $wgStylePath, $wgStyleVersion, $wgJsMimeType, $wgScript, $wgUser;
+               global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgEnableScriptLoader, $wgScriptPath;
+
                if( substr( $file, 0, 1 ) == '/' ) {
                        $path = $file;
                } else {
                        $path =  "{$wgStylePath}/common/{$file}";
                }
-               $this->addScript( 
-                       Xml::element( 'script', 
+               if( $wgEnableScriptLoader ){
+                       if( strpos($path, $wgScript) !== false ){
+                               $reqPath = str_replace($wgScript.'?', '', $path);
+                               $reqArgs = split('&', $reqPath);
+                               $reqSet = array();
+
+                               foreach($reqArgs as $arg){
+                                       list($key, $var) = split('=', $arg);
+                                       $reqSet[$key]= $var;
+                               }
+
+                               if( isset( $reqSet['title'] ) &&  $reqSet != '' ) {
+                                       //extract any extra param (for now just skin)
+                                       $ext_param = ( isset( $reqSet['useskin'] ) && $reqSet['useskin'] != '') ? '|useskin=' . ucfirst( $reqSet['useskin'] ) : '';
+                                       $this->mScriptLoaderClassList[] = 'WT:' . $reqSet['title'] . $ext_param ;
+                                       //add the title revision to the key
+                                       $t = Title::newFromText( $reqSet['title'] );
+                                       //if there is no title (don't worry we just use the $wgStyleVersion var (which should be updated on relevant commits)
+                                       if( $t->exists() ){
+                                               if( $t->getLatestRevID() > $this->mLatestScriptRevID  )
+                                                       $this->mLatestScriptRevID = $t->getLatestRevID();
+                                       }
+                                       return true;
+                               }
+                       }
+                       //check for class from path:
+                       $js_class = $this->getJsClassFromPath( $path );
+                       if( $js_class ){
+                               //add to the class list:
+                               $this->mScriptLoaderClassList[] = $js_class;
+                               return true;
+                       }
+               }
+               //die();
+               //if the script loader did not find a way to add the script than add using AddScript
+               $this->addScript(
+                       Xml::element( 'script',
                                array(
                                        'type' => $wgJsMimeType,
-                                       'src' => "$path?$wgStyleVersion",
+                                       'src' => "$path?" . $this->getURIDparam(),
                                ),
                                '', false
                        )
-               );      
+               );
+       }
+       /*
+        * This is the core script that is included on every page
+        * (they are requested separately to improve caching across
+        *  different page load types (edit, upload, view, etc)
+        */
+       function addCoreScripts2Top(){
+               global $wgEnableScriptLoader, $wgStyleVersion,$wgJSAutoloadLocalClasses, $wgJsMimeType, $wgScriptPath, $wgEnableJS2system ;
+               //@@todo we should depricate wikibits in favor of mv_embed and native jQuery functions
+
+               if( $wgEnableJS2system ){
+                   $core_classes = array('window.jQuery', 'mv_embed', 'wikibits');
+               }else{
+                   $core_classes = array('wikibits');
+               }
+               if( $wgEnableScriptLoader ){
+                       $this->mScripts = $this->getScriptLoaderJs( $core_classes ) . $this->mScripts;
+               }else{
+                       $so = '';
+                       foreach($core_classes as $s){
+                               if(isset( $wgJSAutoloadLocalClasses[$s] )){
+                                               $so.= Xml::element( 'script', array(
+                                                               'type' => $wgJsMimeType,
+                                                               'src' => "{$wgScriptPath}/{$wgJSAutoloadLocalClasses[$s]}?" . $this->getURIDparam()
+                                                       ),
+                                                       '', false
+                                               );
+                               }
+                       }
+                       $this->mScripts =  $so . $this->mScripts;
+               }
+       }
+       function addScriptClass( $js_class ){
+               global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgJsMimeType,
+                               $wgEnableScriptLoader, $wgStyleVersion, $wgScriptPath;
+               if(isset($wgJSAutoloadClasses[ $js_class ] ) || isset( $wgJSAutoloadLocalClasses[$js_class]) ){
+                       if($wgEnableScriptLoader){
+                               if( ! in_array( $js_class, $this->mScriptLoaderClassList ) ){
+                                       $this->mScriptLoaderClassList[] = $js_class;
+                               }
+                       }else{
+                               //do a normal load of without the script-loader:
+                               $path = $wgScriptPath . '/';
+                               $path.= isset($wgJSAutoloadClasses[ $js_class ] )?$wgJSAutoloadClasses[ $js_class ]:
+                                                       $wgJSAutoloadLocalClasses[$js_class];
+                               $this->addScript(
+                                       Xml::element( 'script',
+                                               array(
+                                                       'type' => $wgJsMimeType,
+                                                       'src' => "$path?$wgStyleVersion",
+                                               ),
+                                               '', false
+                                       )
+                               );
+                       }
+                       return true;
+               }
+               wfDebug( __METHOD__ . " could not find js_class: " . $js_class );
+               return false; //could not find the class
+       }
+       /**
+        * gets the scriptLoader javascript include
+        *
+        */
+       function getScriptLoaderJs( $forceClassAry=false ){
+               global $wgScriptPath, $wgJsMimeType, $wgStyleVersion, $wgRequest, $wgDebugJavaScript;
+
+               if(!$forceClassAry){
+                       $class_list = implode(',', $this->mScriptLoaderClassList );
+               }else{
+                       $class_list = implode(',', $forceClassAry );
+               }
+
+               $debug_param = ( $wgDebugJavaScript ||
+                                                $wgRequest->getVal('debug')=='true' ||
+                                                $wgRequest->getVal('debug')=='1' )
+                                        ? '&debug=true' : '';
+
+               //@@todo intelligent unique id generation based on svn version of file (rather than just grabbing the $wgStyleVersion var)
+               //@@todo we should check the packaged message text in this javascript file for updates and update the $mScriptLoaderURID id (in getJsClassFromPath)
+
+               //generate the unique request param (combine with the most recent revision id of any wiki page with the $wgStyleVersion var)
+
+
+               return Xml::element( 'script',
+                               array(
+                                       'type' => $wgJsMimeType,
+                                       'src' => "$wgScriptPath/mwScriptLoader.php?class={$class_list}{$debug_param}&".$this->getURIDparam(),
+                               ),
+                               '', false
+               );
+       }
+       function getURIDparam(){
+               global $wgDebugJavaScript,$wgStyleVersion;
+               if( $wgDebugJavaScript ){
+                       return "urid=". time();
+               }else{
+                       return "urid={$wgStyleVersion}_{$this->mLatestScriptRevID}";
+               }
+       }
+       function getJsClassFromPath( $path ){
+               global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgScriptPath;
+
+               $scriptLoaderPaths = array_merge( $wgJSAutoloadClasses,  $wgJSAutoloadLocalClasses );
+               foreach( $scriptLoaderPaths as $js_class => $js_path ){
+                       $js_path = "{$wgScriptPath}/{$js_path}";
+                       if($path == $js_path)
+                               return $js_class;
+               }
+               return false;
        }
-       
        /**
         * Add a self-contained script tag with the given contents
         * @param string $script JavaScript text, no <script> tags
@@ -132,7 +283,13 @@ class OutputPage {
        }
 
        function getScript() {
-               return $this->mScripts . $this->getHeadItems();
+               global $wgEnableScriptLoader;
+               if( $wgEnableScriptLoader ){
+                       //include       $this->mScripts (for anything that we could not package into the scriptloader
+                       return $this->mScripts ."\n". $this->getScriptLoaderJs() . $this->getHeadItems();
+               }else{
+                       return $this->mScripts . $this->getHeadItems();
+               }
        }
 
        function getHeadItems() {
@@ -159,7 +316,7 @@ class OutputPage {
                # $linkarr should be an associative array of attributes. We'll escape on output.
                array_push( $this->mLinktags, $linkarr );
        }
-       
+
        # Get all links added by extensions
        function getExtStyle() {
                return $this->mExtStyles;
@@ -184,7 +341,7 @@ class OutputPage {
         */
        function checkLastModified( $timestamp ) {
                global $wgCachePages, $wgCacheEpoch, $wgUser, $wgRequest;
-               
+
                if ( !$timestamp || $timestamp == '19700101000000' ) {
                        wfDebug( __METHOD__ . ": CACHE DISABLED, NO TIMESTAMP\n" );
                        return false;
@@ -237,9 +394,9 @@ class OutputPage {
                }
                $clientHeaderTime = wfTimestamp( TS_MW, $clientHeaderTime );
 
-               wfDebug( __METHOD__ . ": client sent If-Modified-Since: " . 
+               wfDebug( __METHOD__ . ": client sent If-Modified-Since: " .
                        wfTimestamp( TS_ISO_8601, $clientHeaderTime ) . "\n", false );
-               wfDebug( __METHOD__ . ": effective Last-Modified: " . 
+               wfDebug( __METHOD__ . ": effective Last-Modified: " .
                        wfTimestamp( TS_ISO_8601, $maxModified ) . "\n", false );
                if( $clientHeaderTime < $maxModified ) {
                        wfDebug( __METHOD__ . ": STALE, $info\n", false );
@@ -247,7 +404,7 @@ class OutputPage {
                }
 
                # Not modified
-               # Give a 304 response code and disable body output 
+               # Give a 304 response code and disable body output
                wfDebug( __METHOD__ . ": NOT MODIFIED, $info\n", false );
                ini_set('zlib.output_compression', 0);
                $wgRequest->response()->header( "HTTP/1.1 304 Not Modified" );
@@ -356,11 +513,11 @@ class OutputPage {
                # change "<i>foo&amp;bar</i>" to "foo&bar"
                $this->setHTMLTitle( wfMsg( 'pagetitle', Sanitizer::stripAllTags( $nameWithTags ) ) );
        }
-       
+
        public function setTitle( $t ) {
                $this->mTitle = $t;
        }
-       
+
        public function getTitle() {
                if ( $this->mTitle instanceof Title ) {
                        return $this->mTitle;
@@ -510,7 +667,7 @@ class OutputPage {
                $val = is_null( $revid ) ? null : intval( $revid );
                return wfSetVar( $this->mRevisionId, $val );
        }
-       
+
        public function getRevisionId() {
                return $this->mRevisionId;
        }
@@ -714,7 +871,7 @@ class OutputPage {
        /**
         * @param Article $article
         * @param User    $user
-        * 
+        *
         * @deprecated
         *
         * @return bool True if successful, else false.
@@ -722,7 +879,7 @@ class OutputPage {
        public function tryParserCache( &$article ) {
                wfDeprecated( __METHOD__ );
                $parserOutput = ParserCache::singleton()->get( $article, $article->getParserOptions() );
-               
+
                if ($parserOutput !== false) {
                        $this->addParserOutput( $parserOutput );
                        return true;
@@ -879,9 +1036,7 @@ class OutputPage {
                if( $this->mDoNothing ){
                        return;
                }
-
                wfProfileIn( __METHOD__ );
-
                if ( '' != $this->mRedirect ) {
                        # Standards require redirect URLs to be absolute
                        $this->mRedirect = wfExpandUrl( $this->mRedirect );
@@ -891,7 +1046,6 @@ class OutputPage {
                                }
                                $this->mLastModified = wfTimestamp( TS_RFC2822 );
                        }
-
                        $this->sendCacheControl();
 
                        $wgRequest->response()->header("Content-Type: text/html; charset=utf-8");
@@ -963,6 +1117,9 @@ class OutputPage {
 
                $sk = $wgUser->getSkin();
 
+               //add our core scripts to output
+               $this->addCoreScripts2Top();
+
                if ( $wgUseAjax ) {
                        $this->addScriptFile( 'ajax.js' );
 
@@ -971,12 +1128,12 @@ class OutputPage {
                        if( $wgAjaxWatch && $wgUser->isLoggedIn() ) {
                                $this->addScriptFile( 'ajaxwatch.js' );
                        }
-                       
+
                        if ( $wgEnableMWSuggest && !$wgUser->getOption( 'disablesuggest', false ) ){
                                $this->addScriptFile( 'mwsuggest.js' );
                        }
                }
-               
+
                if( $wgUser->getBoolOption( 'editsectiononrightclick' ) ) {
                        $this->addScriptFile( 'rightclickedit.js' );
                }
@@ -999,7 +1156,7 @@ class OutputPage {
                                ) );
                        }
                }
-               
+
                # Buffer output; final headers may depend on later processing
                ob_start();
 
@@ -1553,7 +1710,7 @@ class OutputPage {
        public function headElement( Skin $sk ) {
                global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType;
                global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces;
-               global $wgContLang, $wgUseTrackbacks, $wgStyleVersion, $wgHtml5;
+               global $wgContLang, $wgUseTrackbacks, $wgStyleVersion, $wgEnableScriptLoader, $wgHtml5;
 
                $this->addMeta( "http:Content-Type", "$wgMimeType; charset={$wgOutputEncoding}" );
                if ( $sk->commonPrintStylesheet() ) {
@@ -1587,20 +1744,23 @@ class OutputPage {
                $ret .= implode( "\n", array(
                        $this->getHeadLinks(),
                        $this->buildCssLinks(),
-                       $sk->getHeadScripts( $this->mAllowUserJs, $this->mScripts ),
+                       $sk->getHeadScripts( $this ),
                        $this->getHeadItems(),
                ));
                if( $sk->usercss ){
                        $ret .= "<style type='text/css'>{$sk->usercss}</style>";
                }
 
+               if( $wgEnableScriptLoader )
+                       $ret .= $this->getScriptLoaderJs();
+
                if ($wgUseTrackbacks && $this->isArticleRelated())
                        $ret .= $this->getTitle()->trackbackRDF();
 
                $ret .= "</head>\n";
                return $ret;
        }
-       
+
        protected function addDefaultMeta() {
                global $wgVersion, $wgHtml5;
 
@@ -1615,7 +1775,7 @@ class OutputPage {
                        $this->addMeta( 'http:Content-Style-Type', 'text/css' ); //bug 15835
                }
                $this->addMeta( 'generator', "MediaWiki $wgVersion" );
-               
+
                $p = "{$this->mIndexPolicy},{$this->mFollowPolicy}";
                if( $p !== 'index,follow' ) {
                        // http://www.robotstxt.org/wc/meta-user.html
@@ -1637,12 +1797,12 @@ class OutputPage {
         */
        public function getHeadLinks() {
                global $wgRequest, $wgFeed;
-               
+
                // Ideally this should happen earlier, somewhere. :P
                $this->addDefaultMeta();
-               
+
                $tags = array();
-               
+
                foreach ( $this->mMetatags as $tag ) {
                        if ( 0 == strcasecmp( 'http:', substr( $tag[0], 0, 5 ) ) ) {
                                $a = 'http-equiv';
@@ -1672,19 +1832,19 @@ class OutputPage {
                                        wfMsg( "page-{$format}-feed", $this->getTitle()->getPrefixedText() ) ); # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
                        }
 
-                       # Recent changes feed should appear on every page (except recentchanges, 
-                       # that would be redundant). Put it after the per-page feed to avoid 
-                       # changing existing behavior. It's still available, probably via a 
+                       # Recent changes feed should appear on every page (except recentchanges,
+                       # that would be redundant). Put it after the per-page feed to avoid
+                       # changing existing behavior. It's still available, probably via a
                        # menu in your browser. Some sites might have a different feed they'd
                        # like to promote instead of the RC feed (maybe like a "Recent New Articles"
                        # or "Breaking news" one). For this, we see if $wgOverrideSiteFeed is defined.
                        # If so, use it instead.
-                       
+
                        global $wgOverrideSiteFeed, $wgSitename, $wgFeedClasses;
                        $rctitle = SpecialPage::getTitleFor( 'Recentchanges' );
-                       
+
                        if ( $wgOverrideSiteFeed ) {
-                               foreach ( $wgOverrideSiteFeed as $type => $feedUrl ) { 
+                               foreach ( $wgOverrideSiteFeed as $type => $feedUrl ) {
                                        $tags[] = $this->feedLink (
                                                $type,
                                                htmlspecialchars( $feedUrl ),
@@ -1755,7 +1915,9 @@ class OutputPage {
                        $options['dir'] = $dir;
                $this->styles[$style] = $options;
        }
-
+       public function addInlineStyle( $style_css ){
+               $this->mScripts .= "<style type=\"text/css\">$style_css</style>";
+       }
        /**
         * Build a set of <link>s for the stylesheets specified in the $this->styles array.
         * These will be applied to various media & IE conditionals.
index 86a988e..cc96076 100644 (file)
@@ -616,4 +616,4 @@ abstract class WantedQueryPage extends QueryPage {
                $wgLang->formatNum( $result->value ) );
                return $skin->link( $wlh, $label, array(), array( 'target' => $title->getPrefixedText() ) );
        }
-}
+}
\ No newline at end of file
index 821b6ea..23d636f 100644 (file)
@@ -62,7 +62,7 @@ class Skin extends Linker {
                }
                return $wgValidSkinNames;
        }
-       
+
        /**
         * Fetch the list of usable skins in regards to $wgSkipSkins.
         * Useful for Special:Preferences and other places where you
@@ -277,7 +277,7 @@ class Skin extends Linker {
                $this->userpage = $wgUser->getUserPage()->getPrefixedText();
                $this->usercss = false;
        }
-       
+
        /**
         * Set the title
         * @param Title $t The title to use
@@ -285,7 +285,7 @@ class Skin extends Linker {
        public function setTitle( $t ) {
                $this->mTitle = $t;
        }
-       
+
        /** Get the title */
        public function getTitle() {
                return $this->mTitle;
@@ -319,7 +319,7 @@ class Skin extends Linker {
                $out->out( $out->mBodytext . "\n" );
 
                $out->out( $this->afterContent() );
-               
+
                $out->out( $afterContent );
 
                $out->out( $this->bottomScripts() );
@@ -333,21 +333,13 @@ class Skin extends Linker {
        static function makeVariablesScript( $data ) {
                global $wgJsMimeType;
 
-               $doneFirstVar = false;
-               $r = array( "<script type=\"$wgJsMimeType\">/*<![CDATA[*/\n" );
+               $r = array( "<script type=\"$wgJsMimeType\">/*<![CDATA[*/" );
                foreach ( $data as $name => $value ) {
                        $encValue = Xml::encodeJsVar( $value );
-                       if ( $doneFirstVar )
-                               $r[] = ",\n$name=$encValue";
-                       else {
-                               $r[] = "var $name=$encValue";
-                               $doneFirstVar = true;
-                       }
+                       $r[] = "var $name = $encValue;";
                }
-               # No need for ; since the script is terminating
-               $r[] = "\n/*]]>*/</script>\n";
-
-               return implode( $r );
+               $r[] = "/*]]>*/</script>\n";
+               return implode( "\n\t\t", $r );
        }
 
        /**
@@ -418,7 +410,14 @@ class Skin extends Linker {
                if ( !( $wgContLang->hasVariants() ) ) {
                        unset( $vars['wgUserVariant'] );
                }
-               
+
+               //if on upload page output the extension list & js_upload
+               if( SpecialPage::resolveAlias( $wgTitle->getDBkey() ) ==  "Upload" ){
+                       global $wgFileExtensions, $wgAjaxUploadInterface;
+                       $vars['wgFileExtensions']        = $wgFileExtensions;
+                       $vars['wgAjaxUploadInterface'] = $wgAjaxUploadInterface;
+               }
+
                if( $wgUseAjax && $wgEnableMWSuggest && !$wgUser->getOption( 'disablesuggest', false ) ){
                        $vars['wgMWSuggestTemplate'] = SearchEngine::getMWSuggestTemplate();
                        $vars['wgDBname'] = $wgDBname;
@@ -449,49 +448,37 @@ class Skin extends Linker {
 
                return self::makeVariablesScript( $vars );
        }
-
        /**
-        * Return a random selection of the scripts we want in the header, 
-        * according to no particular rhyme or reason.  Various other scripts are 
-        * returned from a haphazard assortment of other functions scattered over 
-        * various files.  This entire hackish system needs to be burned to the 
-        * ground and rebuilt.
+        * Returns the Head Scripts (from local skin context)
         *
-        * @var $allowUserJs bool Should probably be identical to $wgAllowUserJs, 
-        *                        but is passed as a local variable for some 
-        *                        obscure reason.
-        * @var $extraHtml string A bunch of raw HTML to jam into some arbitrary 
-        *                        place where MonoBook has historically wanted it.
-        *                        Old-style skins formerly put it in a different 
-        *                        place, but if either of those is broken it's 
-        *                        likely to be the old-style skins.
-        * @return string Raw HTML to output in some location in the <head> that's 
-        *                entirely arbitrary but which will probably break 
-        *                everything if you put it someplace else.
+        * local $out variable that should be the same as $wgOut
+        *
+        * @return string Raw HTML to output to <head>
         */
-       function getHeadScripts( $allowUserJs, $extraHtml = '' ) {
-               global $wgStylePath, $wgUser, $wgJsMimeType, $wgStyleVersion;
+       function getHeadScripts( OutputPage &$out ) {
+               global $wgStylePath, $wgUser, $wgJsMimeType, $wgStyleVersion, $wgOut;
+               global $wgUseSiteJs;
 
-               $vars = self::makeGlobalVariablesScript( $this->getSkinName() );
+               $vars = self::makeGlobalVariablesScript( array( 'skinname' => $this->getSkinName() ) );
 
-               $r = array( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/wikibits.js?$wgStyleVersion\"></script>\n$extraHtml" );
-               global $wgUseSiteJs;
+               //moved wikibits to be called earlier on
+               //$out->addScriptFile( "{$wgStylePath}/common/wikibits.js" );
                if( $wgUseSiteJs ) {
                        $jsCache = $wgUser->isLoggedIn() ? '&smaxage=0' : '';
-                       $r[] = "<script type=\"$wgJsMimeType\" src=\"".
-                               htmlspecialchars( self::makeUrl( '-',
+                       $wgOut->addScriptFile(  self::makeUrl( '-',
                                        "action=raw$jsCache&gen=js&useskin=" .
-                                       urlencode( $this->getSkinName() ) ) ) .
-                               "\"></script>";
+                                       urlencode( $this->getSkinName() )
+                                       )
+                               );
                }
-               if( $allowUserJs && $wgUser->isLoggedIn() ) {
+               if( $out->isUserJsAllowed() && $wgUser->isLoggedIn() ) {
                        $userpage = $wgUser->getUserPage();
-                       $userjs = htmlspecialchars( self::makeUrl(
+                       $userjs =  self::makeUrl(
                                $userpage->getPrefixedText().'/'.$this->getSkinName().'.js',
-                               'action=raw&ctype='.$wgJsMimeType ) );
-                       $r[] = '<script type="'.$wgJsMimeType.'" src="'.$userjs."\"></script>";
+                               'action=raw&ctype='.$wgJsMimeType );
+                       $wgOut->addScriptFile( $userjs );
                }
-               return $vars . "\t" . implode ( "\n\t", $r );
+               return $vars . "\t" . implode ( "\n\t", $r ) . $out->mScripts;
        }
 
        /**
@@ -529,15 +516,20 @@ class Skin extends Linker {
         * top.  For now Monobook.js will be maintained, but it should be consi-
         * dered deprecated.
         *
+        * @param force_skin  lets you override the skin name
+        *
         * @return string
         */
-       public function generateUserJs() {
+       public function generateUserJs( $skinName = null) {
                global $wgStylePath;
 
                wfProfileIn( __METHOD__ );
+               if(!$skinName){
+                       $skinName =     $this->getSkinName();
+               }
 
                $s = "/* generated javascript */\n";
-               $s .= "var skin = '" . Xml::escapeJsString( $this->getSkinName() ) . "';\n";
+               $s .= "var skin = '" . Xml::escapeJsString($skinName ) . "';\n";
                $s .= "var stylepath = '" . Xml::escapeJsString( $wgStylePath ) . "';";
                $s .= "\n\n/* MediaWiki:Common.js */\n";
                $commonJs = wfMsgForContent( 'common.js' );
@@ -545,10 +537,10 @@ class Skin extends Linker {
                        $s .= $commonJs;
                }
 
-               $s .= "\n\n/* MediaWiki:".ucfirst( $this->getSkinName() ).".js */\n";
+               $s .= "\n\n/* MediaWiki:".ucfirst( $skinName ).".js */\n";
                // avoid inclusion of non defined user JavaScript (with custom skins only)
                // by checking for default message content
-               $msgKey = ucfirst( $this->getSkinName() ).'.js';
+               $msgKey = ucfirst( $skinName ).'.js';
                $userJS = wfMsgForContent( $msgKey );
                if ( !wfEmptyMsg( $msgKey, $userJS ) ) {
                        $s .= $userJS;
@@ -568,7 +560,7 @@ class Skin extends Linker {
                wfProfileOut( __METHOD__ );
                return $s;
        }
-       
+
        /**
         * Split for easier subclassing in SkinSimple, SkinStandard and SkinCologneBlue
         */
@@ -712,7 +704,7 @@ END;
                        ' skin-'. Sanitizer::escapeClass( $this->getSkinName() );
                return $a;
        }
-       
+
        function getPageClasses( $title ) {
                $numeric = 'ns-'.$title->getNamespace();
                if( $title->getNamespace() == NS_SPECIAL ) {
@@ -1381,7 +1373,7 @@ END;
                                        $element[] = $this->emailUserLink();
                                }
                        }
-                       
+
                        $s = implode( $element, $sep );
 
                        if ( $this->mTitle->getArticleId() ) {
@@ -1472,7 +1464,7 @@ END;
                // Allow for site and per-namespace customization of copyright notice.
                if( isset($wgArticle) )
                        wfRunHooks( 'SkinCopyrightFooter', array( $wgArticle->getTitle(), $type, &$msg, &$link ) );
-               
+
                $out .= wfMsgForContent( $msg, $link );
                return $out;
        }
@@ -1654,7 +1646,7 @@ END;
        function editUrlOptions() {
                global $wgArticle;
 
-               $options = array( 'action' => 'edit' ); 
+               $options = array( 'action' => 'edit' );
 
                if( $this->mRevisionId && ! $wgArticle->isCurrent() ) {
                        $options['oldid'] = intval( $this->mRevisionId );
@@ -2080,9 +2072,9 @@ END;
        }
 
        /**
-        * Should we include common/wikiprintable.css?  Skins that have their own 
-        * print stylesheet should override this and return false.  (This is an 
-        * ugly hack to get Monobook to play nicely with 
+        * Should we include common/wikiprintable.css?  Skins that have their own
+        * print stylesheet should override this and return false.  (This is an
+        * ugly hack to get Monobook to play nicely with
         * OutputPage::headElement().)
         *
         * @return bool
@@ -2090,4 +2082,4 @@ END;
        public function commonPrintStylesheet() {
                return true;
        }
-}
+}
\ No newline at end of file
index 82574cd..f915bcb 100644 (file)
@@ -110,9 +110,21 @@ class SkinTemplate extends Skin {
         */
        function setupSkinUserCss( OutputPage $out ){
                $out->addStyle( 'common/shared.css', 'screen' );
-               $out->addStyle( 'common/commonPrint.css', 'print' );    
+               $out->addStyle( 'common/commonPrint.css', 'print' );
        }
-       
+       /* add specific javascript the base Skin class */
+       function setupSkinUserJs( OutputPage $out ){
+               global $wgUseSiteJs;
+               //use site js:
+               if( $wgUseSiteJs ) {
+                       $jsCache = $this->loggedin ? '&smaxage=0' : '';
+                       $siteGenScriptFile =  self::makeUrl( '-',
+                                       "action=raw$jsCache&gen=js&useskin=" .
+                                               urlencode( $this->getSkinName() ) ) ;
+                       $this->jsvarurl = $siteGenScriptFile;
+               }
+       }
+
        /**
         * Create the template engine object; we feed it a bunch of data
         * and eventually it spits out some HTML. Should have interface
@@ -245,7 +257,9 @@ class SkinTemplate extends Skin {
                $tpl->setRef( 'jsmimetype', $wgJsMimeType );
                $tpl->setRef( 'charset', $wgOutputEncoding );
                $tpl->set( 'headlinks', $out->getHeadLinks() );
-               $tpl->set( 'headscripts', $out->getScript() );
+
+               //moved headscripts to near end of template header output
+
                $tpl->set( 'csslinks', $out->buildCssLinks() );
                $tpl->setRef( 'wgScript', $wgScript );
                $tpl->setRef( 'skinname', $this->skinname );
@@ -467,6 +481,9 @@ class SkinTemplate extends Skin {
                $tpl->set( 'sidebar', $this->buildSidebar() );
                $tpl->set( 'nav_urls', $this->buildNavUrls() );
 
+               //set the head script near the end (in case above actions result in adding scripts)
+               $tpl->set( 'headscripts', $out->getScript() );
+
                // original version by hansm
                if( !wfRunHooks( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
                        wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!\n" );
@@ -603,7 +620,7 @@ class SkinTemplate extends Skin {
                                );
                        }
                }
-               
+
                wfRunHooks( 'PersonalUrls', array( &$personal_urls, &$title ) );
                wfProfileOut( __METHOD__ );
                return $personal_urls;
@@ -710,16 +727,16 @@ class SkinTemplate extends Skin {
                                        'href' => $this->mTitle->getLocalUrl( $this->editUrlOptions() )
                                );
 
-                               // adds new section link if page is a current revision of a talk page or 
+                               // adds new section link if page is a current revision of a talk page or
                                if ( ( $wgArticle && $wgArticle->isCurrent() && $istalk ) || $wgOut->showNewSectionLink() ) {
                                        if ( !$wgOut->forceHideNewSectionLink() ) {
                                                $content_actions['addsection'] = array(
                                                        'class' => $section == 'new' ? 'selected' : false,
                                                        'text' => wfMsg( 'addsection' ),
                                                        'href' => $this->mTitle->getLocalUrl( 'action=edit&section=new' )
-                                               );                                      
+                                               );
                                        }
-                               }  
+                               }
                        } elseif ( $this->mTitle->isKnown() ) {
                                $content_actions['viewsource'] = array(
                                        'class' => ($action == 'edit') ? 'selected' : false,
@@ -992,7 +1009,6 @@ class SkinTemplate extends Skin {
         */
        function setupUserJs( $allowUserJs ) {
                global $wgRequest, $wgJsMimeType;
-
                wfProfileIn( __METHOD__ );
 
                $action = $wgRequest->getVal( 'action', 'view' );
index bdd2a2e..6db66ba 100644 (file)
@@ -92,13 +92,12 @@ function wfGetType( $filename, $safe = true ) {
        if ( $safe ) {
                global $wgFileBlacklist, $wgCheckFileExtensions, $wgStrictFileExtensions, 
                        $wgFileExtensions, $wgVerifyMimeType, $wgMimeTypeBlacklist, $wgRequest;
-               $form = new UploadForm( $wgRequest );
-               list( $partName, $extList ) = $form->splitExtensions( $filename );
-               if ( $form->checkFileExtensionList( $extList, $wgFileBlacklist ) ) {
+               list( $partName, $extList ) = UploadBase::splitExtensions( $filename );
+               if ( UploadBase::checkFileExtensionList( $extList, $wgFileBlacklist ) ) {
                        return 'unknown/unknown';
                }
                if ( $wgCheckFileExtensions && $wgStrictFileExtensions 
-                       && !$form->checkFileExtensionList( $extList, $wgFileExtensions ) )
+                       && !UploadBase::checkFileExtensionList( $extList, $wgFileExtensions ) )
                {
                        return 'unknown/unknown';
                }
index cdd4c5a..10e96af 100644 (file)
@@ -829,6 +829,7 @@ abstract class ApiBase {
                'toofewexpiries' => array('code' => 'toofewexpiries', 'info' => "\$1 expiry timestamps were provided where \$2 were needed"),
                'cantimport' => array('code' => 'cantimport', 'info' => "You don't have permission to import pages"),
                'cantimport-upload' => array('code' => 'cantimport-upload', 'info' => "You don't have permission to import uploaded pages"),
+               'nouploadmodule' => array( 'code' => 'nomodule', 'info' => 'No upload module set' ),            
                'importnofile' => array('code' => 'nofile', 'info' => "You didn't upload a file"),
                'importuploaderrorsize' => array('code' => 'filetoobig', 'info' => 'The file you uploaded is bigger than the maximum upload size'),
                'importuploaderrorpartial' => array('code' => 'partialupload', 'info' => 'The file was only partially uploaded'),
index e89c867..cf1f16c 100644 (file)
@@ -66,11 +66,19 @@ class ApiFormatJson extends ApiFormatBase {
                // Some versions of PHP have a broken json_encode, see PHP bug 
                // 46944. Test encoding an affected character (U+20000) to 
                // avoid this.
-               if (!function_exists('json_encode') || $this->getIsHtml() || strtolower(json_encode("\xf0\xa0\x80\x80")) != '"\ud840\udc00"') {
+               $this->printText( $prefix . $this->getJsonEncode($this->getResultData(),   $this->getIsHtml() )  . $suffix);            
+       }       
+       /*
+        * static to support static calls to json output (instead of json_encode function) 
+        * @param array $results  the results array to output as a json string
+        * @parm isHTML if the output is html
+        */     
+       public static function getJsonEncode($value, $isHtml=false){
+               if (!function_exists('json_encode') || $isHtml || strtolower(json_encode("\xf0\xa0\x80\x80")) != '\ud840\udc00') {
                        $json = new Services_JSON();
-                       $this->printText($prefix . $json->encode($this->getResultData(), $this->getIsHtml()) . $suffix);
+                       return $json->encode($value, $isHtml) ;
                } else {
-                       $this->printText($prefix . json_encode($this->getResultData()) . $suffix);
+                       return json_encode($value);
                }
        }
 
index 5a7d3a2..17fa068 100644 (file)
@@ -76,6 +76,7 @@ class ApiMain extends ApiBase {
                'unblock' => 'ApiUnblock',
                'move' => 'ApiMove',
                'edit' => 'ApiEditPage',
+               'upload' => 'ApiUpload',
                'emailuser' => 'ApiEmailUser',
                'watch' => 'ApiWatch',
                'patrol' => 'ApiPatrol',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
new file mode 100644 (file)
index 0000000..14afc62
--- /dev/null
@@ -0,0 +1,347 @@
+<?php
+
+/*
+ * Created on Aug 21, 2008
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2008 - 2009 Bryan Tong Minh <Bryan.TongMinh@Gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+       // Eclipse helper - will be ignored in production
+       require_once ("ApiBase.php");
+}
+
+
+/**
+ * @ingroup API
+ */
+class ApiUpload extends ApiBase {
+       var $mUpload = null;
+
+       public function __construct($main, $action) {
+               parent :: __construct($main, $action);
+       }
+
+       public function execute() {
+               global $wgUser;
+
+
+               $this->getMain()->isWriteMode();
+               $this->mParams = $this->extractRequestParams();
+               $request = $this->getMain()->getRequest();
+
+               //do token checks:
+               if(is_null($this->mParams['token']))
+                       $this->dieUsageMsg(array('missingparam', 'token'));
+               if(!$wgUser->matchEditToken($this->mParams['token']))
+                       $this->dieUsageMsg(array('sessionfailure'));
+
+
+               // Add the uploaded file to the params array
+               $this->mParams['file'] = $request->getFileName( 'file' );
+
+               // Check whether upload is enabled
+               if( !UploadBase::isEnabled() )
+                       $this->dieUsageMsg( array( 'uploaddisabled' ) );
+
+               wfDebug("running require param\n");
+               // One and only one of the following parameters is needed
+               $this->requireOnlyOneParameter( $this->mParams,
+                       'sessionkey', 'file', 'url', 'enablechunks' );
+
+               if( $this->mParams['enablechunks'] ){
+                       //chunks upload enabled
+                       $this->mUpload = new UploadFromChunks();
+                       $this->mUpload->initializeFromParams( $this->mParams, $request );
+
+                       //if getAPIresult did not exit report the status error:
+                       if( isset( $this->mUpload->status[ 'error' ] ) )
+                               $this->dieUsageMsg( $this->mUpload->status[ 'error' ] );
+
+               }else if( $this->mParams['internalhttpsession'] ){
+                       $sd = & $_SESSION['wsDownload'][ $this->mParams['internalhttpsession'] ];
+
+                       //get the params from the init session:
+                       $this->mUpload = new UploadFromFile();
+
+                       $this->mUpload->initialize( $this->mParams['filename'],
+                               $sd['target_file_path'],
+                               filesize( $sd['target_file_path'] )
+                       );
+
+                       if( !isset( $this->mUpload ) )
+                               $this->dieUsage( 'No upload module set', 'nomodule' );
+
+               }else if( $this->mParams['httpstatus'] && $this->mParams['sessionkey']){
+                       //return the status of the given upload session_key:
+                       if(!isset($_SESSION['wsDownload'][ $this->mParams['sessionkey'] ])){
+                                       return $this->getResult()->addValue( null, $this->getModuleName(),
+                                                                       array( 'error' => 'invalid-session-key'
+                                                       ));
+                       }
+                       $sd = & $_SESSION['wsDownload'][ $this->mParams['sessionkey'] ];
+                       //keep passing down the upload sessionkey
+                       $statusResult = array(
+                               'upload_session_key' => $this->mParams['sessionkey']
+                       );
+
+                       //put values into the final apiResult if available
+                       if( isset($sd['apiUploadResult'])) $statusResult['apiUploadResult'] = $sd['apiUploadResult'];
+                       if( isset($sd['loaded']) ) $statusResult['loaded'] = $sd['loaded'];
+                       if( isset($sd['content_length']) ) $statusResult['content_length'] = $sd['content_length'];
+
+                       return $this->getResult()->addValue( null, $this->getModuleName(),
+                                               $statusResult
+                       );
+               }else if( $this->mParams['sessionkey'] ) {
+                       // Stashed upload
+                       $this->mUpload = new UploadFromStash();
+                       $this->mUpload->initialize( $this->mParams['filename'], $_SESSION['wsUploadData'][$this->mParams['sessionkey']] );
+               }else{
+                       // Upload from url or file
+                       // Parameter filename is required
+                       if( !isset( $this->mParams['filename'] ) )
+                               $this->dieUsageMsg( array( 'missingparam', 'filename' ) );
+
+                       // Initialize $this->mUpload
+                       if( isset( $this->mParams['file'] ) ) {
+                               $this->mUpload = new UploadFromFile();
+                               $this->mUpload->initialize(
+                                       $request->getFileName( 'file' ),
+                                       $request->getFileTempName( 'file' ),
+                                       $request->getFileSize( 'file' )
+                               );
+                       } elseif( isset( $this->mParams['url'] ) ) {
+
+                               $this->mUpload = new UploadFromUrl();
+                               $this->mUpload->initialize(  $this->mParams['filename'], $this->mParams['url'], $this->mParams['asyncdownload']);
+
+                               $status = $this->mUpload->fetchFile();
+                               if( !$status->isOK() ){
+                                       return $this->dieUsage( 'fetchfileerror', $status->getWikiText() );
+                               }
+                               //check if we doing a async request set session info and return the upload_session_key)
+                               if( $this->mUpload->isAsync() ){
+                                       $upload_session_key = $status->value;
+                                       //update the session with anything with the params we will need to finish up the upload later on:
+                                       if(!isset($_SESSION['wsDownload'][$upload_session_key]))
+                                               $_SESSION['wsDownload'][$upload_session_key] = array();
+
+                                       $sd =& $_SESSION['wsDownload'][$upload_session_key];
+
+                                       //copy mParams for finishing up after:
+                                       $sd['mParams'] = $this->mParams;
+
+                                       return $this->getResult()->addValue( null, $this->getModuleName(),
+                                                                       array( 'upload_session_key' => $upload_session_key
+                                                       ));
+                               }
+                               //else the file downloaded in place continue with validation:
+                       }
+               }
+
+               if( !isset( $this->mUpload ) )
+                       $this->dieUsage( 'No upload module set', 'nomodule' );
+
+               //finish up the exec command:
+               $this->doExecUpload();
+       }
+       function doExecUpload(){
+               global $wgUser;
+               //Check whether the user has the appropriate permissions to upload anyway
+               $permission = $this->mUpload->isAllowed( $wgUser );
+
+
+               if( $permission !== true ) {
+                       if( !$wgUser->isLoggedIn() )
+                               $this->dieUsageMsg( array( 'mustbeloggedin', 'upload' ) );
+                       else
+                               $this->dieUsageMsg( array( 'badaccess-groups' ) );
+               }
+               // Perform the upload
+               $result = $this->performUpload();
+               // Cleanup any temporary mess
+               $this->mUpload->cleanupTempFile();
+               $this->getResult()->addValue( null, $this->getModuleName(), $result );
+       }
+       private function performUpload() {
+               global $wgUser;
+               $result = array();
+               $resultDetails = null;
+               $permErrors = $this->mUpload->verifyPermissions( $wgUser );
+               if( $permErrors !== true ) {
+                       $result['result'] = 'Failure';
+                       $result['error'] = 'permission-denied';
+                       return $result;
+               }
+               $verification = $this->mUpload->verifyUpload( $resultDetails );
+               if( $verification != UploadBase::OK ) {
+                       $result['result'] = 'Failure';
+                       switch( $verification ) {
+                               case UploadBase::EMPTY_FILE:
+                                       $result['error'] = 'empty-file';
+                                       break;
+                               case UploadBase::FILETYPE_MISSING:
+                                       $result['error'] = 'filetype-missing';
+                                       break;
+                               case UploadBase::FILETYPE_BADTYPE:
+                                       global $wgFileExtensions;
+                                       $result['error'] = 'filetype-banned';
+                                       $result['filetype'] = $resultDetails['finalExt'];
+                                       $result['allowed-filetypes'] = $wgFileExtensions;
+                                       break;
+                               case UploadBase::MIN_LENGHT_PARTNAME:
+                                       $result['error'] = 'filename-tooshort';
+                                       break;
+                               case UploadBase::ILLEGAL_FILENAME:
+                                       $result['error'] = 'illegal-filename';
+                                       $result['filename'] = $resultDetails['filtered'];
+                                       break;
+                               case UploadBase::OVERWRITE_EXISTING_FILE:
+                                       $result['error'] = 'overwrite';
+                                       break;
+                               case UploadBase::VERIFICATION_ERROR:
+                                       $result['error'] = 'verification-error';
+                                       $args = $resultDetails['veri'];
+                                       $code = array_shift( $args );
+                                       $result['verification-error'] = $code;
+                                       $result['args'] = $args;
+                                       $this->getResult()->setIndexedTagName( $result['args'], 'arg' );
+                                       break;
+                               case UploadBase::UPLOAD_VERIFICATION_ERROR:
+                                       $result['error'] = 'upload-verification-error';
+                                       $result['upload-verification-error'] = $resultDetails['error'];
+                                       break;
+                               default:
+                                       $result['error'] = 'unknown-error';
+                                       $result['code'] = $verification;
+                                       break;
+                       }
+                       return $result;
+               }
+               if( !$this->mParams['ignorewarnings'] ) {
+                       $warnings = $this->mUpload->checkWarnings();
+                       if( $warnings ) {
+                               $this->getResult()->setIndexedTagName( $warnings, 'warning' );
+
+                               $result['result'] = 'Warning';
+                               $result['warnings'] = $warnings;
+                               if( isset( $result['filewasdeleted'] ) )
+                                       $result['filewasdeleted'] = $result['filewasdeleted']->getDBkey();
+
+                               $sessionKey = $this->mUpload->stashSession();
+                               if( $sessionKey )
+                                       $result['sessionkey'] = $sessionKey;
+                               return $result;
+                       }
+               }
+               //do the upload
+               $status = $this->mUpload->performUpload( $this->mParams['comment'],
+                       $this->mParams['comment'], $this->mParams['watch'], $wgUser );
+
+               if( !$status->isGood() ) {
+                       $result['result'] = 'Failure';
+                       $result['error'] = 'internal-error';
+                       $result['details'] = $status->getErrorsArray();
+                       $this->getResult()->setIndexedTagName( $result['details'], 'error' );
+                       return $result;
+               }
+
+               $file = $this->mUpload->getLocalFile();
+               $result['result'] = 'Success';
+               $result['filename'] = $file->getName();
+
+
+               // Append imageinfo to the result
+
+               //might be a cleaner way to call this:
+               $imParam = ApiQueryImageInfo::getAllowedParams();
+               $imProp = $imParam['prop'][ApiBase :: PARAM_TYPE];
+               $result['imageinfo'] = ApiQueryImageInfo::getInfo( $file,
+                       array_flip( $imProp ),
+                       $this->getResult() );
+
+               wfDebug("\n\n return result: " . print_r($result, true));
+
+               return $result;
+       }
+
+       public function mustBePosted() {
+               return true;
+       }
+
+       public function getAllowedParams() {
+               return array (
+                       'filename' => null,
+                       'file' => null,
+                       'chunk' => null,
+                       'url' => null,
+                   'token' => null,
+                       'enablechunks' => null,
+                       'comment' => array(
+                               ApiBase :: PARAM_DFLT => ''
+                       ),
+                       'asyncdownload'=>false,
+                       'watch' => false,
+                       'ignorewarnings' => false,
+                       'done'  => false,
+                       'sessionkey' => null,
+                       'httpstatus' => null,
+                       'chunksessionkey'=> null,
+                       'internalhttpsession'=> null,
+               );
+       }
+
+       public function getParamDescription() {
+               return array (
+                       'filename' => 'Target filename',
+                       'file' => 'File contents',
+                       'chunk'=> 'Chunk File Contents',
+                       'url' => 'Url to upload from',
+                       'comment' => 'Upload comment or initial page text',
+                       'token' => 'Edit token. You can get one of these through prop=info (this helps avoid remote ajax upload requests with your credentials)',
+                       'enablechunks' => 'Boolean If we are in chunk mode; accepts many small file POSTs',
+                       'asyncdownload' => 'If we should download the url asyncrously usefull for large http downloads (returns a upload session key to get status updates in subquent calls)',
+                       'watch' => 'Watch the page',
+                       'ignorewarnings' => 'Ignore any warnings',
+                       'done'  => 'When used with "chunks", Is sent to notify the api The last chunk is being uploaded.',
+                       'sessionkey' => 'Session key in case there were any warnings.',
+                       'httpstatus' => 'When set to true, will return the status of a given sessionKey (used for progress meters)',
+                       'chunksessionkey' => 'Used to sync uploading of chunks',
+                       'internalhttpsession' => 'Used internally for http session downloads',
+               );
+       }
+
+       public function getDescription() {
+               return array(
+                       'Upload an File'
+               );
+       }
+
+       protected function getExamples() {
+               return array (
+                       'api.php?action=upload&filename=Wiki.png&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&ignorewarnings'
+               );
+       }
+
+       public function getVersion() {
+               return __CLASS__ . ': $Id: ApiUpload.php 51812 2009-06-12 23:45:20Z dale $';
+       }
+}
+
index c0a50ef..680ec93 100644 (file)
@@ -212,7 +212,32 @@ class FSRepo extends FileRepo {
                }
                return $status;
        }
+       function append( $srcPath, $toAppendPath ){
+               $status = $this->newGood();
 
+               //resolve the virtual url:
+               if ( self::isVirtualUrl( $srcPath ) ) {
+                               $srcPath = $this->resolveVirtualUrl( $srcPath );
+               }
+               //make sure files are there: 
+               if ( !is_file( $srcPath ) )                             
+                       $status->fatal( 'append-src-filenotfound', $srcPath );
+                       
+               if ( !is_file( $toAppendPath ) )                                
+                       $status->fatal( 'append-toappend-filenotfound', $toAppendPath );
+                       
+               //do the append: 
+               if( file_put_contents( $srcPath, file_get_contents( $toAppendPath ), FILE_APPEND ) ){
+                       $status->value = $srcPath;
+               }else{
+                       $status->fatal( 'fileappenderror', $toAppendPath,  $srcPath);
+               }
+               
+               //either way remove the append chunk as we have no use for it now:
+               unlink($toAppendPath);
+                       
+               return $status;         
+       }
        /**
         * Checks existence of specified array of files.
         *
index 9b28816..e08afff 100644 (file)
@@ -18,38 +18,22 @@ function wfSpecialUpload() {
  * implements Special:Upload
  * @ingroup SpecialPage
  */
-class UploadForm {
-       const SUCCESS = 0;
-       const BEFORE_PROCESSING = 1;
-       const LARGE_FILE_SERVER = 2;
-       const EMPTY_FILE = 3;
-       const MIN_LENGTH_PARTNAME = 4;
-       const ILLEGAL_FILENAME = 5;
-       const PROTECTED_PAGE = 6;
-       const OVERWRITE_EXISTING_FILE = 7;
-       const FILETYPE_MISSING = 8;
-       const FILETYPE_BADTYPE = 9;
-       const VERIFICATION_ERROR = 10;
-       const UPLOAD_VERIFICATION_ERROR = 11;
-       const UPLOAD_WARNING = 12;
-       const INTERNAL_ERROR = 13;
-
+class UploadForm extends SpecialPage {
        /**#@+
         * @access private
         */
-       var $mComment, $mLicense, $mIgnoreWarning, $mCurlError;
-       var $mDestName, $mTempPath, $mFileSize, $mFileProps;
+       var $mComment, $mLicense, $mIgnoreWarning;
        var $mCopyrightStatus, $mCopyrightSource, $mReUpload, $mAction, $mUploadClicked;
-       var $mSrcName, $mSessionKey, $mStashed, $mDesiredDestName, $mRemoveTempFile, $mSourceType;
-       var $mDestWarningAck, $mCurlDestHandle;
+       var $mDestWarningAck;
        var $mLocalFile;
 
+       var $mUpload;   // Instance of UploadBase or derivative
+
        # Placeholders for text injection by hooks (must be HTML)
        # extensions should take care to _append_ to the present value
        var $uploadFormTextTop;
        var $uploadFormTextAfterSummary;
-
-       const SESSION_VERSION = 1;
+    var $mTokenOk = false;
        /**#@-*/
 
        /**
@@ -57,23 +41,29 @@ class UploadForm {
         * Get data POSTed through the form and assign them to the object
         * @param $request Data posted.
         */
-       function UploadForm( &$request ) {
-               global $wgAllowCopyUploads;
+       function __construct( &$request ) {
+           global $wgUser;
+               // Guess the desired name from the filename if not provided
                $this->mDesiredDestName   = $request->getText( 'wpDestFile' );
+               if( !$this->mDesiredDestName )
+                       $this->mDesiredDestName = $request->getText( 'wpUploadFile' );
+
                $this->mIgnoreWarning     = $request->getCheck( 'wpIgnoreWarning' );
                $this->mComment           = $request->getText( 'wpUploadDescription' );
-               $this->mForReUpload       = $request->getBool( 'wpForReUpload' );
-               $this->mReUpload          = $request->getCheck( 'wpReUpload' );
 
                if( !$request->wasPosted() ) {
                        # GET requests just give the main form; no data except destination
                        # filename and description
                        return;
                }
+               //if it was posted check for the token (no remote POST'ing with user credentials)
+               $token = $request->getVal( 'wpEditToken' );
+               $this->mTokenOk = $wgUser->matchEditToken( $token );
 
                # Placeholders for text injection by hooks (empty per default)
                $this->uploadFormTextTop = "";
                $this->uploadFormTextAfterSummary = "";
+
                $this->mUploadClicked     = $request->getCheck( 'wpUpload' );
 
                $this->mLicense           = $request->getText( 'wpLicense' );
@@ -83,145 +73,13 @@ class UploadForm {
                $this->mSourceType        = $request->getText( 'wpSourceType' );
                $this->mDestWarningAck    = $request->getText( 'wpDestFileWarningAck' );
 
-               $this->mAction            = $request->getVal( 'action' );
-
-               $this->mSessionKey        = $request->getInt( 'wpSessionKey' );
-               if( !empty( $this->mSessionKey ) &&
-                       isset( $_SESSION['wsUploadData'][$this->mSessionKey]['version'] ) &&
-                       $_SESSION['wsUploadData'][$this->mSessionKey]['version'] == self::SESSION_VERSION ) {
-                       /**
-                        * Confirming a temporarily stashed upload.
-                        * We don't want path names to be forged, so we keep
-                        * them in the session on the server and just give
-                        * an opaque key to the user agent.
-                        */
-                       $data = $_SESSION['wsUploadData'][$this->mSessionKey];
-                       $this->mTempPath         = $data['mTempPath'];
-                       $this->mFileSize         = $data['mFileSize'];
-                       $this->mSrcName          = $data['mSrcName'];
-                       $this->mFileProps        = $data['mFileProps'];
-                       $this->mCurlError        = 0/*UPLOAD_ERR_OK*/;
-                       $this->mStashed          = true;
-                       $this->mRemoveTempFile   = false;
-               } else {
-                       /**
-                        *Check for a newly uploaded file.
-                        */
-                       if( $wgAllowCopyUploads && $this->mSourceType == 'web' ) {
-                               $this->initializeFromUrl( $request );
-                       } else {
-                               $this->initializeFromUpload( $request );
-                       }
-               }
-       }
-
-       /**
-        * Initialize the uploaded file from PHP data
-        * @access private
-        */
-       function initializeFromUpload( $request ) {
-               $this->mTempPath       = $request->getFileTempName( 'wpUploadFile' );
-               $this->mFileSize       = $request->getFileSize( 'wpUploadFile' );
-               $this->mSrcName        = $request->getFileName( 'wpUploadFile' );
-               $this->mCurlError      = $request->getUploadError( 'wpUploadFile' );
-               $this->mSessionKey     = false;
-               $this->mStashed        = false;
-               $this->mRemoveTempFile = false; // PHP will handle this
-       }
+               $this->mForReUpload       = $request->getBool( 'wpForReUpload' );
+               $this->mReUpload          = $request->getCheck( 'wpReUpload' );
 
-       /**
-        * Copy a web file to a temporary file
-        * @access private
-        */
-       function initializeFromUrl( $request ) {
-               global $wgTmpDirectory;
-               $url = $request->getText( 'wpUploadFileURL' );
-               $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' );
-
-               $this->mTempPath       = $local_file;
-               $this->mFileSize       = 0; # Will be set by curlCopy
-               $this->mCurlError      = $this->curlCopy( $url, $local_file );
-               $pathParts             = explode( '/', $url );
-               $this->mSrcName        = array_pop( $pathParts );
-               $this->mSessionKey     = false;
-               $this->mStashed        = false;
-
-               // PHP won't auto-cleanup the file
-               $this->mRemoveTempFile = file_exists( $local_file );
+               $this->mAction            = $request->getVal( 'action' );
+               $this->mUpload                    = UploadBase::createFromRequest( $request );
        }
 
-       /**
-        * Safe copy from URL
-        * Returns true if there was an error, false otherwise
-        */
-       private function curlCopy( $url, $dest ) {
-               global $wgUser, $wgOut, $wgHTTPProxy, $wgCopyUploadTimeout;
-
-               if( !$wgUser->isAllowed( 'upload_by_url' ) ) {
-                       $wgOut->permissionRequired( 'upload_by_url' );
-                       return true;
-               }
-
-               # Maybe remove some pasting blanks :-)
-               $url =  trim( $url );
-               if( stripos($url, 'http://') !== 0 && stripos($url, 'ftp://') !== 0 ) {
-                       # Only HTTP or FTP URLs
-                       $wgOut->showErrorPage( 'upload-proto-error', 'upload-proto-error-text' );
-                       return true;
-               }
-
-               # Open temporary file
-               $this->mCurlDestHandle = @fopen( $this->mTempPath, "wb" );
-               if( $this->mCurlDestHandle === false ) {
-                       # Could not open temporary file to write in
-                       $wgOut->showErrorPage( 'upload-file-error', 'upload-file-error-text');
-                       return true;
-               }
-
-               $ch = curl_init();
-               curl_setopt( $ch, CURLOPT_HTTP_VERSION, 1.0); # Probably not needed, but apparently can work around some bug
-               curl_setopt( $ch, CURLOPT_TIMEOUT, $wgCopyUploadTimeout); # Default 30 seconds timeout
-               curl_setopt( $ch, CURLOPT_LOW_SPEED_LIMIT, 512); # 0.5KB per second minimum transfer speed
-               curl_setopt( $ch, CURLOPT_URL, $url);
-               if( $wgHTTPProxy ) {
-                       curl_setopt( $ch, CURLOPT_PROXY, $wgHTTPProxy );
-               }
-               curl_setopt( $ch, CURLOPT_WRITEFUNCTION, array( $this, 'uploadCurlCallback' ) );
-               curl_exec( $ch );
-               $error = curl_errno( $ch ) ? true : false;
-               $errornum =  curl_errno( $ch );
-               // if ( $error ) print curl_error ( $ch ) ; # Debugging output
-               curl_close( $ch );
-
-               fclose( $this->mCurlDestHandle );
-               unset( $this->mCurlDestHandle );
-               if( $error ) {
-                       unlink( $dest );
-                       if( wfEmptyMsg( "upload-curl-error$errornum", wfMsg("upload-curl-error$errornum") ) )
-                               $wgOut->showErrorPage( 'upload-misc-error', 'upload-misc-error-text' );
-                       else
-                               $wgOut->showErrorPage( "upload-curl-error$errornum", "upload-curl-error$errornum-text" );
-               }
-
-               return $error;
-       }
-
-       /**
-        * Callback function for CURL-based web transfer
-        * Write data to file unless we've passed the length limit;
-        * if so, abort immediately.
-        * @access private
-        */
-       function uploadCurlCallback( $ch, $data ) {
-               global $wgMaxUploadSize;
-               $length = strlen( $data );
-               $this->mFileSize += $length;
-               if( $this->mFileSize > $wgMaxUploadSize ) {
-                       return 0;
-               }
-               fwrite( $this->mCurlDestHandle, $data );
-               return $length;
-       }
 
        /**
         * Start doing stuff
@@ -229,29 +87,22 @@ class UploadForm {
         */
        function execute() {
                global $wgUser, $wgOut;
-               global $wgEnableUploads;
-
-               # Check php's file_uploads setting
-               if( !wfIniGetBool( 'file_uploads' ) ) {
-                       $wgOut->showErrorPage( 'uploaddisabled', 'php-uploaddisabledtext', array( $this->mDesiredDestName ) );
-                       return;
-               }
-
                # Check uploading enabled
-               if( !$wgEnableUploads ) {
-                       $wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext', array( $this->mDesiredDestName ) );
+               if( !UploadBase::isEnabled() ) {
+                       $wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext' );
                        return;
                }
-
                # Check permissions
-               global $wgGroupPermissions;
-               if( !$wgUser->isAllowed( 'upload' ) ) {
-                       if( !$wgUser->isLoggedIn() && ( $wgGroupPermissions['user']['upload']
-                               || $wgGroupPermissions['autoconfirmed']['upload'] ) ) {
-                               // Custom message if logged-in users without any special rights can upload
+               if( $this->mUpload ) {
+                       $permission = $this->mUpload->isAllowed( $wgUser );
+               } else {
+                       $permission = $wgUser->isAllowed( 'upload' ) ? true : 'upload';
+               }
+               if( $permission !== true ) {
+                       if( !$wgUser->isLoggedIn() ) {
                                $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
                        } else {
-                               $wgOut->permissionRequired( 'upload' );
+                               $wgOut->permissionRequired( $permission );
                        }
                        return;
                }
@@ -266,108 +117,128 @@ class UploadForm {
                        $wgOut->readOnlyPage();
                        return;
                }
+               //check token if uploading or reUploading
+               if( !$this->mTokenOk && !$this->mReUpload && ($this->mUpload && (
+                                               'submit' == $this->mAction ||
+                                               $this->mUploadClicked
+                                       )
+                               )
+               ){
+                   $this->mainUploadForm ( wfMsg( 'session_fail_preview' ) );
+                   return ;
+               }
+
 
                if( $this->mReUpload ) {
-                       if( !$this->unsaveUploadedFile() ) {
+                       // User choose to cancel upload
+                       if( !$this->mUpload->unsaveUploadedFile() ) {
                                return;
                        }
                        # Because it is probably checked and shouldn't be
                        $this->mIgnoreWarning = false;
-                       
                        $this->mainUploadForm();
-               } else if( 'submit' == $this->mAction || $this->mUploadClicked ) {
+               } elseif( $this->mUpload && (
+                                       'submit' == $this->mAction ||
+                                       $this->mUploadClicked
+                               ) ) {
                        $this->processUpload();
                } else {
                        $this->mainUploadForm();
                }
 
-               $this->cleanupTempFile();
+               if( $this->mUpload )
+                       $this->mUpload->cleanupTempFile();
        }
 
        /**
         * Do the upload
         * Checks are made in SpecialUpload::execute()
         *
+        * FIXME this should really use the standard Status class (instead of associative array)
+        * FIXME would be nice if we refactored this into the upload api.
+        *                      (the special upload page is not the only response point that needs clean localized error msgs)
+        *
         * @access private
         */
        function processUpload(){
                global $wgOut, $wgFileExtensions, $wgLang;
-               $details = null;
-               $value = null;
-               $value = $this->internalProcessUpload( $details );
-
-               switch($value) {
-                       case self::SUCCESS:
+               $details = $this->internalProcessUpload();
+               switch( $details['status'] ) {
+                       case UploadBase::SUCCESS:
                                $wgOut->redirect( $this->mLocalFile->getTitle()->getFullURL() );
                                break;
 
-                       case self::BEFORE_PROCESSING:
+                       case UploadBase::BEFORE_PROCESSING:
+                               $this->uploadError( $details['error'] );
                                break;
-
-                       case self::LARGE_FILE_SERVER:
+                       case UploadBase::LARGE_FILE_SERVER:
                                $this->mainUploadForm( wfMsgHtml( 'largefileserver' ) );
                                break;
 
-                       case self::EMPTY_FILE:
+                       case UploadBase::EMPTY_FILE:
                                $this->mainUploadForm( wfMsgHtml( 'emptyfile' ) );
                                break;
 
-                       case self::MIN_LENGTH_PARTNAME:
+                       case UploadBase::MIN_LENGTH_PARTNAME:
                                $this->mainUploadForm( wfMsgHtml( 'minlength1' ) );
                                break;
 
-                       case self::ILLEGAL_FILENAME:
-                               $filtered = $details['filtered'];
-                               $this->uploadError( wfMsgWikiHtml( 'illegalfilename', htmlspecialchars( $filtered ) ) );
+                       case UploadBase::ILLEGAL_FILENAME:
+                               $this->uploadError( wfMsgExt( 'illegalfilename',
+                                       'parseinline', $details['filtered'] ) );
                                break;
 
-                       case self::PROTECTED_PAGE:
+                       case UploadBase::PROTECTED_PAGE:
                                $wgOut->showPermissionsErrorPage( $details['permissionserrors'] );
                                break;
 
-                       case self::OVERWRITE_EXISTING_FILE:
-                               $errorText = $details['overwrite'];
-                               $this->uploadError( $wgOut->parse( $errorText ) );
+                       case UploadBase::OVERWRITE_EXISTING_FILE:
+                               $this->uploadError( wfMsgExt( $details['overwrite'],
+                                       'parseinline' ) );
                                break;
 
-                       case self::FILETYPE_MISSING:
+                       case UploadBase::FILETYPE_MISSING:
                                $this->uploadError( wfMsgExt( 'filetype-missing', array ( 'parseinline' ) ) );
                                break;
 
-                       case self::FILETYPE_BADTYPE:
+                       case UploadBase::FILETYPE_BADTYPE:
                                $finalExt = $details['finalExt'];
                                $this->uploadError(
                                        wfMsgExt( 'filetype-banned-type',
                                                array( 'parseinline' ),
                                                htmlspecialchars( $finalExt ),
-                                               $wgLang->commaList( $wgFileExtensions ),
-                                               $wgLang->formatNum( count($wgFileExtensions) )
+                                               implode(
+                                                       wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
+                                                       $wgFileExtensions
+                                               ),
+                                               $wgLang->formatNum( count( $wgFileExtensions ) )
                                        )
                                );
                                break;
 
-                       case self::VERIFICATION_ERROR:
-                               $veri = $details['veri'];
-                               $this->uploadError( $veri->toString() );
+                       case UploadBase::VERIFICATION_ERROR:
+                               unset( $details['status'] );
+                               $code = array_shift( $details );
+                               $this->uploadError( wfMsgExt( $code, 'parseinline', $details ) );
                                break;
 
-                       case self::UPLOAD_VERIFICATION_ERROR:
+                       case UploadBase::UPLOAD_VERIFICATION_ERROR:
                                $error = $details['error'];
-                               $this->uploadError( $error );
+                               $this->uploadError( wfMsgExt( $error, 'parseinline' ) );
                                break;
 
-                       case self::UPLOAD_WARNING:
-                               $warning = $details['warning'];
-                               $this->uploadWarning( $warning );
+                       case UploadBase::UPLOAD_WARNING:
+                               unset( $details['status'] );
+                               $this->uploadWarning( $details );
                                break;
 
-                       case self::INTERNAL_ERROR:
-                               $internal = $details['internal'];
-                               $this->showError( $internal );
+                       case UploadBase::INTERNAL_ERROR:
+                               $status = $details['internal'];
+                               $this->showError( $wgOut->parse( $status->getWikiText() ) );
                                break;
 
                        default:
-                               throw new MWException( __METHOD__ . ": Unknown value `{$value}`" );
+                               throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
                }
        }
 
@@ -379,219 +250,63 @@ class UploadForm {
         *
         * @access private
         */
-       function internalProcessUpload( &$resultDetails ) {
+       function internalProcessUpload() {
                global $wgUser;
 
                if( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) )
                {
                        wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
-                       return self::BEFORE_PROCESSING;
+                       return array( 'status' => UploadBase::BEFORE_PROCESSING );
                }
 
-               /**
-                * If there was no filename or a zero size given, give up quick.
-                */
-               if( trim( $this->mSrcName ) == '' || empty( $this->mFileSize ) ) {
-                       return self::EMPTY_FILE;
-               }
-
-               /* Check for curl error */
-               if( $this->mCurlError ) {
-                       return self::BEFORE_PROCESSING;
-               }
-
-               /**
-                * Chop off any directories in the given filename. Then
-                * filter out illegal characters, and try to make a legible name
-                * out of it. We'll strip some silently that Title would die on.
-                */
-               if( $this->mDesiredDestName != '' ) {
-                       $basename = $this->mDesiredDestName;
-               } else {
-                       $basename = $this->mSrcName;
-               }
-               $filtered = wfStripIllegalFilenameChars( $basename );
-               
-               /* Normalize to title form before we do any further processing */
-               $nt = Title::makeTitleSafe( NS_FILE, $filtered );
-               if( is_null( $nt ) ) {
-                       $resultDetails = array( 'filtered' => $filtered );
-                       return self::ILLEGAL_FILENAME;
-               }
-               $filtered = $nt->getDBkey();
-               
-               /**
-                * We'll want to blacklist against *any* 'extension', and use
-                * only the final one for the whitelist.
-                */
-               list( $partname, $ext ) = $this->splitExtensions( $filtered );
-
-               if( count( $ext ) ) {
-                       $finalExt = $ext[count( $ext ) - 1];
-               } else {
-                       $finalExt = '';
-               }
-
-               # If there was more than one "extension", reassemble the base
-               # filename to prevent bogus complaints about length
-               if( count( $ext ) > 1 ) {
-                       for( $i = 0; $i < count( $ext ) - 1; $i++ )
-                               $partname .= '.' . $ext[$i];
-               }
-
-               if( strlen( $partname ) < 1 ) {
-                       return self::MIN_LENGTH_PARTNAME;
-               }
-
-               $this->mLocalFile = wfLocalFile( $nt );
-               $this->mDestName = $this->mLocalFile->getName();
-
                /**
                 * If the image is protected, non-sysop users won't be able
                 * to modify it by uploading a new revision.
                 */
-               $permErrors = $nt->getUserPermissionsErrors( 'edit', $wgUser );
-               $permErrorsUpload = $nt->getUserPermissionsErrors( 'upload', $wgUser );
-               $permErrorsCreate = ( $nt->exists() ? array() : $nt->getUserPermissionsErrors( 'create', $wgUser ) );
-
-               if( $permErrors || $permErrorsUpload || $permErrorsCreate ) {
-                       // merge all the problems into one list, avoiding duplicates
-                       $permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsUpload, $permErrors ) );
-                       $permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsCreate, $permErrors ) );
-                       $resultDetails = array( 'permissionserrors' => $permErrors );
-                       return self::PROTECTED_PAGE;
-               }
-
-               /**
-                * In some cases we may forbid overwriting of existing files.
-                */
-               $overwrite = $this->checkOverwrite( $this->mDestName );
-               if( $overwrite !== true ) {
-                       $resultDetails = array( 'overwrite' => $overwrite );
-                       return self::OVERWRITE_EXISTING_FILE;
+               $permErrors = $this->mUpload->verifyPermissions( $wgUser );
+               if( $permErrors !== true ) {
+                       return array( 'status' => UploadBase::PROTECTED_PAGE, 'permissionserrors' => $permErrors );
                }
 
-               /* Don't allow users to override the blacklist (check file extension) */
-               global $wgCheckFileExtensions, $wgStrictFileExtensions;
-               global $wgFileExtensions, $wgFileBlacklist;
-               if ($finalExt == '') {
-                       return self::FILETYPE_MISSING;
-               } elseif ( $this->checkFileExtensionList( $ext, $wgFileBlacklist ) ||
-                               ($wgCheckFileExtensions && $wgStrictFileExtensions &&
-                                       !$this->checkFileExtension( $finalExt, $wgFileExtensions ) ) ) {
-                       $resultDetails = array( 'finalExt' => $finalExt );
-                       return self::FILETYPE_BADTYPE;
+               // Fetch the file if required
+               $status = $this->mUpload->fetchFile();
+               if( !$status->isOK() ){
+                       return array( 'status' =>UploadBase::BEFORE_PROCESSING, 'error'=>$status->getWikiText() );
                }
 
-               /**
-                * Look at the contents of the file; if we can recognize the
-                * type but it's corrupt or data of the wrong type, we should
-                * probably not accept it.
-                */
-               if( !$this->mStashed ) {
-                       $this->mFileProps = File::getPropsFromPath( $this->mTempPath, $finalExt );
-                       $this->checkMacBinary();
-                       $veri = $this->verify( $this->mTempPath, $finalExt );
-
-                       if( $veri !== true ) { //it's a wiki error...
-                               $resultDetails = array( 'veri' => $veri );
-                               return self::VERIFICATION_ERROR;
-                       }
-
-                       /**
-                        * Provide an opportunity for extensions to add further checks
-                        */
-                       $error = '';
-                       if( !wfRunHooks( 'UploadVerification',
-                                       array( $this->mDestName, $this->mTempPath, &$error ) ) ) {
-                               $resultDetails = array( 'error' => $error );
-                               return self::UPLOAD_VERIFICATION_ERROR;
-                       }
-               }
-
-
-               /**
-                * Check for non-fatal conditions
-                */
-               if ( ! $this->mIgnoreWarning ) {
-                       $warning = '';
-
-                       $comparableName = str_replace( ' ', '_', $basename );
-                       global $wgCapitalLinks, $wgContLang;
-                       if ( $wgCapitalLinks ) {
-                               $comparableName = $wgContLang->ucfirst( $comparableName );
-                       }
+               // Check whether this is a sane upload
+               $result = $this->mUpload->verifyUpload();
+               if( $result != UploadBase::OK )
+                       return $result;
 
-                       if( $comparableName !== $filtered ) {
-                               $warning .=  '<li>'.wfMsgHtml( 'badfilename', htmlspecialchars( $this->mDestName ) ).'</li>';
-                       }
+               $this->mLocalFile = $this->mUpload->getLocalFile();
 
-                       global $wgCheckFileExtensions;
-                       if ( $wgCheckFileExtensions ) {
-                               if ( !$this->checkFileExtension( $finalExt, $wgFileExtensions ) ) {
-                                       global $wgLang;
-                                       $warning .= '<li>' .
-                                       wfMsgExt( 'filetype-unwanted-type',
-                                               array( 'parseinline' ),
-                                               htmlspecialchars( $finalExt ),
-                                               $wgLang->commaList( $wgFileExtensions ),
-                                               $wgLang->formatNum( count($wgFileExtensions) )
-                                       ) . '</li>';
-                               }
-                       }
+               if( !$this->mIgnoreWarning ) {
+                       $warnings = $this->mUpload->checkWarnings();
 
-                       global $wgUploadSizeWarning;
-                       if ( $wgUploadSizeWarning && ( $this->mFileSize > $wgUploadSizeWarning ) ) {
-                               $skin = $wgUser->getSkin();
-                               $wsize = $skin->formatSize( $wgUploadSizeWarning );
-                               $asize = $skin->formatSize( $this->mFileSize );
-                               $warning .= '<li>' . htmlspecialchars( wfMsg( 'large-file', $wsize, $asize ) ) . '</li>';
-                       }
-                       if ( $this->mFileSize == 0 ) {
-                               $warning .= '<li>'.wfMsgHtml( 'emptyfile' ).'</li>';
-                       }
-
-                       if ( !$this->mDestWarningAck ) {
-                               $warning .= self::getExistsWarning( $this->mLocalFile );
-                       }
-                       
-                       $warning .= $this->getDupeWarning( $this->mTempPath, $finalExt, $nt );
-                       
-                       if( $warning != '' ) {
-                               /**
-                                * Stash the file in a temporary location; the user can choose
-                                * to let it through and we'll complete the upload then.
-                                */
-                               $resultDetails = array( 'warning' => $warning );
-                               return self::UPLOAD_WARNING;
+                       if( count( $warnings ) ) {
+                               $warnings['status'] = UploadBase::UPLOAD_WARNING;
+                               return $warnings;
                        }
                }
 
+
                /**
                 * Try actually saving the thing...
-                * It will show an error form on failure.
+                * It will show an error form on failure. No it will not.
                 */
                if( !$this->mForReUpload ) {
                        $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
                                $this->mCopyrightStatus, $this->mCopyrightSource );
-               } else {
-                       $pageText = false;
                }
+               $status = $this->mUpload->performUpload( $this->mComment, $pageText, $this->mWatchthis, $wgUser );
 
-               $status = $this->mLocalFile->upload( $this->mTempPath, $this->mComment, $pageText,
-                       File::DELETE_SOURCE, $this->mFileProps );
                if ( !$status->isGood() ) {
-                       $resultDetails = array( 'internal' => $status->getWikiText() );
-                       return self::INTERNAL_ERROR;
+                       return array( 'status' => UploadBase::INTERNAL_ERROR, 'internal' => $status );
                } else {
-                       if ( $this->mWatchthis ) {
-                               global $wgUser;
-                               $wgUser->addWatch( $this->mLocalFile->getTitle() );
-                       }
                        // Success, redirect to description page
-                       $img = null; // @todo: added to avoid passing a ref to null - should this be defined somewhere?
-                       wfRunHooks( 'UploadComplete', array( &$this ) );
-                       return self::SUCCESS;
+                       wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
+                       return UploadBase::SUCCESS;
                }
        }
 
@@ -601,40 +316,23 @@ class UploadForm {
         * Returns an HTML fragment consisting of one or more LI elements if there is a warning
         * Returns an empty string if there is no warning
         */
-       static function getExistsWarning( $file ) {
+       static function getExistsWarning( $exists ) {
                global $wgUser, $wgContLang;
-               // Check for uppercase extension. We allow these filenames but check if an image
-               // with lowercase extension exists already
+
+               if( $exists === false )
+                       return '';
+
                $warning = '';
                $align = $wgContLang->isRtl() ? 'left' : 'right';
 
-               if( strpos( $file->getName(), '.' ) == false ) {
-                       $partname = $file->getName();
-                       $rawExtension = '';
-               } else {
-                       $n = strrpos( $file->getName(), '.' );
-                       $rawExtension = substr( $file->getName(), $n + 1 );
-                       $partname = substr( $file->getName(), 0, $n );
-               }
+               list( $existsType, $file ) = $exists;
 
                $sk = $wgUser->getSkin();
 
-               if ( $rawExtension != $file->getExtension() ) {
-                       // We're not using the normalized form of the extension.
-                       // Normal form is lowercase, using most common of alternate
-                       // extensions (eg 'jpg' rather than 'JPEG').
-                       //
-                       // Check for another file using the normalized form...
-                       $nt_lc = Title::makeTitle( NS_FILE, $partname . '.' . $file->getExtension() );
-                       $file_lc = wfLocalFile( $nt_lc );
-               } else {
-                       $file_lc = false;
-               }
-
-               if( $file->exists() ) {
-                       $dlink = $sk->linkKnown( $file->getTitle() );
+               if( $existsType == 'exists' ) {
+                       // Exact match
+                       $dlink = $sk->makeKnownLinkObj( $file->getTitle() );
                        if ( $file->allowInlineDisplay() ) {
-                               // FIXME: replace deprecated makeImageLinkObj by link()
                                $dlink2 = $sk->makeImageLinkObj( $file->getTitle(), wfMsgExt( 'fileexists-thumb', 'parseinline' ),
                                        $file->getName(), $align, array(), false, true );
                        } elseif ( !$file->allowInlineDisplay() && $file->isSafeFile() ) {
@@ -647,15 +345,10 @@ class UploadForm {
 
                        $warning .= '<li>' . wfMsgExt( 'fileexists', array('parseinline','replaceafter'), $dlink ) . '</li>' . $dlink2;
 
-               } elseif( $file->getTitle()->getArticleID() ) {
-                       $lnk = $sk->linkKnown(
-                               $file->getTitle(),
-                               null,
-                               array(),
-                               array( 'redirect' => 'no' )
-                       );
+               } elseif( $existsType == 'page-exists' ) {
+                       $lnk = $sk->makeKnownLinkObj( $file->getTitle(), '', 'redirect=no' );
                        $warning .= '<li>' . wfMsgExt( 'filepageexists', array( 'parseinline', 'replaceafter' ), $lnk ) . '</li>';
-               } elseif ( $file_lc && $file_lc->exists() ) {
+               } elseif ( $existsType == 'exists-normalized' ) {
                        # Check if image with lowercase extension exists.
                        # It's not forbidden but in 99% it makes no sense to upload the same filename with uppercase extension
                        $dlink = $sk->linkKnown( $nt_lc );
@@ -708,7 +401,7 @@ class UploadForm {
                        }
                }
 
-               $filenamePrefixBlacklist = self::getFilenamePrefixBlacklist();
+               $filenamePrefixBlacklist = UploadBase::getFilenamePrefixBlacklist();
                # Do the match
                foreach( $filenamePrefixBlacklist as $prefix ) {
                        if ( substr( $partname, 0, strlen( $prefix ) ) == $prefix ) {
@@ -750,7 +443,9 @@ class UploadForm {
                }
                $s = '&nbsp;';
                if ( $file ) {
-                       $warning = self::getExistsWarning( $file );
+                       $exists = UploadBase::getExistsWarning( $file );
+                       $warning = self::getExistsWarning( $exists );
+                       // FIXME: We probably also want the prefix blacklist and the wasdeleted check here
                        if ( $warning !== '' ) {
                                $s = "<ul>$warning</ul>";
                        }
@@ -776,119 +471,29 @@ class UploadForm {
 
                return $output->getText();
        }
-       
+
        /**
-        * Check for duplicate files and throw up a warning before the upload
-        * completes.
+        * Construct the human readable warning message from an array of duplicate files
         */
-       function getDupeWarning( $tempfile, $extension, $destinationTitle ) {
-               $hash = File::sha1Base36( $tempfile );
-               $dupes = RepoGroup::singleton()->findBySha1( $hash );
-               $archivedImage = new ArchivedFile( null, 0, $hash.".$extension" );
+       public static function getDupeWarning( $dupes ) {
                if( $dupes ) {
                        global $wgOut;
                        $msg = "<gallery>";
                        foreach( $dupes as $file ) {
                                $title = $file->getTitle();
-                               # Don't throw the warning when the titles are the same, it's a reupload
-                               # and highly redundant.
-                               if ( !$title->equals( $destinationTitle ) || !$this->mForReUpload ) {
-                                       $msg .= $title->getPrefixedText() .
-                                               "|" . $title->getText() . "\n";
-                               }
+                               $msg .= $title->getPrefixedText() .
+                                       "|" . $title->getText() . "\n";
                        }
                        $msg .= "</gallery>";
                        return "<li>" .
                                wfMsgExt( "file-exists-duplicate", array( "parse" ), count( $dupes ) ) .
                                $wgOut->parse( $msg ) .
                                "</li>\n";
-               } elseif ( $archivedImage->getID() > 0 ) {
-                       global $wgOut;
-                       $name = Title::makeTitle( NS_FILE, $archivedImage->getName() )->getPrefixedText();
-                       return Xml::tags( 'li', null, wfMsgExt( 'file-deleted-duplicate', array( 'parseinline' ), array( $name ) ) );
                } else {
                        return '';
                }
        }
 
-       /**
-        * Get a list of blacklisted filename prefixes from [[MediaWiki:filename-prefix-blacklist]]
-        *
-        * @return array list of prefixes
-        */
-       public static function getFilenamePrefixBlacklist() {
-               $blacklist = array();
-               $message = wfMsgForContent( 'filename-prefix-blacklist' );
-               if( $message && !( wfEmptyMsg( 'filename-prefix-blacklist', $message ) || $message == '-' ) ) {
-                       $lines = explode( "\n", $message );
-                       foreach( $lines as $line ) {
-                               // Remove comment lines
-                               $comment = substr( trim( $line ), 0, 1 );
-                               if ( $comment == '#' || $comment == '' ) {
-                                       continue;
-                               }
-                               // Remove additional comments after a prefix
-                               $comment = strpos( $line, '#' );
-                               if ( $comment > 0 ) {
-                                       $line = substr( $line, 0, $comment-1 );
-                               }
-                               $blacklist[] = trim( $line );
-                       }
-               }
-               return $blacklist;
-       }
-
-       /**
-        * Stash a file in a temporary directory for later processing
-        * after the user has confirmed it.
-        *
-        * If the user doesn't explicitly cancel or accept, these files
-        * can accumulate in the temp directory.
-        *
-        * @param string $saveName - the destination filename
-        * @param string $tempName - the source temporary file to save
-        * @return string - full path the stashed file, or false on failure
-        * @access private
-        */
-       function saveTempUploadedFile( $saveName, $tempName ) {
-               global $wgOut;
-               $repo = RepoGroup::singleton()->getLocalRepo();
-               $status = $repo->storeTemp( $saveName, $tempName );
-               if ( !$status->isGood() ) {
-                       $this->showError( $status->getWikiText() );
-                       return false;
-               } else {
-                       return $status->value;
-               }
-       }
-
-       /**
-        * Stash a file in a temporary directory for later processing,
-        * and save the necessary descriptive info into the session.
-        * Returns a key value which will be passed through a form
-        * to pick up the path info on a later invocation.
-        *
-        * @return int
-        * @access private
-        */
-       function stashSession() {
-               $stash = $this->saveTempUploadedFile( $this->mDestName, $this->mTempPath );
-
-               if( !$stash ) {
-                       # Couldn't save the file.
-                       return false;
-               }
-
-               $key = mt_rand( 0, 0x7fffffff );
-               $_SESSION['wsUploadData'][$key] = array(
-                       'mTempPath'       => $stash,
-                       'mFileSize'       => $this->mFileSize,
-                       'mSrcName'        => $this->mSrcName,
-                       'mFileProps'      => $this->mFileProps,
-                       'version'         => self::SESSION_VERSION,
-               );
-               return $key;
-       }
 
        /**
         * Remove a temporarily kept file stashed by saveTempUploadedFile().
@@ -897,18 +502,18 @@ class UploadForm {
         */
        function unsaveUploadedFile() {
                global $wgOut;
-               if( !$this->mTempPath ) return true; // nothing to delete
-               $repo = RepoGroup::singleton()->getLocalRepo();
-               $success = $repo->freeTemp( $this->mTempPath );
+               $success = $this->mUpload->unsaveUploadedFile();
                if ( ! $success ) {
-                       $wgOut->showFileDeleteError( $this->mTempPath );
+                       $wgOut->showFileDeleteError( $this->mUpload->getTempPath() );
                        return false;
                } else {
                        return true;
                }
        }
 
-       /* -------------------------------------------------------------- */
+       /*              Interface code starts below this line             *
+        * -------------------------------------------------------------- */
+
 
        /**
         * @param string $error as HTML
@@ -928,18 +533,51 @@ class UploadForm {
         * @param string $warning as HTML
         * @access private
         */
-       function uploadWarning( $warning ) {
-               global $wgOut;
+       function uploadWarning( $warnings ) {
+               global $wgOut, $wgUser;
                global $wgUseCopyrightUpload;
 
-               $this->mSessionKey = $this->stashSession();
-               if( !$this->mSessionKey ) {
+               $this->mSessionKey = $this->mUpload->stashSession();
+
+               if( $sessionData === false ) {
                        # Couldn't save file; an error has been displayed so let's go.
                        return;
                }
 
+               $sk = $wgUser->getSkin();
+
                $wgOut->addHTML( '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" );
-               $wgOut->addHTML( '<ul class="warning">' . $warning . "</ul>\n" );
+               $wgOut->addHTML( '<ul class="warning">' );
+               foreach( $warnings as $warning => $args ) {
+                               $msg = null;
+                               if( $warning == 'exists' ) {
+
+                                       //we should not have produced this warning if the user already acknowledged the destination warning
+                                       //at any rate I don't see why we should hid this warning if mDestWarningAck has been checked
+                                       //(it produces an empty warning page when no other warnings are fired)
+                                       //if ( !$this->mDestWarningAck )
+                                               $msg = self::getExistsWarning( $args );
+
+                               } elseif( $warning == 'duplicate' ) {
+                                       $msg = $this->getDupeWarning( $args );
+                               } elseif( $warning == 'duplicate-archive' ) {
+                                       $titleText = Title::makeTitle( NS_FILE, $args )->getPrefixedText();
+                                       $msg = Xml::tags( 'li', null, wfMsgExt( 'file-deleted-duplicate', array( 'parseinline' ), array( $titleText ) ) );
+                               } elseif( $warning == 'filewasdeleted' ) {
+                                       $ltitle = SpecialPage::getTitleFor( 'Log' );
+                                       $llink = $sk->makeKnownLinkObj( $ltitle, wfMsgHtml( 'deletionlog' ),
+                                               'type=delete&page=' . $args->getPrefixedUrl() );
+                                       $msg = "\t<li>" . wfMsgWikiHtml( 'filewasdeleted', $llink ) . "</li>\n";
+                               } else {
+                                       if( is_bool( $args ) )
+                                               $args = array();
+                                       elseif( !is_array( $args ) )
+                                               $args = array( $args );
+                                       $msg = "\t<li>" . wfMsgExt( $warning, 'parseinline', $args ) . "</li>\n";
+                               }
+                               if( $msg )
+                                       $wgOut->addHTML( $msg );
+               }
 
                $titleObj = SpecialPage::getTitleFor( 'Upload' );
 
@@ -949,11 +587,16 @@ class UploadForm {
                } else {
                        $copyright = '';
                }
+        //add the wpEditToken
+               $token = htmlspecialchars( $wgUser->editToken() );
+               $tokenInput = "\n<input type='hidden' value=\"$token\" name=\"wpEditToken\" />\n";
 
                $wgOut->addHTML(
                        Xml::openElement( 'form', array( 'method' => 'post', 'action' => $titleObj->getLocalURL( 'action=submit' ),
                                 'enctype' => 'multipart/form-data', 'id' => 'uploadwarning' ) ) . "\n" .
+                       $tokenInput .
                        Xml::hidden( 'wpIgnoreWarning', '1' ) . "\n" .
+                       Xml::hidden( 'wpSourceType', 'stash' ) . "\n" .
                        Xml::hidden( 'wpSessionKey', $this->mSessionKey ) . "\n" .
                        Xml::hidden( 'wpUploadDescription', $this->mComment ) . "\n" .
                        Xml::hidden( 'wpLicense', $this->mLicense ) . "\n" .
@@ -974,40 +617,51 @@ class UploadForm {
         * @access private
         */
        function mainUploadForm( $msg='' ) {
-               global $wgOut, $wgUser, $wgLang, $wgMaxUploadSize;
+               global $wgOut, $wgUser, $wgLang, $wgMaxUploadSize, $wgEnableFirefogg;
                global $wgUseCopyrightUpload, $wgUseAjax, $wgAjaxUploadDestCheck, $wgAjaxLicensePreview;
-               global $wgRequest, $wgAllowCopyUploads;
+               global $wgRequest;
                global $wgStylePath, $wgStyleVersion;
+               global $wgEnableJS2system;
 
                $useAjaxDestCheck = $wgUseAjax && $wgAjaxUploadDestCheck;
                $useAjaxLicensePreview = $wgUseAjax && $wgAjaxLicensePreview;
 
                $adc = wfBoolToStr( $useAjaxDestCheck );
                $alp = wfBoolToStr( $useAjaxLicensePreview );
+               $uef = wfBoolToStr( $wgEnableFirefogg );
                $autofill = wfBoolToStr( $this->mDesiredDestName == '' );
 
+
                $wgOut->addScript( "<script type=\"text/javascript\">
 wgAjaxUploadDestCheck = {$adc};
 wgAjaxLicensePreview = {$alp};
+wgEnableFirefogg = {$uef};
 wgUploadAutoFill = {$autofill};
 </script>" );
-               $wgOut->addScriptFile( 'upload.js' );
-               $wgOut->addScriptFile( 'edit.js' ); // For <charinsert> support
+
+               if( $wgEnableJS2system ){
+                       //js2version of upload page:
+                   $wgOut->addScriptClass( 'uploadPage' );
+               }else{
+                       //legacy upload code:
+                       $wgOut->addScriptFile( 'upload.js' );
+                       $wgOut->addScriptFile( 'edit.js' ); // For <charinsert> support
+               }
 
                if( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) )
                {
-                       wfDebug( "Hook 'UploadForm:initial' broke output of the upload form\n" );
+                       wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" );
                        return false;
                }
 
-               if( $this->mDesiredDestName != '' ) {
+               if( $this->mDesiredDestName ) {
                        $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
                        // Show a subtitle link to deleted revisions (to sysops et al only)
                        if( $title instanceof Title && ( $count = $title->isDeleted() ) > 0 && $wgUser->isAllowed( 'deletedhistory' ) ) {
                                $link = wfMsgExt(
                                        $wgUser->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted',
                                        array( 'parse', 'replaceafter' ),
-                                       $wgUser->getSkin()->linkKnown(
+                                       $wgUser->getSkin()->makeKnownLinkObj(
                                                SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
                                                wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
                                        )
@@ -1034,6 +688,7 @@ wgUploadAutoFill = {$autofill};
                        $wgOut->addHTML( "<h2>{$sub}</h2>\n" .
                          "<span class='error'>{$msg}</span>\n" );
                }
+
                $wgOut->addHTML( '<div id="uploadtext">' );
                $wgOut->addWikiMsg( 'uploadtext', $this->mDesiredDestName );
                $wgOut->addHTML( "</div>\n" );
@@ -1045,20 +700,21 @@ wgUploadAutoFill = {$autofill};
 
                $allowedExtensions = '';
                if( $wgCheckFileExtensions ) {
+                       $delim = wfMsgExt( 'comma-separator', array( 'escapenoentities' ) );
                        if( $wgStrictFileExtensions ) {
                                # Everything not permitted is banned
                                $extensionsList =
                                        '<div id="mw-upload-permitted">' .
-                                       wfMsgWikiHtml( 'upload-permitted', $wgLang->commaList( $wgFileExtensions ) ) .
+                                       wfMsgWikiHtml( 'upload-permitted', implode( $wgFileExtensions, $delim ) ) .
                                        "</div>\n";
                        } else {
                                # We have to list both preferred and prohibited
                                $extensionsList =
                                        '<div id="mw-upload-preferred">' .
-                                       wfMsgWikiHtml( 'upload-preferred', $wgLang->commaList( $wgFileExtensions ) ) .
+                                       wfMsgWikiHtml( 'upload-preferred', implode( $wgFileExtensions, $delim ) ) .
                                        "</div>\n" .
                                        '<div id="mw-upload-prohibited">' .
-                                       wfMsgWikiHtml( 'upload-prohibited', $wgLang->commaList( $wgFileBlacklist ) ) .
+                                       wfMsgWikiHtml( 'upload-prohibited', implode( $wgFileBlacklist, $delim ) ) .
                                        "</div>\n";
                        }
                } else {
@@ -1067,34 +723,37 @@ wgUploadAutoFill = {$autofill};
                }
 
                # Get the maximum file size from php.ini as $wgMaxUploadSize works for uploads from URL via CURL only
-               # See http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes for possible values of upload_max_filesize and post_max_filesize
-               $max_sizes = array();
-               $max_sizes[] = trim( ini_get( 'upload_max_filesize' ) );
-               $max_sizes[] = trim( ini_get( 'post_max_size' ) );
-               foreach( $max_sizes as &$size) {
-                       $last = strtoupper( substr( $size, -1 ) );
-                       switch( $last ) {
-                               case 'G':
-                                       $size = substr( $size, 0, -1 ) * 1024 * 1024 * 1024;
-                                       break;
-                               case 'M':
-                                       $size = substr( $size, 0, -1 ) * 1024 * 1024;
-                                       break;
-                               case 'K':
-                                       $size = substr( $size, 0, -1 ) * 1024;
-                                       break;
-                       }
+               # See http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize for possible values of upload_max_filesize
+               $val = trim( ini_get( 'upload_max_filesize' ) );
+               $last = strtoupper( ( substr( $val, -1 ) ) );
+               switch( $last ) {
+                       case 'G':
+                               $val2 = substr( $val, 0, -1 ) * 1024 * 1024 * 1024;
+                               break;
+                       case 'M':
+                               $val2 = substr( $val, 0, -1 ) * 1024 * 1024;
+                               break;
+                       case 'K':
+                               $val2 = substr( $val, 0, -1 ) * 1024;
+                               break;
+                       default:
+                               $val2 = $val;
                }
-               $val = min( $max_sizes[0], $max_sizes[1] );
-               $val = $wgAllowCopyUploads ? min( $wgMaxUploadSize, $val ) : $val;
-               $maxUploadSize = '<div id="mw-upload-maxfilesize">' . 
-                       wfMsgExt( 'upload-maxfilesize', array( 'parseinline', 'escapenoentities' ), 
-                               $wgLang->formatSize( $val ) ) .
+               $maxUploadSize = '<div id="mw-upload-maxfilesize">' .
+                       wfMsgExt( 'upload-maxfilesize', array( 'parseinline', 'escapenoentities' ),
+                               $wgLang->formatSize( $val2 ) ) .
+                               "</div>\n";
+               //add a hidden filed for upload by url (uses the $wgMaxUploadSize var)
+               if( UploadFromUrl::isEnabled() ){
+                       $maxUploadSize.='<div id="mw-upload-maxfilesize-url" style="display:none">' .
+                       wfMsgExt( 'upload-maxfilesize', array( 'parseinline', 'escapenoentities' ),
+                               $wgLang->formatSize( $wgMaxUploadSize ) ) .
                                "</div>\n";
+               }
 
                $sourcefilename = wfMsgExt( 'sourcefilename', array( 'parseinline', 'escapenoentities' ) );
-        $destfilename = wfMsgExt( 'destfilename', array( 'parseinline', 'escapenoentities' ) ); 
-               
+        $destfilename = wfMsgExt( 'destfilename', array( 'parseinline', 'escapenoentities' ) );
+
                $msg = $this->mForReUpload ? 'filereuploadsummary' : 'fileuploadsummary';
                $summary = wfMsgExt( $msg, 'parseinline' );
 
@@ -1115,8 +774,19 @@ wgUploadAutoFill = {$autofill};
                $warningChecked = ($this->mIgnoreWarning || $this->mForReUpload) ? 'checked="checked"' : '';
 
                // Prepare form for upload or upload/copy
-               if( $wgAllowCopyUploads && $wgUser->isAllowed( 'upload_by_url' ) ) {
-                       $filename_form =
+               //javascript moved from inline calls to setup:
+               if( UploadFromUrl::isEnabled() && $wgUser->isAllowed( 'upload_by_url' ) ) {
+                   if($wgEnableJS2system){
+                       $filename_form =
+                               "<input type='radio' id=\"wpSourceTypeFile\" name='wpSourceType' value='file' checked='checked' />" .
+                                "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' size='60' />" .
+                               wfMsgHTML( 'upload_source_file' ) . "<br/>" .
+                               "<input type='radio' id='wpSourceTypeURL' name='wpSourceType' value='url' />" .
+                               "<input tabindex='1' type='text' name='wpUploadFileURL' id='wpUploadFileURL' size='60' />" .
+                               wfMsgHtml( 'upload_source_url' ) ;
+                   }else{
+                        //@@todo depreciate (only support  JS2system)
+                $filename_form =
                                "<input type='radio' id='wpSourceTypeFile' name='wpSourceType' value='file' " .
                                   "onchange='toggle_element_activation(\"wpUploadFileURL\",\"wpUploadFile\")' checked='checked' />" .
                                 "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' " .
@@ -1125,7 +795,7 @@ wgUploadAutoFill = {$autofill};
                                     "toggle_element_check(\"wpSourceTypeFile\",\"wpSourceTypeURL\")' " .
                                     "onchange='fillDestFilename(\"wpUploadFile\")' size='60' />" .
                                wfMsgHTML( 'upload_source_file' ) . "<br/>" .
-                               "<input type='radio' id='wpSourceTypeURL' name='wpSourceType' value='web' " .
+                               "<input type='radio' id='wpSourceTypeURL' name='wpSourceType' value='Url' " .
                                  "onchange='toggle_element_activation(\"wpUploadFile\",\"wpUploadFileURL\")' />" .
                                "<input tabindex='1' type='text' name='wpUploadFileURL' id='wpUploadFileURL' " .
                                  "onfocus='" .
@@ -1133,26 +803,34 @@ wgUploadAutoFill = {$autofill};
                                    "toggle_element_check(\"wpSourceTypeURL\",\"wpSourceTypeFile\")' " .
                                    "onchange='fillDestFilename(\"wpUploadFileURL\")' size='60' disabled='disabled' />" .
                                wfMsgHtml( 'upload_source_url' ) ;
+
+                   }
                } else {
                        $filename_form =
-                               "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' " .
-                               ($this->mDesiredDestName!=''?"":"onchange='fillDestFilename(\"wpUploadFile\")' ") .
-                               "size='60' />" .
-                               "<input type='hidden' name='wpSourceType' value='file' />" ;
+                               "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' size='60' />" .
+                               "<input type='hidden' name='wpSourceType' value='upload' />" ;
                }
+
                if ( $useAjaxDestCheck ) {
                        $warningRow = "<tr><td colspan='2' id='wpDestFile-warning'>&nbsp;</td></tr>";
-                       $destOnkeyup = 'onkeyup="wgUploadWarningObj.keypress();"';
+                       $destOnkeyup = '';
                } else {
                        $warningRow = '';
                        $destOnkeyup = '';
                }
+               # Uploading a new version? If so, the name is fixed.
+               $on = $this->mForReUpload ? "readonly='readonly'" : "";
+
                $encComment = htmlspecialchars( $this->mComment );
-               
+
+           //add the wpEditToken
+               $token = htmlspecialchars( $wgUser->editToken() );
+               $tokenInput = "\n<input type='hidden' value=\"$token\" name=\"wpEditToken\" />\n";
 
                $wgOut->addHTML(
-                        Xml::openElement( 'form', array( 'method' => 'post', 'action' => $titleObj->getLocalURL(),
+                        Xml::openElement( 'form', array( 'method' => 'post', 'action' => $titleObj->getLocalURL( 'action=submit' ),
                                 'enctype' => 'multipart/form-data', 'id' => 'mw-upload-form' ) ) .
+                        $tokenInput .
                         Xml::openElement( 'fieldset' ) .
                         Xml::element( 'legend', null, wfMsg( 'upload' ) ) .
                         Xml::openElement( 'table', array( 'border' => '0', 'id' => 'mw-upload-table' ) ) .
@@ -1189,10 +867,10 @@ wgUploadAutoFill = {$autofill};
                else {
                        $wgOut->addHTML(
                                "<input tabindex='2' type='text' name='wpDestFile' id='wpDestFile' size='60'
-                                               value=\"{$encDestName}\" onchange='toggleFilenameFiller()' $destOnkeyup />"
+                                               value=\"{$encDestName}\" $destOnkeyup />"
                        );
                }
-               
+
 
                $wgOut->addHTML(
                                "</td>
@@ -1209,6 +887,7 @@ wgUploadAutoFill = {$autofill};
                        </tr>
                        <tr>"
                );
+
                # Re-uploads should not need license info
                if ( !$this->mForReUpload && $licenseshtml != '' ) {
                        global $wgStylePath;
@@ -1303,7 +982,7 @@ wgUploadAutoFill = {$autofill};
        }
 
        /* -------------------------------------------------------------- */
-       
+
        /**
         * See if we should check the 'watch this page' checkbox on the form
         * based on the user's preferences and whether we're being asked
@@ -1321,7 +1000,7 @@ wgUploadAutoFill = {$autofill};
                        // Watch all edits!
                        return true;
                }
-               
+
                $local = wfLocalFile( $this->mDesiredDestName );
                if( $local && $local->exists() ) {
                        // We're uploading a new version of an existing file.
@@ -1333,467 +1012,17 @@ wgUploadAutoFill = {$autofill};
                }
        }
 
-       /**
-        * Split a file into a base name and all dot-delimited 'extensions'
-        * on the end. Some web server configurations will fall back to
-        * earlier pseudo-'extensions' to determine type and execute
-        * scripts, so the blacklist needs to check them all.
-        *
-        * @return array
-        */
-       public function splitExtensions( $filename ) {
-               $bits = explode( '.', $filename );
-               $basename = array_shift( $bits );
-               return array( $basename, $bits );
-       }
-
-       /**
-        * Perform case-insensitive match against a list of file extensions.
-        * Returns true if the extension is in the list.
-        *
-        * @param string $ext
-        * @param array $list
-        * @return bool
-        */
-       function checkFileExtension( $ext, $list ) {
-               return in_array( strtolower( $ext ), $list );
-       }
-
-       /**
-        * Perform case-insensitive match against a list of file extensions.
-        * Returns true if any of the extensions are in the list.
-        *
-        * @param array $ext
-        * @param array $list
-        * @return bool
-        */
-       public function checkFileExtensionList( $ext, $list ) {
-               foreach( $ext as $e ) {
-                       if( in_array( strtolower( $e ), $list ) ) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Verifies that it's ok to include the uploaded file
-        *
-        * @param string $tmpfile the full path of the temporary file to verify
-        * @param string $extension The filename extension that the file is to be served with
-        * @return mixed true of the file is verified, a WikiError object otherwise.
-        */
-       function verify( $tmpfile, $extension ) {
-               #magically determine mime type
-               $magic = MimeMagic::singleton();
-               $mime = $magic->guessMimeType($tmpfile,false);
-
-
-               #check mime type, if desired
-               global $wgVerifyMimeType;
-               if ($wgVerifyMimeType) {
-                       wfDebug ( "\n\nmime: <$mime> extension: <$extension>\n\n");
-                       #check mime type against file extension
-                       if( !self::verifyExtension( $mime, $extension ) ) {
-                               return new WikiErrorMsg( 'uploadcorrupt' );
-                       }
-
-                       #check mime type blacklist
-                       global $wgMimeTypeBlacklist;
-                       if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist) ) {
-                               if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
-                                       return new WikiErrorMsg( 'filetype-badmime', htmlspecialchars( $mime ) );
-                               }
-
-                               # Check IE type
-                               $fp = fopen( $tmpfile, 'rb' );
-                               $chunk = fread( $fp, 256 );
-                               fclose( $fp );
-                               $extMime = $magic->guessTypesForExtension( $extension );
-                               $ieTypes = $magic->getIEMimeTypes( $tmpfile, $chunk, $extMime );
-                               foreach ( $ieTypes as $ieType ) {
-                                       if ( $this->checkFileExtension( $ieType, $wgMimeTypeBlacklist ) ) {
-                                               return new WikiErrorMsg( 'filetype-bad-ie-mime', $ieType );
-                                       }
-                               }
-                       }
-               }
-
-               #check for htmlish code and javascript
-               if( $this->detectScript ( $tmpfile, $mime, $extension ) ) {
-                       return new WikiErrorMsg( 'uploadscripted' );
-               }
-               if( $extension == 'svg' || $mime == 'image/svg+xml' ) {
-                       if( $this->detectScriptInSvg( $tmpfile ) ) {
-                               return new WikiErrorMsg( 'uploadscripted' );
-                       }
-               }
-
-               /**
-               * Scan the uploaded file for viruses
-               */
-               $virus= $this->detectVirus($tmpfile);
-               if ( $virus ) {
-                       return new WikiErrorMsg( 'uploadvirus', htmlspecialchars($virus) );
-               }
-
-               wfDebug( __METHOD__.": all clear; passing.\n" );
-               return true;
-       }
-
-       /**
-        * Checks if the mime type of the uploaded file matches the file extension.
-        *
-        * @param string $mime the mime type of the uploaded file
-        * @param string $extension The filename extension that the file is to be served with
-        * @return bool
-        */
-       static function verifyExtension( $mime, $extension ) {
-               $magic = MimeMagic::singleton();
-
-               if ( ! $mime || $mime == 'unknown' || $mime == 'unknown/unknown' )
-                       if ( ! $magic->isRecognizableExtension( $extension ) ) {
-                               wfDebug( __METHOD__.": passing file with unknown detected mime type; " .
-                                       "unrecognized extension '$extension', can't verify\n" );
-                               return true;
-                       } else {
-                               wfDebug( __METHOD__.": rejecting file with unknown detected mime type; ".
-                                       "recognized extension '$extension', so probably invalid file\n" );
-                               return false;
-                       }
-
-               $match= $magic->isMatchingExtension($extension,$mime);
-
-               if ($match===NULL) {
-                       wfDebug( __METHOD__.": no file extension known for mime type $mime, passing file\n" );
-                       return true;
-               } elseif ($match===true) {
-                       wfDebug( __METHOD__.": mime type $mime matches extension $extension, passing file\n" );
-
-                       #TODO: if it's a bitmap, make sure PHP or ImageMagic resp. can handle it!
-                       return true;
-
-               } else {
-                       wfDebug( __METHOD__.": mime type $mime mismatches file extension $extension, rejecting file\n" );
-                       return false;
-               }
-       }
-
-
-       /**
-        * Heuristic for detecting files that *could* contain JavaScript instructions or
-        * things that may look like HTML to a browser and are thus
-        * potentially harmful. The present implementation will produce false positives in some situations.
-        *
-        * @param string $file Pathname to the temporary upload file
-        * @param string $mime The mime type of the file
-        * @param string $extension The extension of the file
-        * @return bool true if the file contains something looking like embedded scripts
-        */
-       function detectScript($file, $mime, $extension) {
-               global $wgAllowTitlesInSVG;
-
-               #ugly hack: for text files, always look at the entire file.
-               #For binarie field, just check the first K.
-
-               if (strpos($mime,'text/')===0) $chunk = file_get_contents( $file );
-               else {
-                       $fp = fopen( $file, 'rb' );
-                       $chunk = fread( $fp, 1024 );
-                       fclose( $fp );
-               }
-
-               $chunk= strtolower( $chunk );
-
-               if (!$chunk) return false;
-
-               #decode from UTF-16 if needed (could be used for obfuscation).
-               if (substr($chunk,0,2)=="\xfe\xff") $enc= "UTF-16BE";
-               elseif (substr($chunk,0,2)=="\xff\xfe") $enc= "UTF-16LE";
-               else $enc= NULL;
-
-               if ($enc) $chunk= iconv($enc,"ASCII//IGNORE",$chunk);
-
-               $chunk= trim($chunk);
-
-               #FIXME: convert from UTF-16 if necessarry!
-
-               wfDebug("SpecialUpload::detectScript: checking for embedded scripts and HTML stuff\n");
-
-               #check for HTML doctype
-               if ( preg_match( "/<!DOCTYPE *X?HTML/i", $chunk ) ) return true;
-
-               /**
-               * Internet Explorer for Windows performs some really stupid file type
-               * autodetection which can cause it to interpret valid image files as HTML
-               * and potentially execute JavaScript, creating a cross-site scripting
-               * attack vectors.
-               *
-               * Apple's Safari browser also performs some unsafe file type autodetection
-               * which can cause legitimate files to be interpreted as HTML if the
-               * web server is not correctly configured to send the right content-type
-               * (or if you're really uploading plain text and octet streams!)
-               *
-               * Returns true if IE is likely to mistake the given file for HTML.
-               * Also returns true if Safari would mistake the given file for HTML
-               * when served with a generic content-type.
-               */
-
-               $tags = array(
-                       '<a href',
-                       '<body',
-                       '<head',
-                       '<html',   #also in safari
-                       '<img',
-                       '<pre',
-                       '<script', #also in safari
-                       '<table'
-                       );
-               if( ! $wgAllowTitlesInSVG && $extension !== 'svg' && $mime !== 'image/svg' ) {
-                       $tags[] = '<title';
-               }
-
-               foreach( $tags as $tag ) {
-                       if( false !== strpos( $chunk, $tag ) ) {
-                               return true;
-                       }
-               }
-
-               /*
-               * look for javascript
-               */
-
-               #resolve entity-refs to look at attributes. may be harsh on big files... cache result?
-               $chunk = Sanitizer::decodeCharReferences( $chunk );
-
-               #look for script-types
-               if (preg_match('!type\s*=\s*[\'"]?\s*(?:\w*/)?(?:ecma|java)!sim',$chunk)) return true;
-
-               #look for html-style script-urls
-               if (preg_match('!(?:href|src|data)\s*=\s*[\'"]?\s*(?:ecma|java)script:!sim',$chunk)) return true;
-
-               #look for css-style script-urls
-               if (preg_match('!url\s*\(\s*[\'"]?\s*(?:ecma|java)script:!sim',$chunk)) return true;
-
-               wfDebug("SpecialUpload::detectScript: no scripts found\n");
-               return false;
-       }
-
-       function detectScriptInSvg( $filename ) {
-               $check = new XmlTypeCheck( $filename, array( $this, 'checkSvgScriptCallback' ) );
-               return $check->filterMatch;
-       }
-       
-       /**
-        * @todo Replace this with a whitelist filter!
-        */
-       function checkSvgScriptCallback( $element, $attribs ) {
-               $stripped = $this->stripXmlNamespace( $element );
-               
-               if( $stripped == 'script' ) {
-                       wfDebug( __METHOD__ . ": Found script element '$element' in uploaded file.\n" );
-                       return true;
-               }
-               
-               foreach( $attribs as $attrib => $value ) {
-                       $stripped = $this->stripXmlNamespace( $attrib );
-                       if( substr( $stripped, 0, 2 ) == 'on' ) {
-                               wfDebug( __METHOD__ . ": Found script attribute '$attrib'='value' in uploaded file.\n" );
-                               return true;
-                       }
-                       if( $stripped == 'href' && strpos( strtolower( $value ), 'javascript:' ) !== false ) {
-                               wfDebug( __METHOD__ . ": Found script href attribute '$attrib'='$value' in uploaded file.\n" );
-                               return true;
-                       }
-               }
-       }
-       
-       private function stripXmlNamespace( $name ) {
-               // 'http://www.w3.org/2000/svg:script' -> 'script'
-               $parts = explode( ':', strtolower( $name ) );
-               return array_pop( $parts );
-       }
-       
-       /**
-        * Generic wrapper function for a virus scanner program.
-        * This relies on the $wgAntivirus and $wgAntivirusSetup variables.
-        * $wgAntivirusRequired may be used to deny upload if the scan fails.
-        *
-        * @param string $file Pathname to the temporary upload file
-        * @return mixed false if not virus is found, NULL if the scan fails or is disabled,
-        *         or a string containing feedback from the virus scanner if a virus was found.
-        *         If textual feedback is missing but a virus was found, this function returns true.
-        */
-       function detectVirus($file) {
-               global $wgAntivirus, $wgAntivirusSetup, $wgAntivirusRequired, $wgOut;
-
-               if ( !$wgAntivirus ) {
-                       wfDebug( __METHOD__.": virus scanner disabled\n");
-                       return NULL;
-               }
-
-               if ( !$wgAntivirusSetup[$wgAntivirus] ) {
-                       wfDebug( __METHOD__.": unknown virus scanner: $wgAntivirus\n" );
-                       $wgOut->wrapWikiMsg( '<div class="error">$1</div>', array( 'virus-badscanner', $wgAntivirus ) );
-                       return wfMsg('virus-unknownscanner') . " $wgAntivirus";
-               }
-
-               # look up scanner configuration
-               $command = $wgAntivirusSetup[$wgAntivirus]["command"];
-               $exitCodeMap = $wgAntivirusSetup[$wgAntivirus]["codemap"];
-               $msgPattern = isset( $wgAntivirusSetup[$wgAntivirus]["messagepattern"] ) ?
-                       $wgAntivirusSetup[$wgAntivirus]["messagepattern"] : null;
-
-               if ( strpos( $command,"%f" ) === false ) {
-                       # simple pattern: append file to scan
-                       $command .= " " . wfEscapeShellArg( $file );
-               } else {
-                       # complex pattern: replace "%f" with file to scan
-                       $command = str_replace( "%f", wfEscapeShellArg( $file ), $command );
-               }
-
-               wfDebug( __METHOD__.": running virus scan: $command \n" );
-
-               # execute virus scanner
-               $exitCode = false;
-
-               #NOTE: there's a 50 line workaround to make stderr redirection work on windows, too.
-               #      that does not seem to be worth the pain.
-               #      Ask me (Duesentrieb) about it if it's ever needed.
-               $output = array();
-               if ( wfIsWindows() ) {
-                       exec( "$command", $output, $exitCode );
-               } else {
-                       exec( "$command 2>&1", $output, $exitCode );
-               }
-
-               # map exit code to AV_xxx constants.
-               $mappedCode = $exitCode;
-               if ( $exitCodeMap ) {
-                       if ( isset( $exitCodeMap[$exitCode] ) ) {
-                               $mappedCode = $exitCodeMap[$exitCode];
-                       } elseif ( isset( $exitCodeMap["*"] ) ) {
-                               $mappedCode = $exitCodeMap["*"];
-                       }
-               }
-
-               if ( $mappedCode === AV_SCAN_FAILED ) {
-                       # scan failed (code was mapped to false by $exitCodeMap)
-                       wfDebug( __METHOD__.": failed to scan $file (code $exitCode).\n" );
-
-                       if ( $wgAntivirusRequired ) {
-                               return wfMsg('virus-scanfailed', array( $exitCode ) );
-                       } else {
-                               return NULL;
-                       }
-               } else if ( $mappedCode === AV_SCAN_ABORTED ) {
-                       # scan failed because filetype is unknown (probably imune)
-                       wfDebug( __METHOD__.": unsupported file type $file (code $exitCode).\n" );
-                       return NULL;
-               } else if ( $mappedCode === AV_NO_VIRUS ) {
-                       # no virus found
-                       wfDebug( __METHOD__.": file passed virus scan.\n" );
-                       return false;
-               } else {
-                       $output = join( "\n", $output );
-                       $output = trim( $output );
-
-                       if ( !$output ) {
-                               $output = true; #if there's no output, return true
-                       } elseif ( $msgPattern ) {
-                               $groups = array();
-                               if ( preg_match( $msgPattern, $output, $groups ) ) {
-                                       if ( $groups[1] ) {
-                                               $output = $groups[1];
-                                       }
-                               }
-                       }
-
-                       wfDebug( __METHOD__.": FOUND VIRUS! scanner feedback: $output \n" );
-                       return $output;
-               }
-       }
-
-       /**
-        * Check if the temporary file is MacBinary-encoded, as some uploads
-        * from Internet Explorer on Mac OS Classic and Mac OS X will be.
-        * If so, the data fork will be extracted to a second temporary file,
-        * which will then be checked for validity and either kept or discarded.
-        *
-        * @access private
-        */
-       function checkMacBinary() {
-               $macbin = new MacBinary( $this->mTempPath );
-               if( $macbin->isValid() ) {
-                       $dataFile = tempnam( wfTempDir(), "WikiMacBinary" );
-                       $dataHandle = fopen( $dataFile, 'wb' );
-
-                       wfDebug( "SpecialUpload::checkMacBinary: Extracting MacBinary data fork to $dataFile\n" );
-                       $macbin->extractData( $dataHandle );
-
-                       $this->mTempPath = $dataFile;
-                       $this->mFileSize = $macbin->dataForkLength();
-
-                       // We'll have to manually remove the new file if it's not kept.
-                       $this->mRemoveTempFile = true;
-               }
-               $macbin->close();
-       }
-
-       /**
-        * If we've modified the upload file we need to manually remove it
-        * on exit to clean up.
-        * @access private
-        */
-       function cleanupTempFile() {
-               if ( $this->mRemoveTempFile && $this->mTempPath && file_exists( $this->mTempPath ) ) {
-                       wfDebug( "SpecialUpload::cleanupTempFile: Removing temporary file {$this->mTempPath}\n" );
-                       unlink( $this->mTempPath );
-               }
-       }
-
-       /**
-        * Check if there's an overwrite conflict and, if so, if restrictions
-        * forbid this user from performing the upload.
-        *
-        * @return mixed true on success, WikiError on failure
-        * @access private
-        */
-       function checkOverwrite( $name ) {
-               $img = wfFindFile( $name );
-
-               $error = '';
-               if( $img ) {
-                       global $wgUser, $wgOut;
-                       if( $img->isLocal() ) {
-                               if( !self::userCanReUpload( $wgUser, $img->name ) ) {
-                                       $error = 'fileexists-forbidden';
-                               }
-                       } else {
-                               if( !$wgUser->isAllowed( 'reupload' ) ||
-                                   !$wgUser->isAllowed( 'reupload-shared' ) ) {
-                                       $error = "fileexists-shared-forbidden";
-                               }
-                       }
-               }
-
-               if( $error ) {
-                       $errorText = wfMsg( $error, wfEscapeWikiText( $img->getName() ) );
-                       return $errorText;
-               }
-
-               // Rockin', go ahead and upload
-               return true;
-       }
-
         /**
         * Check if a user is the last uploader
         *
         * @param User $user
         * @param string $img, image name
         * @return bool
+        * @deprecated Use UploadBase::userCanReUpload
         */
        public static function userCanReUpload( User $user, $img ) {
+               wfDeprecated( __METHOD__ );
+
                if( $user->isAllowed( 'reupload' ) )
                        return true; // non-conditional
                if( !$user->isAllowed( 'reupload-own' ) )
@@ -1825,19 +1054,19 @@ wgUploadAutoFill = {$autofill};
        /**
         * Get the initial image page text based on a comment and optional file status information
         */
-       static function getInitialPageText( $comment, $license, $copyStatus, $source ) {
+       static function getInitialPageText( $comment='', $license='', $copyStatus='', $source='' ) {
                global $wgUseCopyrightUpload;
                if ( $wgUseCopyrightUpload ) {
                        if ( $license != '' ) {
                                $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
                        }
-                       $pageText = '== ' . wfMsgForContent ( 'filedesc' ) . " ==\n" . $comment . "\n" .
+                       $pageText = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $comment . "\n" .
                          '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" .
                          "$licensetxt" .
                          '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ;
                } else {
                        if ( $license != '' ) {
-                               $filedesc = $comment == '' ? '' : '== ' . wfMsgForContent ( 'filedesc' ) . " ==\n" . $comment . "\n";
+                               $filedesc = $comment == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $comment . "\n";
                                 $pageText = $filedesc .
                                         '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
                        } else {
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
new file mode 100644 (file)
index 0000000..3059e28
--- /dev/null
@@ -0,0 +1,973 @@
+<?php
+
+class UploadBase {
+       var $mTempPath;
+       var $mDesiredDestName, $mDestName, $mRemoveTempFile, $mSourceType;
+       var $mTitle = false, $mTitleError = 0;
+       var $mFilteredName, $mFinalExtension;
+
+       const SUCCESS = 0;
+       const OK = 0;
+       const BEFORE_PROCESSING = 1;
+       const LARGE_FILE_SERVER = 2;
+       const EMPTY_FILE = 3;
+       const MIN_LENGTH_PARTNAME = 4;
+       const ILLEGAL_FILENAME = 5;
+       const PROTECTED_PAGE = 6;
+       const OVERWRITE_EXISTING_FILE = 7;
+       const FILETYPE_MISSING = 8;
+       const FILETYPE_BADTYPE = 9;
+       const VERIFICATION_ERROR = 10;
+       const UPLOAD_VERIFICATION_ERROR = 11;
+       const UPLOAD_WARNING = 12;
+       const INTERNAL_ERROR = 13;
+       const MIN_LENGHT_PARTNAME = 14;
+
+       const SESSION_VERSION = 2;
+
+       /**
+        * Returns true if uploads are enabled.
+        * Can be override by subclasses.
+        */
+       static function isEnabled() {
+               global $wgEnableUploads;
+               if ( !$wgEnableUploads )
+                       return false;
+
+               # Check php's file_uploads setting
+               if( !wfIniGetBool( 'file_uploads' ) ) {
+                       return false;
+               }
+               return true;
+       }
+       /**
+        * Returns true if the user can use this upload module or else a string
+        * identifying the missing permission.
+        * Can be overriden by subclasses.
+        */
+       static function isAllowed( $user ) {
+               if( !$user->isAllowed( 'upload' ) )
+                       return 'upload';
+               return true;
+       }
+
+       // Upload handlers. Should probably just be a global
+       static $uploadHandlers = array( 'Stash', 'File', 'Url' );
+       /**
+        * Create a form of UploadBase depending on wpSourceType and initializes it
+        */
+       static function createFromRequest( &$request, $type = null ) {
+               $type = $type ? $type : $request->getVal( 'wpSourceType' );
+
+               if( !$type )
+                       return null;
+
+               $type = ucfirst($type);
+               $className = 'UploadFrom'.$type;
+               print "class name: $className";
+               if( !in_array( $type, self::$uploadHandlers ) )
+                       return null;
+
+               if( !call_user_func( array( $className, 'isEnabled' ) ) )
+                       return null;
+
+
+               if( !call_user_func( array( $className, 'isValidRequest' ), $request ) )
+                       return null;
+
+               $handler = new $className;
+
+               $handler->initializeFromRequest( $request );
+               return $handler;
+       }
+       /**
+        * Check whether a request if valid for this handler
+        */
+       static function isValidRequest( $request ) {
+               return false;
+       }
+
+       function __construct() {}
+
+       /**
+        * Do the real variable initialization
+        */
+       function initialize( $name, $tempPath, $fileSize, $removeTempFile = false ) {
+               $this->mDesiredDestName = $name;
+               $this->mTempPath = $tempPath;
+               $this->mFileSize = $fileSize;
+               $this->mRemoveTempFile = $removeTempFile;
+       }
+
+       /**
+        * Fetch the file. Usually a no-op
+        */
+       function fetchFile() {
+               return Status::newGood();
+       }
+       //return the file size
+       function isEmptyFile(){
+               return empty( $this->mFileSize);
+       }
+       /**
+        * Verify whether the upload is sane.
+        * Returns self::OK or else an array with error information
+        */
+       function verifyUpload() {
+               /**
+                * If there was no filename or a zero size given, give up quick.
+                */
+
+               if( $this->isEmptyFile() )
+                       return array( 'status' => self::EMPTY_FILE );
+
+               $nt = $this->getTitle();
+               if( is_null( $nt ) ) {
+                       $result = array( 'status' => $this->mTitleError );
+                       if( $this->mTitleError == self::ILLEGAL_FILENAME )
+                               $result['filtered'] = $this->mFilteredName;
+                       if ( $this->mTitleError == self::FILETYPE_BADTYPE )
+                               $result['finalExt'] = $this->mFinalExtension;
+                       return $result;
+               }
+               $this->mLocalFile = wfLocalFile( $nt );
+               $this->mDestName = $this->mLocalFile->getName();
+
+               /**
+                * In some cases we may forbid overwriting of existing files.
+                */
+               $overwrite = $this->checkOverwrite();
+               if( $overwrite !== true )
+                       return array( 'status' => self::OVERWRITE_EXISTING_FILE, 'overwrite' => $overwrite );
+
+               /**
+                * Look at the contents of the file; if we can recognize the
+                * type but it's corrupt or data of the wrong type, we should
+                * probably not accept it.
+                */
+               $verification = $this->verifyFile( $this->mTempPath );
+
+               if( $verification !== true ) {
+                       if( !is_array( $verification ) )
+                               $verification = array( $verification );
+                       $verification['status'] = self::VERIFICATION_ERROR;
+                       return $verification;
+               }
+
+               $error = '';
+               if( !wfRunHooks( 'UploadVerification',
+                               array( $this->mDestName, $this->mTempPath, &$error ) ) ) {
+                       return array( 'status' => self::UPLOAD_VERIFICATION_ERROR, 'error' => $error );
+               }
+
+               return self::OK;
+       }
+
+       /**
+        * Verifies that it's ok to include the uploaded file
+        *
+        * this function seems to intermixes tmpfile and $this->mTempPath .. no idea why this is
+        *
+        * @param string $tmpfile the full path of the temporary file to verify
+        * @return mixed true of the file is verified, a string or array otherwise.
+        */
+       protected function verifyFile( $tmpfile ) {
+               $this->mFileProps = File::getPropsFromPath( $this->mTempPath, $this->mFinalExtension );
+               $this->checkMacBinary( );
+
+               #magically determine mime type
+               $magic = MimeMagic::singleton();
+               $mime = $magic->guessMimeType( $tmpfile, false );
+
+               #check mime type, if desired
+               global $wgVerifyMimeType;
+               if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist) ) {
+                       if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) )
+                               return array( 'filetype-badmime', $mime );
+
+                       # Check IE type
+                       $fp = fopen( $tmpfile, 'rb' );
+                       $chunk = fread( $fp, 256 );
+                       fclose( $fp );
+                       $extMime = $magic->guessTypesForExtension( $this->mFinalExtension );
+                       $ieTypes = $magic->getIEMimeTypes( $tmpfile, $chunk, $extMime );
+                       foreach ( $ieTypes as $ieType ) {
+                               if ( $this->checkFileExtension( $ieType, $wgMimeTypeBlacklist ) ) {
+                                       return array( 'filetype-bad-ie-mime', $ieType );
+                               }
+                       }
+               }
+
+
+               #check for htmlish code and javascript
+               if( $this->detectScript ( $tmpfile, $mime, $this->mFinalExtension ) ) {
+                       return 'uploadscripted';
+               }
+               if( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) {
+                       if( $this->detectScriptInSvg( $tmpfile ) ) {
+                               return 'uploadscripted';
+                       }
+               }
+
+               /**
+               * Scan the uploaded file for viruses
+               */
+               $virus = $this->detectVirus($tmpfile);
+               if ( $virus ) {
+                       return array( 'uploadvirus', $virus );
+               }
+               wfDebug( __METHOD__.": all clear; passing.\n" );
+               return true;
+       }
+
+       /**
+        * Check whether the user can edit, upload and create the image
+        */
+       function verifyPermissions( $user ) {
+               /**
+                * If the image is protected, non-sysop users won't be able
+                * to modify it by uploading a new revision.
+                */
+               $nt = $this->getTitle();
+               if( is_null( $nt ) )
+                       return true;
+               $permErrors = $nt->getUserPermissionsErrors( 'edit', $user );
+               $permErrorsUpload = $nt->getUserPermissionsErrors( 'upload', $user );
+               $permErrorsCreate = ( $nt->exists() ? array() : $nt->getUserPermissionsErrors( 'create', $user ) );
+               if( $permErrors || $permErrorsUpload || $permErrorsCreate ) {
+                       $permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsUpload, $permErrors ) );
+                       $permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsCreate, $permErrors ) );
+                       return $permErrors;
+               }
+               return true;
+       }
+
+       /**
+        * Check for non fatal problems with the file
+        */
+       function checkWarnings() {
+               $warning = array();
+
+               $filename = $this->mLocalFile->getName();
+               $n = strrpos( $filename, '.' );
+               $partname = $n ? substr( $filename, 0, $n ) : $filename;
+
+               /*
+                * Check whether the resulting filename is different from the desired one,
+                * but ignore things like ucfirst() and spaces/underscore things
+                **/
+               $comparableName = str_replace( ' ', '_', $this->mDesiredDestName );
+               global $wgCapitalLinks, $wgContLang;
+               if ( $wgCapitalLinks ) {
+                       $comparableName = $wgContLang->ucfirst( $comparableName );
+               }
+               if( $this->mDesiredDestName != $filename && $comparableName != $filename )
+                       $warning['badfilename'] = $filename;
+
+               // Check whether the file extension is on the unwanted list
+               global $wgCheckFileExtensions, $wgFileExtensions;
+               if ( $wgCheckFileExtensions ) {
+                       if ( !$this->checkFileExtension( $this->mFinalExtension, $wgFileExtensions ) )
+                               $warning['filetype-unwanted-type'] = $this->mFinalExtension;
+               }
+
+               global $wgUploadSizeWarning;
+               if ( $wgUploadSizeWarning && ( $this->mFileSize > $wgUploadSizeWarning ) )
+                       $warning['large-file'] = $wgUploadSizeWarning;
+
+               if ( $this->mFileSize == 0 )
+                       $warning['emptyfile'] = true;
+
+
+               $exists = self::getExistsWarning( $this->mLocalFile );
+               if( $exists !== false )
+                       $warning['exists'] = $exists;
+
+               // Check whether this may be a thumbnail
+               if( $exists !== false && $exists[0] != 'thumb'
+                               && self::isThumbName( $this->mLocalFile->getName() ) ){
+                       //make the title:
+                       $nt = $this->getTitle();
+                       $warning['file-thumbnail-no'] = substr( $filename , 0,
+                               strpos( $nt->getText() , '-' ) +1 );
+               }
+
+               // Check dupes against existing files
+               $hash = File::sha1Base36( $this->mTempPath );
+               $dupes = RepoGroup::singleton()->findBySha1( $hash );
+               $title = $this->getTitle();
+               // Remove all matches against self
+               foreach ( $dupes as $key => $dupe ) {
+                       if( $title->equals( $dupe->getTitle() ) )
+                               unset( $dupes[$key] );
+               }
+               if( $dupes )
+                       $warning['duplicate'] = $dupes;
+
+               // Check dupes against archives
+               $archivedImage = new ArchivedFile( null, 0, "{$hash}.{$this->mFinalExtension}" );
+               if ( $archivedImage->getID() > 0 )
+                       $warning['duplicate-archive'] = $archivedImage->getName();
+
+               $filenamePrefixBlacklist = self::getFilenamePrefixBlacklist();
+               foreach( $filenamePrefixBlacklist as $prefix ) {
+                       if ( substr( $partname, 0, strlen( $prefix ) ) == $prefix ) {
+                               $warning['filename-bad-prefix'] = $prefix;
+                               break;
+                       }
+               }
+
+               # If the file existed before and was deleted, warn the user of this
+               # Don't bother doing so if the file exists now, however
+               if( $this->mLocalFile->wasDeleted() && !$this->mLocalFile->exists() )
+                       $warning['filewasdeleted'] = $this->mLocalFile->getTitle();
+
+               return $warning;
+       }
+
+       /**
+        * Really perform the upload.
+        */
+       function performUpload( $comment, $pageText, $watch, $user ) {
+           wfDebug("\n\n\performUpload: sum:" . $comment . ' c: ' . $pageText . ' w:' .$watch);
+               $status = $this->mLocalFile->upload( $this->mTempPath, $comment, $pageText,
+                       File::DELETE_SOURCE, $this->mFileProps, false, $user );
+
+               if( $status->isGood() && $watch )
+                       $user->addWatch( $this->mLocalFile->getTitle() );
+
+               if( $status->isGood() )
+                       wfRunHooks( 'UploadComplete', array( &$this ) );
+
+               return $status;
+       }
+
+       /**
+        * Returns a title or null
+        */
+       function getTitle() {
+               if ( $this->mTitle !== false )
+                       return $this->mTitle;
+
+               /**
+                * Chop off any directories in the given filename. Then
+                * filter out illegal characters, and try to make a legible name
+                * out of it. We'll strip some silently that Title would die on.
+                */
+
+               $basename = $this->mDesiredDestName;
+
+               $this->mFilteredName = wfStripIllegalFilenameChars( $basename );
+               /* Normalize to title form before we do any further processing */
+               $nt = Title::makeTitleSafe( NS_FILE, $this->mFilteredName );
+               if( is_null( $nt ) ) {
+                       $this->mTitleError = self::ILLEGAL_FILENAME;
+                       return $this->mTitle = null;
+               }
+               $this->mFilteredName = $nt->getDBkey();
+
+               /**
+                * We'll want to blacklist against *any* 'extension', and use
+                * only the final one for the whitelist.
+                */
+               list( $partname, $ext ) = $this->splitExtensions( $this->mFilteredName );
+
+               if( count( $ext ) ) {
+                       $this->mFinalExtension = trim( $ext[count( $ext ) - 1] );
+               } else {
+                       $this->mFinalExtension = '';
+               }
+
+               /* Don't allow users to override the blacklist (check file extension) */
+               global $wgCheckFileExtensions, $wgStrictFileExtensions;
+               global $wgFileExtensions, $wgFileBlacklist;
+               if ( $this->mFinalExtension == '' ) {
+                       $this->mTitleError = self::FILETYPE_MISSING;
+                       return $this->mTitle = null;
+               } elseif ( $this->checkFileExtensionList( $ext, $wgFileBlacklist ) ||
+                               ( $wgCheckFileExtensions && $wgStrictFileExtensions &&
+                                       !$this->checkFileExtension( $this->mFinalExtension, $wgFileExtensions ) ) ) {
+                       $this->mTitleError = self::FILETYPE_BADTYPE;
+                       return $this->mTitle = null;
+               }
+
+               # If there was more than one "extension", reassemble the base
+               # filename to prevent bogus complaints about length
+               if( count( $ext ) > 1 ) {
+                       for( $i = 0; $i < count( $ext ) - 1; $i++ )
+                               $partname .= '.' . $ext[$i];
+               }
+
+               if( strlen( $partname ) < 1 ) {
+                       $this->mTitleError =  self::MIN_LENGTH_PARTNAME;
+                       return $this->mTitle = null;
+               }
+
+               $nt = Title::makeTitleSafe( NS_FILE, $this->mFilteredName );
+               if( is_null( $nt ) ) {
+                       $this->mTitleError = self::ILLEGAL_FILENAME;
+                       return $this->mTitle = null;
+               }
+               return $this->mTitle = $nt;
+       }
+
+       function getLocalFile() {
+               if( is_null( $this->mLocalFile ) ) {
+                       $nt = $this->getTitle();
+                       $this->mLocalFile = is_null( $nt ) ? null : wfLocalFile( $nt );
+               }
+               return $this->mLocalFile;
+       }
+
+       /**
+        * Stash a file in a temporary directory for later processing
+        * after the user has confirmed it.
+        *
+        * If the user doesn't explicitly cancel or accept, these files
+        * can accumulate in the temp directory.
+        *
+        * @param string $saveName - the destination filename
+        * @param string $tempName - the source temporary file to save
+        * @return string - full path the stashed file, or false on failure
+        * @access private
+        */
+       function saveTempUploadedFile( $saveName, $tempName ) {
+               $repo = RepoGroup::singleton()->getLocalRepo();
+               $status = $repo->storeTemp( $saveName, $tempName );
+               return $status;
+       }
+       /* append to a stashed file */
+       function appendToUploadFile($srcPath, $toAppendPath ){
+               $repo = RepoGroup::singleton()->getLocalRepo();
+               $status = $repo->append($srcPath, $toAppendPath);
+               return $status;
+       }
+
+       /**
+        * Stash a file in a temporary directory for later processing,
+        * and save the necessary descriptive info into the session.
+        * Returns a key value which will be passed through a form
+        * to pick up the path info on a later invocation.
+        *
+        * @return int
+        * @access private
+        */
+       function stashSession() {
+               $status = $this->saveTempUploadedFile( $this->mDestName, $this->mTempPath );
+               if( !$status->isOK() ) {
+                       # Couldn't save the file.
+                       return false;
+               }
+               $mTempPath = $status->value;
+               session_start();//start up the session (might have been previously closed to prevent php session locking)
+               $key = $this->getSessionKey ();
+               $_SESSION['wsUploadData'][$key] = array(
+                       'mTempPath'       => $mTempPath,
+                       'mFileSize'       => $this->mFileSize,
+                       'mSrcName'        => $this->mSrcName,
+                       'mFileProps'      => $this->mFileProps,
+                       'version'         => self::SESSION_VERSION,
+               );
+               session_write_close();
+               return $key;
+       }
+       //pull session Key gen from stash in cases where we want to start an upload without much information
+       function getSessionKey(){
+               $key = mt_rand( 0, 0x7fffffff );
+               $_SESSION['wsUploadData'][$key] = array();
+               return $key;
+       }
+
+       /**
+        * Remove a temporarily kept file stashed by saveTempUploadedFile().
+        * @return success
+        */
+       function unsaveUploadedFile() {
+               $repo = RepoGroup::singleton()->getLocalRepo();
+               $success = $repo->freeTemp( $this->mTempPath );
+               return $success;
+       }
+
+       /**
+        * If we've modified the upload file we need to manually remove it
+        * on exit to clean up.
+        * @access private
+        */
+       function cleanupTempFile() {
+               if ( $this->mRemoveTempFile && $this->mTempPath && file_exists( $this->mTempPath ) ) {
+                       wfDebug( __METHOD__.": Removing temporary file {$this->mTempPath}\n" );
+                       unlink( $this->mTempPath );
+               }
+       }
+
+       function getTempPath() {
+               return $this->mTempPath;
+       }
+
+
+               /**
+        * Split a file into a base name and all dot-delimited 'extensions'
+        * on the end. Some web server configurations will fall back to
+        * earlier pseudo-'extensions' to determine type and execute
+        * scripts, so the blacklist needs to check them all.
+        *
+        * @return array
+        */
+       public static function splitExtensions( $filename ) {
+               $bits = explode( '.', $filename );
+               $basename = array_shift( $bits );
+               return array( $basename, $bits );
+       }
+
+       /**
+        * Perform case-insensitive match against a list of file extensions.
+        * Returns true if the extension is in the list.
+        *
+        * @param string $ext
+        * @param array $list
+        * @return bool
+        */
+       public static function checkFileExtension( $ext, $list ) {
+               return in_array( strtolower( $ext ), $list );
+       }
+
+       /**
+        * Perform case-insensitive match against a list of file extensions.
+        * Returns true if any of the extensions are in the list.
+        *
+        * @param array $ext
+        * @param array $list
+        * @return bool
+        */
+       public static function checkFileExtensionList( $ext, $list ) {
+               foreach( $ext as $e ) {
+                       if( in_array( strtolower( $e ), $list ) ) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+
+       /**
+        * Checks if the mime type of the uploaded file matches the file extension.
+        *
+        * @param string $mime the mime type of the uploaded file
+        * @param string $extension The filename extension that the file is to be served with
+        * @return bool
+        */
+       public static function verifyExtension( $mime, $extension ) {
+               $magic = MimeMagic::singleton();
+
+               if ( ! $mime || $mime == 'unknown' || $mime == 'unknown/unknown' )
+                       if ( ! $magic->isRecognizableExtension( $extension ) ) {
+                               wfDebug( __METHOD__.": passing file with unknown detected mime type; " .
+                                       "unrecognized extension '$extension', can't verify\n" );
+                               return true;
+                       } else {
+                               wfDebug( __METHOD__.": rejecting file with unknown detected mime type; ".
+                                       "recognized extension '$extension', so probably invalid file\n" );
+                               return false;
+                       }
+
+               $match= $magic->isMatchingExtension($extension,$mime);
+
+               if ($match===NULL) {
+                       wfDebug( __METHOD__.": no file extension known for mime type $mime, passing file\n" );
+                       return true;
+               } elseif ($match===true) {
+                       wfDebug( __METHOD__.": mime type $mime matches extension $extension, passing file\n" );
+
+                       #TODO: if it's a bitmap, make sure PHP or ImageMagic resp. can handle it!
+                       return true;
+
+               } else {
+                       wfDebug( __METHOD__.": mime type $mime mismatches file extension $extension, rejecting file\n" );
+                       return false;
+               }
+       }
+
+       /**
+        * Heuristic for detecting files that *could* contain JavaScript instructions or
+        * things that may look like HTML to a browser and are thus
+        * potentially harmful. The present implementation will produce false positives in some situations.
+        *
+        * @param string $file Pathname to the temporary upload file
+        * @param string $mime The mime type of the file
+        * @param string $extension The extension of the file
+        * @return bool true if the file contains something looking like embedded scripts
+        */
+       function detectScript($file, $mime, $extension) {
+               global $wgAllowTitlesInSVG;
+
+               #ugly hack: for text files, always look at the entire file.
+               #For binary field, just check the first K.
+
+               if (strpos($mime,'text/')===0) $chunk = file_get_contents( $file );
+               else {
+                       $fp = fopen( $file, 'rb' );
+                       $chunk = fread( $fp, 1024 );
+                       fclose( $fp );
+               }
+
+               $chunk= strtolower( $chunk );
+
+               if (!$chunk) return false;
+
+               #decode from UTF-16 if needed (could be used for obfuscation).
+               if (substr($chunk,0,2)=="\xfe\xff") $enc= "UTF-16BE";
+               elseif (substr($chunk,0,2)=="\xff\xfe") $enc= "UTF-16LE";
+               else $enc= NULL;
+
+               if ($enc) $chunk= iconv($enc,"ASCII//IGNORE",$chunk);
+
+               $chunk= trim($chunk);
+
+               #FIXME: convert from UTF-16 if necessarry!
+
+               wfDebug("SpecialUpload::detectScript: checking for embedded scripts and HTML stuff\n");
+
+               #check for HTML doctype
+               if (eregi("<!DOCTYPE *X?HTML",$chunk)) return true;
+
+               /**
+               * Internet Explorer for Windows performs some really stupid file type
+               * autodetection which can cause it to interpret valid image files as HTML
+               * and potentially execute JavaScript, creating a cross-site scripting
+               * attack vectors.
+               *
+               * Apple's Safari browser also performs some unsafe file type autodetection
+               * which can cause legitimate files to be interpreted as HTML if the
+               * web server is not correctly configured to send the right content-type
+               * (or if you're really uploading plain text and octet streams!)
+               *
+               * Returns true if IE is likely to mistake the given file for HTML.
+               * Also returns true if Safari would mistake the given file for HTML
+               * when served with a generic content-type.
+               */
+
+               $tags = array(
+                       '<a',
+                       '<body',
+                       '<head',
+                       '<html',   #also in safari
+                       '<img',
+                       '<pre',
+                       '<script', #also in safari
+                       '<table'
+                       );
+               if( ! $wgAllowTitlesInSVG && $extension !== 'svg' && $mime !== 'image/svg' ) {
+                       $tags[] = '<title';
+               }
+
+               foreach( $tags as $tag ) {
+                       if( false !== strpos( $chunk, $tag ) ) {
+                               return true;
+                       }
+               }
+
+               /*
+               * look for javascript
+               */
+
+               #resolve entity-refs to look at attributes. may be harsh on big files... cache result?
+               $chunk = Sanitizer::decodeCharReferences( $chunk );
+
+               #look for script-types
+               if (preg_match('!type\s*=\s*[\'"]?\s*(?:\w*/)?(?:ecma|java)!sim',$chunk)) return true;
+
+               #look for html-style script-urls
+               if (preg_match('!(?:href|src|data)\s*=\s*[\'"]?\s*(?:ecma|java)script:!sim',$chunk)) return true;
+
+               #look for css-style script-urls
+               if (preg_match('!url\s*\(\s*[\'"]?\s*(?:ecma|java)script:!sim',$chunk)) return true;
+
+               wfDebug("SpecialUpload::detectScript: no scripts found\n");
+               return false;
+       }
+
+       function detectScriptInSvg( $filename ) {
+               $check = new XmlTypeCheck( $filename, array( $this, 'checkSvgScriptCallback' ) );
+               return $check->filterMatch;
+       }
+
+       /**
+        * @todo Replace this with a whitelist filter!
+        */
+       function checkSvgScriptCallback( $element, $attribs ) {
+               $stripped = $this->stripXmlNamespace( $element );
+
+               if( $stripped == 'script' ) {
+                       wfDebug( __METHOD__ . ": Found script element '$element' in uploaded file.\n" );
+                       return true;
+               }
+
+               foreach( $attribs as $attrib => $value ) {
+                       $stripped = $this->stripXmlNamespace( $attrib );
+                       if( substr( $stripped, 0, 2 ) == 'on' ) {
+                               wfDebug( __METHOD__ . ": Found script attribute '$attrib'='value' in uploaded file.\n" );
+                               return true;
+                       }
+                       if( $stripped == 'href' && strpos( strtolower( $value ), 'javascript:' ) !== false ) {
+                               wfDebug( __METHOD__ . ": Found script href attribute '$attrib'='$value' in uploaded file.\n" );
+                               return true;
+                       }
+               }
+       }
+
+       private function stripXmlNamespace( $name ) {
+               // 'http://www.w3.org/2000/svg:script' -> 'script'
+               $parts = explode( ':', strtolower( $name ) );
+               return array_pop( $parts );
+       }
+
+
+
+       /**
+        * Generic wrapper function for a virus scanner program.
+        * This relies on the $wgAntivirus and $wgAntivirusSetup variables.
+        * $wgAntivirusRequired may be used to deny upload if the scan fails.
+        *
+        * @param string $file Pathname to the temporary upload file
+        * @return mixed false if not virus is found, NULL if the scan fails or is disabled,
+        *         or a string containing feedback from the virus scanner if a virus was found.
+        *         If textual feedback is missing but a virus was found, this function returns true.
+        */
+       function detectVirus($file) {
+               global $wgAntivirus, $wgAntivirusSetup, $wgAntivirusRequired, $wgOut;
+
+               if ( !$wgAntivirus ) {
+                       wfDebug( __METHOD__.": virus scanner disabled\n");
+                       return NULL;
+               }
+
+               if ( !$wgAntivirusSetup[$wgAntivirus] ) {
+                       wfDebug( __METHOD__.": unknown virus scanner: $wgAntivirus\n" );
+                       $wgOut->wrapWikiMsg( '<div class="error">$1</div>', array( 'virus-badscanner', $wgAntivirus ) );
+                       return wfMsg('virus-unknownscanner') . " $wgAntivirus";
+               }
+
+               # look up scanner configuration
+               $command = $wgAntivirusSetup[$wgAntivirus]["command"];
+               $exitCodeMap = $wgAntivirusSetup[$wgAntivirus]["codemap"];
+               $msgPattern = isset( $wgAntivirusSetup[$wgAntivirus]["messagepattern"] ) ?
+                       $wgAntivirusSetup[$wgAntivirus]["messagepattern"] : null;
+
+               if ( strpos( $command,"%f" ) === false ) {
+                       # simple pattern: append file to scan
+                       $command .= " " . wfEscapeShellArg( $file );
+               } else {
+                       # complex pattern: replace "%f" with file to scan
+                       $command = str_replace( "%f", wfEscapeShellArg( $file ), $command );
+               }
+
+               wfDebug( __METHOD__.": running virus scan: $command \n" );
+
+               # execute virus scanner
+               $exitCode = false;
+
+               #NOTE: there's a 50 line workaround to make stderr redirection work on windows, too.
+               #      that does not seem to be worth the pain.
+               #      Ask me (Duesentrieb) about it if it's ever needed.
+               $output = array();
+               if ( wfIsWindows() ) {
+                       exec( "$command", $output, $exitCode );
+               } else {
+                       exec( "$command 2>&1", $output, $exitCode );
+               }
+
+               # map exit code to AV_xxx constants.
+               $mappedCode = $exitCode;
+               if ( $exitCodeMap ) {
+                       if ( isset( $exitCodeMap[$exitCode] ) ) {
+                               $mappedCode = $exitCodeMap[$exitCode];
+                       } elseif ( isset( $exitCodeMap["*"] ) ) {
+                               $mappedCode = $exitCodeMap["*"];
+                       }
+               }
+
+               if ( $mappedCode === AV_SCAN_FAILED ) {
+                       # scan failed (code was mapped to false by $exitCodeMap)
+                       wfDebug( __METHOD__.": failed to scan $file (code $exitCode).\n" );
+
+                       if ( $wgAntivirusRequired ) {
+                               return wfMsg('virus-scanfailed', array( $exitCode ) );
+                       } else {
+                               return NULL;
+                       }
+               } else if ( $mappedCode === AV_SCAN_ABORTED ) {
+                       # scan failed because filetype is unknown (probably imune)
+                       wfDebug( __METHOD__.": unsupported file type $file (code $exitCode).\n" );
+                       return NULL;
+               } else if ( $mappedCode === AV_NO_VIRUS ) {
+                       # no virus found
+                       wfDebug( __METHOD__.": file passed virus scan.\n" );
+                       return false;
+               } else {
+                       $output = join( "\n", $output );
+                       $output = trim( $output );
+
+                       if ( !$output ) {
+                               $output = true; #if there's no output, return true
+                       } elseif ( $msgPattern ) {
+                               $groups = array();
+                               if ( preg_match( $msgPattern, $output, $groups ) ) {
+                                       if ( $groups[1] ) {
+                                               $output = $groups[1];
+                                       }
+                               }
+                       }
+
+                       wfDebug( __METHOD__.": FOUND VIRUS! scanner feedback: $output \n" );
+                       return $output;
+               }
+       }
+
+       /**
+        * Check if the temporary file is MacBinary-encoded, as some uploads
+        * from Internet Explorer on Mac OS Classic and Mac OS X will be.
+        * If so, the data fork will be extracted to a second temporary file,
+        * which will then be checked for validity and either kept or discarded.
+        *
+        * @access private
+        */
+       function checkMacBinary() {
+               $macbin = new MacBinary( $this->mTempPath );
+               if( $macbin->isValid() ) {
+                       $dataFile = tempnam( wfTempDir(), "WikiMacBinary" );
+                       $dataHandle = fopen( $dataFile, 'wb' );
+
+                       wfDebug( "SpecialUpload::checkMacBinary: Extracting MacBinary data fork to $dataFile\n" );
+                       $macbin->extractData( $dataHandle );
+
+                       $this->mTempPath = $dataFile;
+                       $this->mFileSize = $macbin->dataForkLength();
+
+                       // We'll have to manually remove the new file if it's not kept.
+                       $this->mRemoveTempFile = true;
+               }
+               $macbin->close();
+       }
+
+       /**
+        * Check if there's an overwrite conflict and, if so, if restrictions
+        * forbid this user from performing the upload.
+        *
+        * @return mixed true on success, WikiError on failure
+        * @access private
+        */
+       function checkOverwrite() {
+               global $wgUser;
+               // First check whether the local file can be overwritten
+               if( $this->mLocalFile->exists() )
+                       if( !self::userCanReUpload( $wgUser, $this->mLocalFile ) )
+                               return 'fileexists-forbidden';
+
+               // Check shared conflicts
+               $file = wfFindFile( $this->mLocalFile->getName() );
+               if ( $file && ( !$wgUser->isAllowed( 'reupload' ) ||
+                               !$wgUser->isAllowed( 'reupload-shared' ) ) )
+                       return 'fileexists-shared-forbidden';
+
+               return true;
+
+       }
+       /**
+        * Check if a user is the last uploader
+        *
+        * @param User $user
+        * @param string $img, image name
+        * @return bool
+        */
+       public static function userCanReUpload( User $user, $img ) {
+               if( $user->isAllowed( 'reupload' ) )
+                       return true; // non-conditional
+               if( !$user->isAllowed( 'reupload-own' ) )
+                       return false;
+               if( is_string( $img ) )
+                       $img = wfLocalFile( $img );
+               if ( !( $img instanceof LocalFile ) )
+                       return false;
+
+               return $user->getId() == $img->getUser( 'id' );
+       }
+
+       public static function getExistsWarning( $file ) {
+               if( $file->exists() )
+                       return array( 'exists', $file );
+
+               if( $file->getTitle()->getArticleID() )
+                       return array( 'page-exists', $file );
+
+               if( strpos( $file->getName(), '.' ) == false ) {
+                       $partname = $file->getName();
+                       $rawExtension = '';
+               } else {
+                       $n = strrpos( $file->getName(), '.' );
+                       $rawExtension = substr( $file->getName(), $n + 1 );
+                       $partname = substr( $file->getName(), 0, $n );
+               }
+
+               if ( $rawExtension != $file->getExtension() ) {
+                       // We're not using the normalized form of the extension.
+                       // Normal form is lowercase, using most common of alternate
+                       // extensions (eg 'jpg' rather than 'JPEG').
+                       //
+                       // Check for another file using the normalized form...
+                       $nt_lc = Title::makeTitle( NS_FILE, $partname . '.' . $file->getExtension() );
+                       $file_lc = wfLocalFile( $nt_lc );
+
+                       if( $file_lc->exists() )
+                               return array( 'exists-normalized', $file_lc );
+               }
+
+               if ( self::isThumbName( $file->getName() ) ) {
+                       # Check for filenames like 50px- or 180px-, these are mostly thumbnails
+                       $nt_thb = Title::newFromText( substr( $partname , strpos( $partname , '-' ) +1 ) . '.' . $rawExtension );
+                       $file_thb = wfLocalFile( $nt_thb );
+                       if( $file_thb->exists() )
+                               return array( 'thumb', $file_thb );
+               }
+
+               return false;
+       }
+
+       public static function isThumbName( $filename ) {
+               $n = strrpos( $filename, '.' );
+               $partname = $n ? substr( $filename, 0, $n ) : $filename;
+               return (
+                                       substr( $partname , 3, 3 ) == 'px-' ||
+                                       substr( $partname , 2, 3 ) == 'px-'
+                               ) &&
+                               ereg( "[0-9]{2}" , substr( $partname , 0, 2) );
+       }
+
+       /**
+        * Get a list of blacklisted filename prefixes from [[MediaWiki:filename-prefix-blacklist]]
+        *
+        * @return array list of prefixes
+        */
+       public static function getFilenamePrefixBlacklist() {
+               $blacklist = array();
+               $message = wfMsgForContent( 'filename-prefix-blacklist' );
+               if( $message && !( wfEmptyMsg( 'filename-prefix-blacklist', $message ) || $message == '-' ) ) {
+                       $lines = explode( "\n", $message );
+                       foreach( $lines as $line ) {
+                               // Remove comment lines
+                               $comment = substr( trim( $line ), 0, 1 );
+                               if ( $comment == '#' || $comment == '' ) {
+                                       continue;
+                               }
+                               // Remove additional comments after a prefix
+                               $comment = strpos( $line, '#' );
+                               if ( $comment > 0 ) {
+                                       $line = substr( $line, 0, $comment-1 );
+                               }
+                               $blacklist[] = trim( $line );
+                       }
+               }
+               return $blacklist;
+       }
+
+
+}
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
new file mode 100644 (file)
index 0000000..c822e18
--- /dev/null
@@ -0,0 +1,231 @@
+<?php
+/*
+* first destination checks are made (if ignorewarnings is not checked) errors / warning is returned.
+*
+* we return the uploadUrl
+* we then accept chunk uploads from the client.
+* return chunk id on each POSTED chunk
+* once the client posts done=1 concatenated the files together.
+* more info at: http://firefogg.org/dev/chunk_post.html
+*/
+class UploadFromChunks extends UploadBase {
+
+       var $chunk_mode; //init, chunk, done
+       var $mSessionKey = false;
+       var $status = array();
+
+       const INIT      = 1;
+       const CHUNK = 2;
+       const DONE      = 3;
+
+       function initializeFromParams( $param , &$request) {
+               $this->initFromSessionKey( $param['chunksessionkey'], $request );
+               //set the chunk mode:
+               if( !$this->mSessionKey && !$param['done'] ){
+                       //session key not set init the chunk upload system:
+                       $this->chunk_mode = UploadFromChunks::INIT;
+                       $this->mDesiredDestName = $param['filename'];
+
+               }else if( $this->mSessionKey && !$param['done']){
+                       //this is a chunk piece
+                       $this->chunk_mode = UploadFromChunks::CHUNK;
+               }else if( $this->mSessionKey && $param['done']){
+                       //this is the last chunk
+                       $this->chunk_mode = UploadFromChunks::DONE;
+               }
+               if( $this->chunk_mode == UploadFromChunks::CHUNK ||
+                   $this->chunk_mode == UploadFromChunks::DONE ){
+                               //set chunk related vars:
+                               $this->mTempPath = $request->getFileTempName( 'chunk' );
+                               $this->mFileSize = $request->getFileSize( 'chunk' );
+               }
+
+               return $this->status;
+       }
+
+       static function isValidRequest( $request ) {
+               $sessionData = $request->getSessionData('wsUploadData');
+               if(! self::isValidSessionKey(
+                       $request->getInt( 'wpSessionKey' ),
+                       $sessionData) )
+                               return false;
+               //check for the file:
+               return (bool)$request->getFileTempName( 'file' );
+       }
+
+       /* check warnings depending on chunk_mode*/
+       function checkWarnings(){
+               $warning = array();
+               return $warning;
+       }
+
+       function isEmptyFile(){
+               //does not apply to chunk init
+               if(  $this->chunk_mode ==  UploadFromChunks::INIT ){
+                       return false;
+               }else{
+                       return parent::isEmptyFile();
+               }
+       }
+       /* Verify whether the upload is sane.
+        * Returns self::OK or else an array with error information
+        */
+       function verifyUpload( $resultDetails ) {
+               //no checks on chunk upload mode:
+               if( $this->chunk_mode ==  UploadFromChunks::INIT )
+                       return self::OK;
+
+               //verify on init and last chunk request
+               if(     $this->chunk_mode == UploadFromChunks::CHUNK ||
+                       $this->chunk_mode == UploadFromChunks::DONE )
+                       return parent::verifyUpload( $resultDetails );
+       }
+       //only run verifyFile on completed uploaded chunks
+       function verifyFile( $tmpFile ){
+               if( $this->chunk_mode == UploadFromChunks::DONE ){
+                       //first append last chunk (so we can do a real verifyFile check... (check file type etc)
+                       $status = $this->doChunkAppend();
+                       if( $status->isOK() ){
+                               $this->mTempPath = $this->getRealPath( $this->mTempAppendPath );
+                               //verify the completed merged chunks as if it was the file that got uploaded:
+                               return parent::verifyFile( $this->mTempPath ) ;
+                       }else{
+                               //conflict of status returns (have to return the error ary) ... why we don't consistantly use a status object is beyond me..
+                               return $status->getErrorsArray();
+                       }
+               }else{
+                       return true;
+               }
+       }
+       function getRealPath($srcPath){
+               $repo = RepoGroup::singleton()->getLocalRepo();
+               if ( $repo->isVirtualUrl( $srcPath) ) {
+                       return $repo->resolveVirtualUrl( $srcPath );
+               }
+       }
+       //pretty ugly inter-mixing of mParam and local vars
+       function setupChunkSession( $summary, $comment, $watch ) {
+               $this->mSessionKey = $this->getSessionKey();
+               $_SESSION['wsUploadData'][ $this->mSessionKey ] = array(
+                       'mComment'                      => $comment,
+                   'mSummary'                  => $summary,
+                       'mWatch'                        => $watch,
+                       'mFilteredName'         => $this->mFilteredName,
+                       'mTempAppendPath'       => null, //the repo append path (not temporary local node mTempPath)
+                       'mDesiredDestName'      => $this->mDesiredDestName,
+                       'version'               => self::SESSION_VERSION,
+               );
+               return $this->mSessionKey;
+       }
+    function initFromSessionKey( $sessionKey, $request ){
+               if( !$sessionKey || empty( $sessionKey ) ){
+                       return false;
+               }
+               $this->mSessionKey = $sessionKey;
+               //load the sessionData array:
+               $sessionData = $request->getSessionData('wsUploadData');
+
+               if( isset( $sessionData[$this->mSessionKey]['version'] ) &&
+                       $sessionData[$this->mSessionKey]['version'] == self::SESSION_VERSION ) {
+                       //update the local object from the session                      //
+                       $this->mComment          = $sessionData[ $this->mSessionKey ][ 'mComment' ];
+                       $this->mSummary          = $sessionData[ $this->mSessionKey ][ 'mSummary' ];
+                       $this->mWatch            = $sessionData[ $this->mSessionKey ][ 'mWatch' ];
+            $this->mIgnorewarnings   = $sessionData[ $this->mSessionKey ][ 'mIgnorewarnings' ];
+                       $this->mFilteredName     = $sessionData[ $this->mSessionKey ][ 'mFilteredName' ];
+                       $this->mTempAppendPath   = $sessionData[ $this->mSessionKey ][ 'mTempAppendPath' ];
+                       $this->mDesiredDestName  = $sessionData[ $this->mSessionKey ][ 'mDesiredDestName' ];
+               }else{
+                       $this->status = Array( 'error'=> 'missing session data');
+                       return false;
+               }
+       }
+       //lets us return an api result (as flow for chunk uploads is kind of different than others.
+       function performUpload($summary='', $comment='', $watch='', $user){
+               global $wgServer, $wgScriptPath, $wgUser;
+               if( $this->chunk_mode == UploadFromChunks::INIT ){
+                       //firefogg expects a specific result per:
+                       //http://www.firefogg.org/dev/chunk_post.html
+
+                       //its oky to return the token here because
+                       //a) the user must have requested the token to get here and
+                       //b) should only happen over POST
+                       //c) (we need the token to validate chunks are coming from a non-xss request)
+                       $token = urlencode( $wgUser->editToken() );
+                       ob_clean();
+                       echo ApiFormatJson::getJsonEncode( array(
+                                       "uploadUrl" => "{$wgServer}{$wgScriptPath}/api.php?action=upload&".
+                                                                       "token={$token}&format=json&enablechunks=true&chunksessionkey=".
+                                                                       $this->setupChunkSession($summary, $comment, $watch ) ) );
+                       exit(0);
+               }else if( $this->chunk_mode == UploadFromChunks::CHUNK ){
+                       $status = $this->doChunkAppend();
+                       if( $status->isOK() ){
+                               //return success:
+                               //firefogg expects a specific result per:
+                               //http://www.firefogg.org/dev/chunk_post.html
+                               ob_clean();
+                               echo ApiFormatJson::getJsonEncode( array(
+                                               "result"=>1,
+                                               "filesize"=> filesize( $this->getRealPath( $this->mTempAppendPath ) )
+                                       )
+                               );
+                               exit(0);
+                               /*return array(
+                                       'result' => 1
+                               );*/
+                       }else{
+                               return $status;
+                       }
+               }else if( $this->chunk_mode == UploadFromChunks::DONE ){
+                   //update the values from the local (session init) if not paseed again)
+            if($summary == '')
+                $summary = $this->mSummary;
+
+            if($comment == '')
+                $comment = $this->mComment;
+
+            if($watch == '')
+                $watch = $this->mWatch;
+                       $status = parent::performUpload($summary, $comment, $watch, $user );
+                       if( !$status->isGood() ) {
+                               return $status;
+                       }
+                       $file = $this->getLocalFile();
+                       //firefogg expects a specific result per:
+                       //http://www.firefogg.org/dev/chunk_post.html
+                       ob_clean();
+                       echo ApiFormatJson::getJsonEncode( array(
+                                       "result"=>1,
+                                       "done"=>1,
+                                       "resultUrl"=> $file->getDescriptionUrl()
+                               )
+                       );
+                       exit(0);
+
+               }
+       }
+       //append the given chunk to the temporary uploaded file. (if no temporary uploaded file exists created it.
+       function doChunkAppend(){
+               //if we don't have a mTempAppendPath to generate a file from the chunk packaged var:
+               if( ! $this->mTempAppendPath ){
+                       //die();
+                       //get temp name:
+                       //make a chunk store path. (append tmp file to chunk)
+                       $status = $this->saveTempUploadedFile( $this->mDestName, $this->mTempPath );
+
+                       if( $status->isOK() ) {
+                               $this->mTempAppendPath = $status->value;
+                               $_SESSION[ 'wsUploadData' ][ $this->mSessionKey ][ 'mTempAppendPath' ] = $this->mTempAppendPath;
+                       }
+                       return $status;
+               }else{
+                       if( is_file( $this->getRealPath( $this->mTempAppendPath ) ) ){
+                               $status = $this->appendToUploadFile( $this->mTempAppendPath,  $this->mTempPath );
+                       }else{
+                               $status->fatal( 'filenotfound', $this->mTempAppendPath );
+                       }
+                       return $status;
+               }
+       }
+}
diff --git a/includes/upload/UploadFromFile.php b/includes/upload/UploadFromFile.php
new file mode 100644 (file)
index 0000000..3b17344
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+class UploadFromFile extends UploadBase {
+
+       function initializeFromRequest( &$request ) {
+               $desiredDestName = $request->getText( 'wpDestFile' );
+               if( !$desiredDestName )
+                       $desiredDestName = $request->getText( 'wpUploadFile' );
+               return $this->initialize(
+                       $desiredDestName,
+                       $request->getFileTempName( 'wpUploadFile' ),
+                       $request->getFileSize( 'wpUploadFile' )
+               );
+       }
+
+       static function isValidRequest( $request ) {
+               return (bool)$request->getFileTempName( 'wpUploadFile' );
+       }
+}
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
new file mode 100644 (file)
index 0000000..03de698
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+class UploadFromStash extends UploadBase {
+       static function isValidSessionKey( $key, $sessionData ) {
+               return !empty( $key ) && 
+                       is_array( $sessionData ) && 
+                       isset( $sessionData[$key] ) && 
+                       isset( $sessionData[$key]['version'] ) && 
+                       $sessionData[$key]['version'] == self::SESSION_VERSION
+               ;
+       }
+       static function isValidRequest(& $request ) {           
+               $sessionData = $request->getSessionData('wsUploadData');                
+               return self::isValidSessionKey( 
+                       $request->getInt( 'wpSessionKey' ),
+                       $sessionData
+               );
+       }       
+       function initialize( $name, $sessionData ) {
+                       /**
+                        * Confirming a temporarily stashed upload.
+                        * We don't want path names to be forged, so we keep
+                        * them in the session on the server and just give
+                        * an opaque key to the user agent.
+                        */                                             
+                       parent::initialize( $name, 
+                               $sessionData['mTempPath'], 
+                               $sessionData['mFileSize'],
+                               false
+                       );
+
+                       $this->mFileProps        = $sessionData['mFileProps'];
+       }
+       function initializeFromRequest( &$request ) {           
+               $sessionKey = $request->getInt( 'wpSessionKey' );
+               $sessionData = $request->getSessionData('wsUploadData');
+               
+               $desiredDestName = $request->getText( 'wpDestFile' );
+               if( !$desiredDestName )
+                       $desiredDestName = $request->getText( 'wpUploadFile' );         
+               return $this->initialize( $desiredDestName, $sessionData[$sessionKey] );
+       }
+       
+       /**
+        * File has been previously verified so no need to do so again.
+        */
+       protected function verifyFile( $tmpfile ) {
+               return true;
+       }
+       /**
+        * We're here from "ignore warnings anyway" so return just OK
+        */
+       function checkWarnings() {
+               return array();
+       }
+}
+?>
\ No newline at end of file
diff --git a/includes/upload/UploadFromUrl.php b/includes/upload/UploadFromUrl.php
new file mode 100644 (file)
index 0000000..e10f0bd
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+class UploadFromUrl extends UploadBase {
+       protected $mTempDownloadPath;
+       
+       //by default do a SYNC_DOWNLOAD 
+       protected $dl_mode = null;
+       
+       static function isAllowed( $user ) {
+               if( !$user->isAllowed( 'upload_by_url' ) )
+                       return 'upload_by_url';
+               return parent::isAllowed( $user );
+       }
+       static function isEnabled() {
+               global $wgAllowCopyUploads;
+               return $wgAllowCopyUploads && parent::isEnabled();
+       }       
+       /*entry point for Api upload:: ASYNC_DOWNLOAD (if possible) */
+       function initialize( $name, $url, $asyncdownload = false) {             
+               global $wgTmpDirectory, $wgPhpCliPath;                          
+                       
+               //check for $asyncdownload request: 
+               if($asyncdownload !== false){
+                       if($wgPhpCliPath && wfShellExecEnabled() ){
+                               $this->dl_mode = Http::ASYNC_DOWNLOAD;
+                       }else{
+                               $this->dl_mode = Http::SYNC_DOWNLOAD;   
+                       }
+               }
+               
+               $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' );
+               parent::initialize( $name, $local_file, 0, true );
+                               
+               $this->mUrl = trim( $url );             
+       }
+       public function isAsync(){
+               return $this->dl_mode == Http::ASYNC_DOWNLOAD;
+       }
+       /*entry point for SpecialUpload no ASYNC_DOWNLOAD possible: */
+       function initializeFromRequest( &$request ) {           
+
+               //set dl mode if not set:
+               if(!$this->dl_mode)
+                       $this->dl_mode = Http::SYNC_DOWNLOAD;   
+                       
+               $desiredDestName = $request->getText( 'wpDestFile' );
+               if( !$desiredDestName )
+                       $desiredDestName = $request->getText( 'wpUploadFile' );         
+               return $this->initialize( 
+                       $desiredDestName, 
+                       $request->getVal('wpUploadFileURL')
+               );
+       }
+       /**
+        * Do the real fetching stuff
+        */
+       function fetchFile( ) {                 
+               //entry point for SpecialUplaod 
+               if( self::isValidURI($this->mUrl) === false) {
+                       return Status::newFatal('upload-proto-error');
+               }                               
+               //now do the actual download to the target file:                        
+               $status = Http::doDownload ( $this->mUrl, $this->mTempPath, $this->dl_mode );                                           
+               
+               //update the local filesize var: 
+               $this->mFileSize = filesize( $this->mTempPath );                                        
+                                               
+               return $status;                                 
+       }
+       
+       static function isValidRequest( $request ){
+               if( !$request->getVal('wpUploadFileURL') )
+                       return false;
+               //check that is a valid url:
+               return self::isValidURI( $request->getVal('wpUploadFileURL') );
+       }
+       static function isValidURI( $uri ){
+               return preg_match('/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/',
+                                                 $uri, $matches);
+       }
+}
\ No newline at end of file
diff --git a/js2/README b/js2/README
new file mode 100644 (file)
index 0000000..4daa7f5
--- /dev/null
@@ -0,0 +1,3 @@
+MediaWiki Javascript phase 2
+
+Documentaiton to follow: 
\ No newline at end of file
diff --git a/js2/editPage.js b/js2/editPage.js
new file mode 100644 (file)
index 0000000..0ddd1e9
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * js2 style replacement for mediaWiki edit.js 
+ */
+//setup configuration vars: 
+if(!mwAddMediaConfig)
+       var mwAddMediaConfig = {
+                       'profile':'mediawiki_edit',                     
+                       'target_textbox': '#wpTextbox1',                        
+                       //note selections in the textbox will take over the default query
+                       'default_query': wgTitle,
+                       'target_title':wgPageName,                      
+                       //here we can setup the conten provider overides
+                       'cpconfig': {},                                 
+                       
+                       //the local wiki api url: 
+                       'local_wiki_api_url': wgServer + wgScriptPath + '/api.php'
+               };
+
+
+mwAddOnloadHook( function(){
+       mwEditPageHelper.init();        
+});
+var mwEditPageHelper = {       
+       init:function(){
+               var _this = this;
+               //@@todo check for new version of toolbar and add properly:
+               if(typeof $j.fn.toolbar == 'undefined'){                        
+                       //add the add-media-wizard button for old toolbar: 
+                       $j('#toolbar').append('<img style="cursor:pointer" id="btn-add-media-wiz" src="' + mv_skin_img_path + 'Button_add_media.png">');
+                       $j('#btn-add-media-wiz').addMediaWiz( 
+                                       mwAddMediaConfig 
+                       );              
+               }
+       }
+}
diff --git a/js2/mwEmbed/README b/js2/mwEmbed/README
new file mode 100644 (file)
index 0000000..05d3219
--- /dev/null
@@ -0,0 +1,91 @@
+***********************************************
+*
+* mwEmbed version 1.1
+* for details see: http://metavid.ucsc.edu/wiki/index.php/mwEmbed
+* and this README
+*
+* All Metavid Wiki code is Released under the GPL2
+* for more info visit http:/metavid.ucsc.edu/code
+*
+* @author Michael Dale, 
+* @email dale@ucsc.edu
+* @url http://metavid.org
+*
+*********************************************
+
+v.1.1
+Major refactoring lots of new interfaces (full release info to follow shortly)
+
+v.6
+* added msg system for compatibility with translations
+* add support for relative file or path names for media files for cortado.
+* added support for safari
+** will force load javascript instead of DOM injection
+** slower on pages without video clips
+* added "experimental" support for "sequences" and editing. (see http://metavid.ucsc.edu/blog/
+* improved playlists usage
+
+v.5
+* add support for playlists, basic usage: <playlist id="plid" src="playlist.xml"/>
+       * see sample_page.php for example usage of playlist
+* better support for different resolutions.
+* inline playlist:
+
+
+
+
+v.4
+* adds support for oggplay with playhead: http://www.annodex.net/software/plugin/index.html
+* adds linkback support (for adding a link back to a particular page)
+* adds config value for selecting cortado in an iframe or loaded in the page
+
+v.3 an intermediary release: supports vlc, basic cortado, basic mplayer/totem
+well tested browsers are firefox & IE 6 (more testing needed for more browsers)
+
+
+the goal of mv_embed is to create a complete/wrapper fall back system for
+the liboggplay API:
+
+http://wiki.xiph.org/index.php/OggPlayJavascriptAPI
+
+& integrate the video element as close as possible with the html5 spec:
+http://www.whatwg.org/specs/web-apps/current-work/#video
+
+it attempts to wrap these calls for the following players:
+I try to include a link to their Javascript apis if I can find one:
+
+(initially just cortado and vlc)
+cortado applet: a custom build of the fluendos java based applet
+(included with the mv_embed package in the future we should get a signed applet hosted
+so that cross domain video playing does not require a copy of cortado+iframe on that server)
+    http://www.flumotion.net/cortado/
+
+vlc plugin: video lan client plugin
+    http://www.videolan.org/doc/play-howto/en/ch04.html#id293992
+
+mplayer plugin: the mplayer plugin
+    http://mplayerplug-in.cvs.sourceforge.net/mplayerplug-in/mplayerplug-in/DOCS/tech/javascript.txt?view=markup
+
+totem:
+    http://www.gnome.org/projects/totem/
+
+
+Sample Usage:
+<script type="text/javascript" src="mv_embed.js" />
+<video id="video_id" src="video_url"></video>
+
+once the page loads the video_id object is rewritten as an mv_embed object
+
+
+Supported Attributes for <video> tag:
+type   name            [default]       description
+bool    autoplay    [false]    if the clip should play on page load
+bool    controls       [true]          if the default interface should be displayed (see interface)
+string  id          null       the id of the html element useful for grabbing the video object
+string  src                    null            the url src for the video file
+string  thumbnail   logo       the thumbnail to be displayed a frame grab is ideal.
+string  linkback    link       a info link back for more info about this stream
+                                                               (useful for when the clip is embed externally)
+int     width       [320]      the video display width
+int     height      [240]      the video display height
+bool    embed_link  [ture]             if the html to embed this clip on an external page should be displayed
diff --git a/js2/mwEmbed/binPlayers/cortado/README b/js2/mwEmbed/binPlayers/cortado/README
new file mode 100644 (file)
index 0000000..554c23b
--- /dev/null
@@ -0,0 +1 @@
+This version of cortado comes form http://theora.org/cortado.jar it should cloesly mirror the svn version hosted by wikimedia
diff --git a/js2/mwEmbed/binPlayers/cortado/cortado.jar b/js2/mwEmbed/binPlayers/cortado/cortado.jar
new file mode 100644 (file)
index 0000000..30565ef
Binary files /dev/null and b/js2/mwEmbed/binPlayers/cortado/cortado.jar differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/LICENSE.txt b/js2/mwEmbed/binPlayers/flowplayer/LICENSE.txt
new file mode 100644 (file)
index 0000000..20d40b6
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/flowplayer/README.txt b/js2/mwEmbed/binPlayers/flowplayer/README.txt
new file mode 100644 (file)
index 0000000..22624ed
--- /dev/null
@@ -0,0 +1,52 @@
+Version history:
+
+RC2
+---
+- fixed: setting the screen height in configuration did not have any effect
+
+RC1
+-----
+- better error message if plugin loading fails, shows the URL used
+- validates our redesigned multidomain license key correctly
+- fix to prevent the play button going visible when the onBufferEmpty event occurs
+- the commercial swf now correctly loads the controls using version information
+- fixed: the play button overlay became invisible with long fadeOutSpeeds
+
+beta6
+-----
+- removed the onFirstFramePause event
+- playing a clip for the second time caused a doubled sound
+- pausing on first frame did not work on some FLV files
+
+beta5
+-----
+- logo only uses percentage scaling if it's a SWF file (there is ".swf" in it's url)
+- context menu now correctly builds up from string entries in configuration
+-always closes the previous connection before starting a new clip
+
+beta4
+-----
+- now it's possible to load a plugin into the panel without specifying any position/dimensions
+ information, the plugin is placed to left: "50%", top: "50%" and using the plugin DisplayObject's width & height
+- The Flowplayer API was not fully initialized when onLoad was invoked on Flash plugins
+
+beta3
+-----
+- tweaking logo placement
+- "play" did not show up after repeated pause/resume
+- player now loads the latest controls SWF version, right now the latest SWF is called 'flowplayer.controls-3.0.0-beta2.swf'
+
+beta2
+-----
+- fixed support for RTMP stream groups
+- changed to loop through available fonts in order to find a suitable font also in IE
+- Preloader was broken on IE: When the player SWf was in browser's cache it did not initialize properly
+- Context menu now correctly handles menu items that are configured by their string labels only (not using json objects)
+- fixed custom logo positioning (was moved to the left edge of screen in fullscreen)
+- "play" now always follows the position and size of the screen
+- video was stretched below the controls in fullscreen when autoHide: 'never'
+- logo now takes 6.5% of the screen height, width is scaled so that the aspect ratio is preserved
+
+beta1
+-----
+- First public beta release
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.js b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.js
new file mode 100644 (file)
index 0000000..52f2780
--- /dev/null
@@ -0,0 +1,1520 @@
+/**
+ * flowplayer.js 3.0.0-rc2. The Flowplayer API.
+ * 
+ * This file is part of Flowplayer, http://flowplayer.org
+ *
+ * Author: Tero Piirainen, <support@flowplayer.org>
+ * Copyright (c) 2008 Flowplayer Ltd
+ *
+ * Released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * 
+ * Version: 3.0.0-rc2 - Fri Nov 07 2008 16:50:59 GMT-0000 (GMT+00:00)
+ */
+(function() {
+/* 
+       FEATURES 
+       --------
+       - handling multiple instances 
+       - Flowplayer programming API 
+       - Flowplayer event model        
+       - player loading / unloading
+       - $f() function
+       - jQuery support
+*/ 
+
+/*jslint glovar: true, browser: true */
+/*global flowplayer, $f */
+
+// {{{ private utility methods
+       
+       function log(args) {
+               
+               // write into opera console
+               if (typeof opera == 'object') {
+                       opera.postError("$f.fireEvent: " + args.join(" | "));   
+
+                       
+               } else if (typeof console == 'object') {
+                       console.log("$f.fireEvent", [].slice.call(args));       
+               }
+       }
+
+               
+       // thanks: http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
+       function clone(obj) {   
+               if (!obj || typeof obj != 'object') { return obj; }             
+               var temp = new obj.constructor();       
+               for (var key in obj) {  
+                       if (obj.hasOwnProperty(key)) {
+                               temp[key] = clone(obj[key]);
+                       }
+               }               
+               return temp;
+       }
+
+       // stripped from jQuery, thanks John Resig 
+       function each(obj, fn) {
+               if (!obj) { return; }
+               
+               var name, i = 0, length = obj.length;
+       
+               // object
+               if (length === undefined) {
+                       for (name in obj) {
+                               if (fn.call(obj[name], name, obj[name]) === false) { break; }
+                       }
+                       
+               // array
+               } else {
+                       for (var value = obj[0];
+                               i < length && fn.call( value, i, value ) !== false; value = obj[++i]) {                         
+                       }
+               }
+       
+               return obj;
+       }
+
+       
+       // convenience
+       function el(id) {
+               return document.getElementById(id);     
+       }       
+
+       
+       // used extensively. a very simple implementation. 
+       function extend(to, from, skipFuncs) {
+               if (to && from) {                       
+                       each(from, function(name, value) {
+                               if (!skipFuncs || typeof value != 'function') {
+                                       to[name] = value;               
+                               }
+                       });
+               }
+       }
+       
+       // var arr = select("elem.className"); 
+       function select(query) {
+               var index = query.indexOf("."); 
+               if (index != -1) {
+                       var tag = query.substring(0, index) || "*";
+                       var klass = query.substring(index + 1, query.length);
+                       var els = [];
+                       each(document.getElementsByTagName(tag), function() {
+                               if (this.className && this.className.indexOf(klass) != -1) {
+                                       els.push(this);         
+                               }
+                       });
+                       return els;
+               }
+       }
+       
+       // fix event inconsistencies across browsers
+       function stopEvent(e) {
+               e = e || window.event;
+               
+               if (e.preventDefault) {
+                       e.stopPropagation();
+                       e.preventDefault();
+                       
+               } else {
+                       e.returnValue = false;  
+                       e.cancelBubble = true;
+               } 
+               return false;
+       }
+
+       // push an event listener into existing array of listeners
+       function bind(to, evt, fn) {
+               to[evt] = to[evt] || [];
+               to[evt].push(fn);               
+       }
+       
+       
+       // generates an unique id
+   function makeId() {
+         return "_" + ("" + Math.random()).substring(2, 10);   
+   }
+       
+//}}}  
+       
+
+// {{{ Clip
+
+       var Clip = function(json, index, player) {
+               
+               // private variables
+               var self = this;
+               var cuepoints = {};
+               var listeners = {}; 
+               this.index = index;
+               
+               // instance variables
+               if (typeof json == 'string') {
+                       json = {url:json};      
+               }
+       
+               extend(this, json, true);       
+               
+               // event handling 
+               each(("Start*,MetaData,Pause*,Resume*,Seek*,Stop*,Finish,LastSecond,Update,BufferFull,BufferEmpty").split(","),
+                       function() {
+                       
+                       var evt = "on" + this;
+                               
+                       // before event
+                       if (evt.indexOf("*") != -1) {
+                               evt = evt.substring(0, evt.length -1); 
+                               var before = "onBefore" + evt.substring(2); 
+                               
+                               self[before] = function(fn) {
+                                       bind(listeners, before, fn);
+                                       return self;
+                               };                              
+                       }  
+                       
+                       self[evt] = function(fn) {
+                               bind(listeners, evt, fn);
+                               return self;
+                       };
+                       
+                       
+                       // set common clip event listeners to player level
+                       if (index == -1) {
+                               if (self[before]) {
+                                       player[before] = self[before];          
+                               }                               
+                               if (self[evt])  {
+                                       player[evt] = self[evt];                
+                               }
+                       }
+                       
+               });                       
+               
+               extend(this, {
+                       
+                        
+                       onCuepoint: function(points, fn) {
+                               
+                               // embedded cuepoints
+                               if (arguments.length == 1) {
+                                       cuepoints.embedded = [null, points];
+                                       return self;
+                               }
+                               
+                               if (typeof points == 'number') {
+                                       points = [points];      
+                               }
+                               
+                               var fnId = makeId();  
+                               cuepoints[fnId] = [points, fn]; 
+                               
+                               if (player.isLoaded()) {
+                                       player._api().fp_addCuepoints(points, index, fnId);     
+                               }  
+                               
+                               return self;
+                       },
+                       
+                       update: function(json) {
+                               extend(self, json);
+
+                               if (player.isLoaded()) {
+                                       player._api().fp_updateClip(json, index);       
+                               }
+                               var conf = player._config(); 
+                               var clip = (index == -1) ? conf.clip : conf.playlist[index];
+                               extend(clip, json, true);
+                       },
+                       
+                       
+                       // internal event for performing clip tasks. should be made private someday
+                       _fireEvent: function(evt, arg1, arg2, target) {                                 
+                               
+                               if (evt == 'onLoad') { 
+                                       each(cuepoints, function(key, val) {
+                                               player._api().fp_addCuepoints(val[0], index, key);              
+                                       }); 
+                                       return false;
+                               }                                       
+                               
+                               // target clip we are working against
+                               if (index != -1) {
+                                       target = self;  
+                               }
+                               
+                               if (evt == 'onCuepoint') {
+                                       var fn = cuepoints[arg1];
+                                       if (fn) {
+                                               return fn[1].call(player, target, arg2);
+                                       }
+                               }  
+       
+                               if (evt == 'onMetaData' || evt == 'onUpdate') {
+                                       
+                                       extend(target, arg1);                                   
+                                       
+                                       if (!target.duration) {
+                                               target.duration = arg1.metaData.duration;       
+                                       } else {
+                                               target.fullDuration = arg1.metaData.duration;   
+                                       }                                       
+                               }  
+                               
+                               var ret = true;
+                               each(listeners[evt], function() {
+                                       ret = this.call(player, target, arg1);          
+                               }); 
+                               return ret;                             
+                       }                       
+                       
+               });
+               
+               
+               // get cuepoints from config
+               if (json.onCuepoint) {
+                       self.onCuepoint.apply(self, json.onCuepoint);
+                       delete json.onCuepoint;
+               } 
+               
+               // get other events
+               each(json, function(key, val) {
+                       if (typeof val == 'function') {
+                               bind(listeners, key, val);
+                               delete json[key];       
+                       }
+               });
+
+               
+               // setup common clip event callbacks for Player object too (shortcuts)
+               if (index == -1) {
+                       player.onCuepoint = this.onCuepoint;    
+               }
+       
+       };
+
+//}}}
+
+
+// {{{ Plugin
+               
+       var Plugin = function(name, json, player, fn) {
+       
+               var listeners = {};
+               var self = this;   
+               var hasMethods = false;
+       
+               if (fn) {
+                       extend(listeners, fn);  
+               }   
+               
+               // custom callback functions in configuration
+               each(json, function(key, val) {
+                       if (typeof val == 'function') {
+                               listeners[key] = val;
+                               delete json[key];       
+                       }
+               });  
+               
+               // core plugin methods          
+               extend(this, {
+  
+                       animate: function(props, speed, fn) { 
+                               if (!props) {
+                                       return self;    
+                               }
+                               
+                               if (typeof speed == 'function') { 
+                                       fn = speed; 
+                                       speed = 500;
+                               }
+                               
+                               if (typeof props == 'string') {
+                                       var key = props;
+                                       props = {};
+                                       props[key] = speed;
+                                       speed = 500; 
+                               }
+                               
+                               if (fn) {
+                                       var fnId = makeId();
+                                       listeners[fnId] = fn;
+                               }
+               
+                               if (speed === undefined) { speed = 500; }
+                               json = player._api().fp_animate(name, props, speed, fnId);      
+                               return self;
+                       },
+                       
+                       css: function(props, val) {
+                               if (val !== undefined) {
+                                       var css = {};
+                                       css[props] = val;
+                                       props = css;                                    
+                               }
+                               json = player._api().fp_css(name, props);
+                               extend(self, json);
+                               return self;
+                       },
+                       
+                       show: function() {
+                               this.display = 'block';
+                               player._api().fp_showPlugin(name);
+                               return self;
+                       },
+                       
+                       hide: function() {
+                               this.display = 'none';
+                               player._api().fp_hidePlugin(name);
+                               return self;
+                       },
+                       
+                       toggle: function() {
+                               this.display = player._api().fp_togglePlugin(name);
+                               return self;
+                       },                      
+                       
+                       fadeTo: function(o, speed, fn) {
+                               
+                               if (typeof speed == 'function') { 
+                                       fn = speed; 
+                                       speed = 500;
+                               }
+                               
+                               if (fn) {
+                                       var fnId = makeId();
+                                       listeners[fnId] = fn;
+                               }                               
+                               this.display = player._api().fp_fadeTo(name, o, speed, fnId);
+                               this.opacity = o;
+                               return self;
+                       },
+                       
+                       fadeIn: function(speed, fn) { 
+                               return self.fadeTo(1, speed, fn);                               
+                       },
+       
+                       fadeOut: function(speed, fn) {
+                               return self.fadeTo(0, speed, fn);       
+                       },
+                       
+                       getName: function() {
+                               return name;    
+                       },
+                       
+                       
+                       // internal method not meant to be used by clients
+                _fireEvent: function(evt, arg) {
+
+                               
+                       // update plugins properties & methods
+                       if (evt == 'onUpdate') {
+                          var json = arg || player._api().fp_getPlugin(name); 
+                                       if (!json) { return;    }                                       
+                                       
+                          extend(self, json);
+                          delete self.methods;
+                                       
+                          if (!hasMethods) {
+                                 each(json.methods, function() {
+                                        var method = "" + this;           
+                                                       
+                                        self[method] = function() {
+                                               var a = [].slice.call(arguments);
+                                               var ret = player._api().fp_invoke(name, method, a); 
+                                               return ret == 'undefined' ? self : ret;
+                                        };
+                                 });
+                                 hasMethods = true;             
+                          }
+                       }
+                       
+                       // plugin callbacks
+                       var fn = listeners[evt];
+
+                               if (fn) {
+                                       
+                                       fn.call(self, arg);
+                                       
+                                       // "one-shot" callback
+                                       if (evt.substring(0, 1) == "_") {
+                                               delete listeners[evt];  
+                                       } 
+                       }                
+                }                                      
+                       
+               });
+
+       };
+
+
+//}}}
+
+
+function Player(wrapper, params, conf) {   
+               
+       // private variables (+ arguments)
+       var 
+               self = this, 
+               api = null, 
+               html, 
+               commonClip, 
+               playlist = [], 
+               plugins = {},
+               listeners = {},
+               playerId,
+               apiId,
+               activeIndex,
+               swfHeight;      
+
+  
+// {{{ public methods 
+       
+       extend(self, {
+                       
+               id: function() {
+                       return playerId;        
+               }, 
+               
+               isLoaded: function() {
+                       return (api !== null);  
+               },
+               
+               getParent: function() {
+                       return wrapper; 
+               },
+               
+               hide: function() {
+                       if (api) { api.style.height = "0px"; } 
+                       return self;
+               },
+
+               show: function() {
+                       if (api) { api.style.height = swfHeight + "px"; }
+                       return self;
+               }, 
+                                       
+               isHidden: function() {
+                       return api && parseInt(api.style.height, 10) === 0;
+               },
+               
+               
+               load: function(fn) { 
+                       
+                       if (!api && self._fireEvent("onBeforeLoad") !== false) {
+                               
+                               // unload all instances
+                               each(players, function()  {
+                                       this.unload();          
+                               });
+                               
+                               html = wrapper.innerHTML; 
+                               flashembed(wrapper, params, {config: conf});
+                               
+                               // function argument
+                               if (fn) {
+                                       fn.cached = true;
+                                       bind(listeners, "onLoad", fn);  
+                               }
+                       }
+                       
+                       return self;    
+               },
+               
+               unload: function() {  
+                       
+                if (api && html.replace(/\s/g, '') !== '' && !api.fp_isFullscreen() && 
+                       self._fireEvent("onBeforeUnload") !== false) { 
+                               api.fp_close();
+                               wrapper.innerHTML = html; 
+                               self._fireEvent("onUnload");
+                               api = null;
+                       }
+                       
+                       return self;
+               },
+
+               getClip: function(index) {
+                       if (index === undefined) {
+                               index = activeIndex;    
+                       }
+                       return playlist[index];
+               },
+               
+               
+               getCommonClip: function() {
+                       return commonClip;      
+               },              
+               
+               getPlaylist: function() {
+                       return playlist; 
+               },
+               
+         getPlugin: function(name) {  
+                var plugin = plugins[name];
+                
+                       // create plugin if nessessary
+                if (!plugin && self.isLoaded()) {
+                               var json = self._api().fp_getPlugin(name);
+                               if (json) {
+                                       plugin = new Plugin(name, json, self);
+                                       plugins[name] = plugin;                                                 
+                               } 
+                }              
+                return plugin; 
+         },
+               
+               getScreen: function() { 
+                       return self.getPlugin("screen");
+               }, 
+               
+               getControls: function() { 
+                       return self.getPlugin("controls");
+               }, 
+
+               getConfig: function() { 
+                       return clone(conf);
+               },
+               
+               getFlashParams: function() { 
+                       return params;
+               },              
+               
+               loadPlugin: function(name, url, props, fn) { 
+
+                       // properties not supplied                      
+                       if (typeof props == 'function') { 
+                               fn = props; 
+                               props = {};
+                       } 
+                       
+                       // if fn not given, make a fake id so that plugin's onUpdate get's fired
+                       var fnId = fn ? makeId() : "_"; 
+                       self._api().fp_loadPlugin(name, url, props, fnId); 
+                       
+                       // create new plugin
+                       var arg = {};
+                       arg[fnId] = fn;
+                       var p = new Plugin(name, null, self, arg);
+                       plugins[name] = p;
+                       return p;                       
+               },
+               
+               
+               getState: function() {
+                       return api ? api.fp_getState() : -1;
+               },
+               
+               // "lazy" play
+               play: function(clip) {
+                       
+                       function play() {
+                               if (clip !== undefined) {
+                                       self._api().fp_play(clip);
+                               } else {
+                                       self._api().fp_play();  
+                               }
+                       }
+                       
+                       if (api) {
+                               play();
+                               
+                       } else {
+                               self.load(function() { 
+                                       play();
+                               });
+                       }
+                       
+                       return self;
+               },
+               
+               getVersion: function() {
+                       var js = "flowplayer.js 3.0.0-rc2";
+                       if (api) {
+                               var ver = api.fp_getVersion();
+                               ver.push(js);
+                               return ver;
+                       }
+                       return js; 
+               },
+               
+               _api: function() {
+                       if (!api) {
+                               throw "Flowplayer " +self.id()+ " not loaded. Try moving your call to player's onLoad event";
+                       }
+                       return api;                             
+               },
+               
+               _config: function() {
+                       return conf;    
+               }
+               
+       }); 
+       
+       
+       // event handlers
+       each(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,Fullscreen*,FullscreenExit,Error").split(","),
+               function() {             
+                       var name = "on" + this;
+                       
+                       // before event
+                       if (name.indexOf("*") != -1) {
+                               name = name.substring(0, name.length -1); 
+                               var name2 = "onBefore" + name.substring(2);
+                               self[name2] = function(fn) {
+                                       bind(listeners, name2, fn);     
+                                       return self;
+                               };                                              
+                       }
+                       
+                       // normal event
+                       self[name] = function(fn) {
+                               bind(listeners, name, fn);      
+                               return self;
+                       };                       
+               }
+       ); 
+       
+       
+       // core API methods
+       each(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,reset").split(","),         
+               function() {             
+                       var name = this;
+                       
+                       self[name] = function(arg) {
+                               if (!api) { return self; }
+                               var ret = (arg === undefined) ? api["fp_" + name]() : api["fp_" + name](arg);
+                               return ret == 'undefined' ? self : ret;
+                       };                       
+               }
+       );              
+       
+//}}}
+
+
+// {{{ public method: _fireEvent
+               
+       self._fireEvent = function(evt, arg0, arg1, arg2) {             
+                               
+               if (conf.debug) {
+                       log(arguments);         
+               }                               
+               
+               // internal onLoad
+               if (evt == 'onLoad' && !api) {  
+                       
+                       api = api || el(apiId); 
+                       swfHeight = api.clientHeight;
+                       
+                       each(playlist, function() {
+                               this._fireEvent("onLoad");              
+                       });
+                       
+                       each(plugins, function(name, p) {
+                               p._fireEvent("onUpdate");               
+                       });
+                       
+                       
+                       commonClip._fireEvent("onLoad");  
+               }
+               
+         if (evt == 'onContextMenu') {
+                each(conf.contextMenu[arg0], function(key, fn)  {
+                       fn.call(self);
+                });
+                return;
+         }
+
+               if (evt == 'onPluginEvent') {
+                       var name = arg0.name || arg0;
+                       var p = plugins[name];
+                       if (p) {
+                               if (arg0.name) {
+                                       p._fireEvent("onUpdate", arg0);         
+                               }
+                               p._fireEvent(arg1);             
+                       }
+                       return;
+               }               
+
+               // onPlaylistReplace
+               if (evt == 'onPlaylistReplace') {
+                       playlist = [];
+                       var index = 0;
+                       each(arg0, function() {
+                               playlist.push(new Clip(this, index++));
+                       });             
+               }
+               
+               var ret = true;
+               
+               // clip event
+               if (arg0 === 0 || (arg0 && arg0 >= 0)) {
+                       
+                       activeIndex = arg0;
+                       var clip = playlist[arg0];                      
+                       
+                       if (!clip || clip._fireEvent(evt, arg1, arg2) !== false) {
+                               
+                               // clip argument is given for common clip, because it behaves as the target
+                               ret = commonClip._fireEvent(evt, arg1, arg2, clip);     
+                       }  
+               } 
+               
+               // player event 
+               var i = 0;
+               each(listeners[evt], function() {
+                       ret = this.call(self, arg0);            
+                       
+                       // remove cached entry
+                       if (this.cached) {
+                               listeners[evt].splice(i, 1);    
+                       }
+                       
+                       // break loop
+                       if (ret === false) { return false;       }
+                       i++;
+                       
+               }); 
+
+               return ret;
+       };
+
+//}}}
+
+// {{{ init
+       
+   function init() {
+               
+               if ($f(wrapper)) {
+                       return null;    
+               }               
+               
+               // register this player into global array of instances
+               players.push(self);  
+               
+               
+               // flashembed parameters
+               if (typeof params == 'string') {
+                       params = {src: params}; 
+               }       
+               
+               // playerId     
+               playerId = wrapper.id || "fp" + makeId();
+               apiId = params.id || playerId + "_api";                 
+               params.id = apiId;
+               conf.playerId = playerId;
+               
+               
+               // plain url is given as config
+               if (typeof conf == 'string') {
+                       conf = {clip:{url:conf}};       
+               } 
+               
+               // common clip is always there
+               conf.clip = conf.clip || {};
+               commonClip = new Clip(conf.clip, -1, self);  
+               
+               
+               // wrapper href as playlist
+               if (wrapper.getAttribute("href")) { 
+                       conf.playlist = [{url:wrapper.getAttribute("href", 2)}];                        
+               } 
+               
+               // playlist
+               conf.playlist = conf.playlist || [conf.clip]; 
+               
+               var index = 0;
+               each(conf.playlist, function() {
+
+                       var clip = this;
+                       
+                       // clip is an array, we don't allow that
+                       if (typeof clip == 'object' && clip.length)  {
+                               clip = "" + clip;       
+                       }
+                       
+                       if (!clip.url && typeof clip == 'string') {                             
+                               clip = {url: clip};                             
+                       } 
+                       
+                       // populate common clip properties to each clip
+                       extend(clip, conf.clip, true);          
+                       
+                       // modify configuration playlist
+                       conf.playlist[index] = clip;                    
+                       
+                       // populate playlist array
+                       clip = new Clip(clip, index, self);
+                       playlist.push(clip);                                            
+                       index++;                        
+               });
+                       
+               
+               // event listeners
+               each(conf, function(key, val) {
+                       if (typeof val == 'function') {
+                               bind(listeners, key, val);
+                               delete conf[key];       
+                       }
+               });              
+               
+               
+               // plugins
+               each(conf.plugins, function(name, val) {
+                       if (val) {
+                               plugins[name] = new Plugin(name, val, self);
+                       }
+               });
+               
+               
+               // setup controlbar plugin if not explicitly defined
+               if (!conf.plugins || conf.plugins.controls === undefined) {
+                       plugins.controls = new Plugin("controls", null, self);  
+               } 
+               
+               // Flowplayer uses black background by default
+               params.bgcolor = params.bgcolor || "#000000";
+               
+               
+               // setup default settings for express install
+               params.version = params.version || [9,0];               
+               params.expressInstall = 'http://www.flowplayer.org/swf/expressinstall.swf';
+               
+               
+               // click function
+               function doClick(e) {
+                       if (self._fireEvent("onBeforeClick") !== false) {
+                               self.load();            
+                       } 
+                       return stopEvent(e);                                    
+               }
+               
+               // defer loading upon click
+               html = wrapper.innerHTML;
+               if (html.replace(/\s/g, '') !== '') {    
+                       
+                       if (wrapper.addEventListener) {
+                               wrapper.addEventListener("click", doClick, false);      
+                               
+                       } else if (wrapper.attachEvent) {
+                               wrapper.attachEvent("onclick", doClick);        
+                       }
+                       
+               // player is loaded upon page load 
+               } else {
+                       
+                       // prevent default action from wrapper (safari problem) loaded
+                       if (wrapper.addEventListener) {
+                               wrapper.addEventListener("click", stopEvent, false);    
+                       }
+                       
+                       // load player
+                       self.load();
+               }
+               
+       }
+
+       // possibly defer initialization until DOM get's loaded
+       if (typeof wrapper == 'string') { 
+               flashembed.domReady(function() {
+                       var node = el(wrapper); 
+                       
+                       if (!node) {
+                               throw "Flowplayer cannot access element: " + wrapper;   
+                       } else {
+                               wrapper = node; 
+                               init();                                 
+                       } 
+               });
+               
+       // we have a DOM element so page is already loaded
+       } else {                
+               init();
+       }
+       
+       
+//}}}
+
+
+}
+
+
+// {{{ flowplayer() & statics 
+
+// container for player instances
+var players = [];
+
+
+// this object is returned when multiple player's are requested 
+function Iterator(arr) {
+       
+       this.length = arr.length;
+       
+       this.each = function(fn)  {
+               each(arr, fn);  
+       };
+       
+       this.size = function() {
+               return arr.length;      
+       };      
+}
+
+// these two variables are the only global variables
+window.flowplayer = window.$f = function() {
+       
+       var instance = null;
+       var arg = arguments[0]; 
+       
+       
+       // $f()
+       if (!arguments.length) {
+               each(players, function() {
+                       if (this.isLoaded())  {
+                               instance = this;        
+                               return false;
+                       }
+               });
+               
+               return instance || players[0];
+       } 
+       
+       if (arguments.length == 1) {
+               
+               // $f(index);
+               if (typeof arg == 'number') { 
+                       return players[arg];    
+       
+                       
+               // $f(wrapper || 'containerId' || '*');
+               } else {
+                       
+                       // $f("*");
+                       if (arg == '*') {
+                               return new Iterator(players);   
+                       }
+                       
+                       // $f(wrapper || 'containerId');
+                       each(players, function() {
+                               if (this.id() == arg.id || this.id() == arg || this.getParent() == arg)  {
+                                       instance = this;        
+                                       return false;
+                               }
+                       });
+                       
+                       return instance;                                        
+               }
+       }                       
+
+       // instance builder 
+       if (arguments.length > 1) {             
+
+               var swf = arguments[1];
+               var conf = (arguments.length == 3) ? arguments[2] : {};
+                                               
+               if (typeof arg == 'string') {
+                       
+                       // select arg by classname
+                       if (arg.indexOf(".") != -1) {
+                               var instances = [];
+                               
+                               each(select(arg), function() { 
+                                       instances.push(new Player(this, clone(swf), clone(conf)));              
+                               });     
+                               
+                               return new Iterator(instances);
+                               
+                       // select node by id
+                       } else {                
+                               var node = el(arg);
+                               return new Player(node !== null ? node : arg, swf, conf);       
+                       } 
+                       
+                       
+               // arg is a DOM element
+               } else if (arg) {
+                       return new Player(arg, swf, conf);                                              
+               }
+               
+       } 
+       
+       return null; 
+};
+       
+extend(window.$f, {
+
+       // called by Flash External Interface           
+       fireEvent: function(id, evt, a0, a1, a2) {              
+               var p = $f(id);         
+               return p ? p._fireEvent(evt, a0, a1, a2) : null;
+       },
+       
+       
+       // create plugins by modifying Player's prototype
+       addPlugin: function(name, fn) {
+               Player.prototype[name] = fn;
+               return $f;
+       },
+       
+       // utility methods for plugin developers
+       each: each,
+       
+       extend: extend
+       
+});
+       
+//}}}
+
+
+//{{{ jQuery support
+
+if (typeof jQuery == 'function') {
+       
+       jQuery.prototype.flowplayer = function(params, conf) {  
+               
+               // select instances
+               if (!arguments.length || typeof arguments[0] == 'number') {
+                       var arr = [];
+                       this.each(function()  {
+                               var p = $f(this);
+                               if (p) {
+                                       arr.push(p);    
+                               }
+                       });
+                       return arguments.length ? arr[arguments[0]] : new Iterator(arr);
+               }
+               
+               // create flowplayer instances
+               return this.each(function() { 
+                       $f(this, clone(params), conf ? clone(conf) : {});       
+               }); 
+               
+       };
+       
+}
+
+//}}}
+
+
+})();
+/** 
+ * flashembed 0.33. Adobe Flash embedding script
+ * 
+ * http://flowplayer.org/tools/flash-embed.html
+ *
+ * Copyright (c) 2008 Tero Piirainen (support@flowplayer.org)
+ *
+ * Released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * 
+ * >> Basically you can do anything you want but leave this header as is <<
+ *
+ * first version 0.01 - 03/11/2008 
+ * version 0.33 - Mon Nov 03 2008 15:37:15 GMT-0000 (GMT+00:00)
+ */
+(function() { 
+//{{{ utility functions 
+               
+var jQ = typeof jQuery == 'function';
+
+
+// from "Pro JavaScript techniques" by John Resig
+function isDomReady() {
+       if (domReady.done)  { return false; }
+       
+       var d = document;
+       if (d && d.getElementsByTagName && d.getElementById && d.body) {
+               clearInterval(domReady.timer);
+               domReady.timer = null;
+               
+               for (var i = 0; i < domReady.ready.length; i++) {
+                       domReady.ready[i].call();       
+               }
+               
+               domReady.ready = null;
+               domReady.done = true;
+       } 
+}
+
+// if jQuery is present, use it's more effective domReady method
+var domReady = jQ ? jQuery : function(f) {
+       
+       if (domReady.done) {
+               return f();     
+       }
+       
+       if (domReady.timer) {
+               domReady.ready.push(f); 
+               
+       } else {
+               domReady.ready = [f];
+               domReady.timer = setInterval(isDomReady, 13);
+       } 
+};     
+
+
+// override extend params function 
+function extend(to, from) {
+       if (from) {
+               for (key in from) {
+                       if (from.hasOwnProperty(key)) {
+                               to[key] = from[key];
+                       }
+               }
+       }
+}      
+
+
+function concatVars(vars) {            
+       var out = "";
+       
+       for (var key in vars) { 
+               if (vars[key]) {
+                       out += [key] + '=' + toString(vars[key]) + '&';
+               }
+       }                       
+       return out.substring(0, out.length -1);                         
+}  
+
+
+
+// JSON.toString() function
+function toString(obj) {
+
+       switch (typeOf(obj)){
+               case 'string':
+                       obj = obj.replace(new RegExp('(["\\\\])', 'g'), '\\$1');
+                       
+                       // flash does not handle %- characters well. transforms "50%" to "50pct" (a dirty hack, I admit)
+                       obj = obj.replace(/^\s?(\d+)%/, "$1pct");
+                       return '"' +obj+ '"';
+                       
+               case 'array':
+                       return '['+ map(obj, function(el) {
+                               return toString(el);
+                       }).join(',') +']'; 
+                       
+               case 'function':
+                       return '"function()"';
+                       
+               case 'object':
+                       var str = [];
+                       for (var prop in obj) {
+                               if (obj.hasOwnProperty(prop)) {
+                                       str.push('"'+prop+'":'+ toString(obj[prop]));
+                               }
+                       }
+                       return '{'+str.join(',')+'}';
+       }
+       
+       // replace ' --> "  and remove spaces
+       return String(obj).replace(/\s/g, " ").replace(/\'/g, "\"");
+}
+
+
+// private functions
+function typeOf(obj) {
+       if (obj === null || obj === undefined) { return false; }
+       var type = typeof obj;
+       return (type == 'object' && obj.push) ? 'array' : type;
+}
+
+
+// version 9 bugfix: (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
+if (window.attachEvent) {
+       window.attachEvent("onbeforeunload", function() {
+               __flash_unloadHandler = function() {};
+               __flash_savedUnloadHandler = function() {};
+       });
+}
+
+function map(arr, func) {
+       var newArr = []; 
+       for (var i in arr) {
+               if (arr.hasOwnProperty(i)) {
+                       newArr[i] = func(arr[i]);
+               }
+       }
+       return newArr;
+}
+       
+//}}}
+
+       
+window.flashembed = function(root, userParams, flashvars) {    
+       
+       
+//{{{ getHTML 
+               
+       function getHTML() {
+               
+               var html = "";
+               if (typeof flashvars == 'function') { flashvars = flashvars(); }
+               
+               
+               // sometimes ie fails to load flash if it's on cache
+               params.src += ((params.src.indexOf("?") != -1 ? "&" : "?") + Math.random());
+               
+               
+               // mozilla
+               if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) {  
+
+                       html = '<embed type="application/x-shockwave-flash" ';
+
+                       if (params.id) {
+                               extend(params, {name:params.id});
+                       }
+                       
+                       for (var key in params) { 
+                               if (params[key] !== null) { 
+                                       html += [key] + '="' +params[key]+ '"\n\t';
+                               }
+                       }
+
+                       if (flashvars) {
+                                html += 'flashvars=\'' + concatVars(flashvars) + '\'';
+                       }
+                       
+                       // thanks Tom Price (07/17/2008)
+                       html += '/>';
+                       
+               // ie
+               } else { 
+
+                       html = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ';
+                       html += 'width="' + params.width + '" height="' + params.height + '"'; 
+                       
+                       // force id for IE. otherwise embedded Flash object cannot be returned
+                       if (!params.id && document.all) {
+                               params.id = "_" + ("" + Math.random()).substring(5);
+                       } 
+                       
+                       if (params.id) {
+                               html += ' id="' + params.id + '"';
+                       }
+                       
+                       html += '>';  
+                       html += '\n\t<param name="movie" value="'+ params.src +'" />';
+                       
+                       params.id = params.src = params.width = params.height = null;
+                       
+                       for (var k in params) {
+                               if (params[k] !== null) {
+                                       html += '\n\t<param name="'+ k +'" value="'+ params[k] +'" />';
+                               }
+                       }
+                       
+                       if (flashvars) {
+                               html += '\n\t<param name="flashvars" value=\'' + concatVars(flashvars) + '\' />';
+                       }
+                        
+                       html += "</object>";
+                       if (debug) { 
+                               alert(html);
+                       }
+                       
+               }  
+
+               return html;
+       }
+
+       //}}}
+
+       
+//{{{ construction
+               
+       // setup params
+       var params = {
+               
+               // very common params
+               src: '#',
+               width: '100%',
+               height: '100%',         
+               
+               // flashembed specific options
+               version:null,
+               onFail:null,
+               expressInstall:null,  
+               debug: false,
+               
+               // flashembed defaults
+               // bgcolor: 'transparent',
+               allowfullscreen: true,
+               allowscriptaccess: 'always',
+               quality: 'high',
+               type: 'application/x-shockwave-flash',
+               pluginspage: 'http://www.adobe.com/go/getflashplayer'
+       };
+       
+       
+       if (typeof userParams == 'string') {
+               userParams = {src: userParams}; 
+       }
+       
+       extend(params, userParams);                      
+               
+       var version = flashembed.getVersion(); 
+       var required = params.version; 
+       var express = params.expressInstall;             
+       var debug = params.debug;
+
+       
+       if (typeof root == 'string') {
+               var el = document.getElementById(root);
+               if (el) {
+                       root = el;      
+               } else {
+                       domReady(function() {
+                               flashembed(root, userParams, flashvars);
+                       });
+                       return;                 
+               } 
+       }
+       
+       if (!root) { return; }
+
+       
+       // is supported 
+       if (!required || flashembed.isSupported(required)) {
+               params.onFail = params.version = params.expressInstall = params.debug = null;
+               
+               // root.innerHTML may cause broplems: http://domscripting.com/blog/display/99
+               // thanks to: Ryan Rud
+               // var tmp = document.createElement("extradiv");
+               // tmp.innerHTML = getHTML();
+               // root.appendChild(tmp);
+               
+               root.innerHTML = getHTML();
+               
+               // return our API                       
+               return root.firstChild;
+               
+       // custom fail event
+       } else if (params.onFail) {
+               var ret = params.onFail.call(params, flashembed.getVersion(), flashvars);
+               if (ret === true) { root.innerHTML = ret; }             
+               
+
+       // express install
+       } else if (required && express && flashembed.isSupported([6,65])) {
+               
+               extend(params, {src: express});
+               
+               flashvars = {
+                       MMredirectURL: location.href,
+                       MMplayerType: 'PlugIn',
+                       MMdoctitle: document.title
+               };
+               
+               root.innerHTML = getHTML();     
+               
+       // not supported
+       } else {
+
+               // minor bug fixed here 08.04.2008 (thanks JRodman)
+               
+               if (root.innerHTML.replace(/\s/g, '') !== '') {
+                       // custom content was supplied
+               
+               } else {
+                       root.innerHTML = 
+                               "<h2>Flash version " + required + " or greater is required</h2>" + 
+                               "<h3>" + 
+                                       (version[0] > 0 ? "Your version is " + version : "You have no flash plugin installed") +
+                               "</h3>" + 
+                               "<p>Download latest version from <a href='" + params.pluginspage + "'>here</a></p>";
+               }
+       }
+
+       return root;
+       
+//}}}
+       
+       
+};
+
+
+//{{{ static methods
+
+extend(window.flashembed, {
+
+       // arr[major, minor, fix]
+       getVersion: function() {
+       
+               var version = [0, 0];
+               
+               if (navigator.plugins && typeof navigator.plugins["Shockwave Flash"] == "object") {
+                       var _d = navigator.plugins["Shockwave Flash"].description;
+                       if (typeof _d != "undefined") {
+                               _d = _d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
+                               var _m = parseInt(_d.replace(/^(.*)\..*$/, "$1"), 10);
+                               var _r = /r/.test(_d) ? parseInt(_d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
+                               version = [_m, _r];
+                       }
+                       
+               } else if (window.ActiveXObject) {
+                       
+                       try { // avoid fp 6 crashes
+                               var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
+                               
+                       } catch(e) {
+                               try { 
+                                       _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
+                                       version = [6, 0];
+                                       _a.AllowScriptAccess = "always"; // throws if fp < 6.47 
+                                       
+                               } catch(ee) {
+                                       if (version[0] == 6) { return; }
+                               }
+                               try {
+                                       _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
+                               } catch(eee) {
+                               
+                               }
+                               
+                       }
+                       
+                       if (typeof _a == "object") {
+                               _d = _a.GetVariable("$version"); // bugs in fp 6.21 / 6.23
+                               if (typeof _d != "undefined") {
+                                       _d = _d.replace(/^\S+\s+(.*)$/, "$1").split(",");
+                                       version = [parseInt(_d[0], 10), parseInt(_d[2], 10)];
+                               }
+                       }
+               } 
+               
+               return version;
+       },
+       
+       isSupported: function(version) {
+               var now = flashembed.getVersion();
+               var ret = (now[0] > version[0]) || (now[0] == version[0] && now[1] >= version[1]);                      
+               return ret;
+       },
+       
+       domReady: domReady,
+       
+       // returns a String representation from JSON object 
+       toString: toString
+       
+});
+
+//}}}
+
+
+// setup jquery support
+if (jQ) {
+       
+       jQuery.prototype.flashembed = function(params, flashvars) { 
+               return this.each(function() { 
+                       flashembed(this, params, flashvars);
+               });
+       };
+
+}
+
+})();
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.min.js b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.min.js
new file mode 100644 (file)
index 0000000..a0fcabd
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * flowplayer.js 3.0.0-rc2. The Flowplayer API.
+ * 
+ * This file is part of Flowplayer, http://flowplayer.org
+ *
+ * Author: Tero Piirainen, <support@flowplayer.org>
+ * Copyright (c) 2008 Flowplayer Ltd
+ *
+ * Released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * 
+ * Version: 3.0.0-rc2 - Fri Nov 07 2008 16:50:52 GMT-0000 (GMT+00:00)
+ */
+(function(){function log(args){if(typeof opera=='object'){opera.postError("$f.fireEvent: "+args.join(" | "));}else if(typeof console=='object'){console.log("$f.fireEvent",[].slice.call(args));}}function clone(obj){if(!obj||typeof obj!='object'){return obj;}var temp=new obj.constructor();for(var key in obj){if(obj.hasOwnProperty(key)){temp[key]=clone(obj[key]);}}return temp;}function each(obj,fn){if(!obj){return;}var name,i=0,length=obj.length;if(length===undefined){for(name in obj){if(fn.call(obj[name],name,obj[name])===false){break;}}}else{for(var value=obj[0];i<length&&fn.call(value,i,value)!==false;value=obj[++i]){}}return obj;}function el(id){return document.getElementById(id);}function extend(to,from,skipFuncs){if(to&&from){each(from,function(name,value){if(!skipFuncs||typeof value!='function'){to[name]=value;}});}}function select(query){var index=query.indexOf(".");if(index!=-1){var tag=query.substring(0,index)||"*";var klass=query.substring(index+1,query.length);var els=[];each(document.getElementsByTagName(tag),function(){if(this.className&&this.className.indexOf(klass)!=-1){els.push(this);}});return els;}}function stopEvent(e){e=e||window.event;if(e.preventDefault){e.stopPropagation();e.preventDefault();}else{e.returnValue=false;e.cancelBubble=true;}return false;}function bind(to,evt,fn){to[evt]=to[evt]||[];to[evt].push(fn);}function makeId(){return"_"+(""+Math.random()).substring(2,10);}var Clip=function(json,index,player){var self=this;var cuepoints={};var listeners={};this.index=index;if(typeof json=='string'){json={url:json};}extend(this,json,true);each(("Start*,MetaData,Pause*,Resume*,Seek*,Stop*,Finish,LastSecond,Update,BufferFull,BufferEmpty").split(","),function(){var evt="on"+this;if(evt.indexOf("*")!=-1){evt=evt.substring(0,evt.length-1);var before="onBefore"+evt.substring(2);self[before]=function(fn){bind(listeners,before,fn);return self;};}self[evt]=function(fn){bind(listeners,evt,fn);return self;};if(index==-1){if(self[before]){player[before]=self[before];}if(self[evt]){player[evt]=self[evt];}}});extend(this,{onCuepoint:function(points,fn){if(arguments.length==1){cuepoints.embedded=[null,points];return self;}if(typeof points=='number'){points=[points];}var fnId=makeId();cuepoints[fnId]=[points,fn];if(player.isLoaded()){player._api().fp_addCuepoints(points,index,fnId);}return self;},update:function(json){extend(self,json);if(player.isLoaded()){player._api().fp_updateClip(json,index);}var conf=player._config();var clip=(index==-1)?conf.clip:conf.playlist[index];extend(clip,json,true);},_fireEvent:function(evt,arg1,arg2,target){if(evt=='onLoad'){each(cuepoints,function(key,val){player._api().fp_addCuepoints(val[0],index,key);});return false;}if(index!=-1){target=self;}if(evt=='onCuepoint'){var fn=cuepoints[arg1];if(fn){return fn[1].call(player,target,arg2);}}if(evt=='onMetaData'||evt=='onUpdate'){extend(target,arg1);if(!target.duration){target.duration=arg1.metaData.duration;}else{target.fullDuration=arg1.metaData.duration;}}var ret=true;each(listeners[evt],function(){ret=this.call(player,target,arg1);});return ret;}});if(json.onCuepoint){self.onCuepoint.apply(self,json.onCuepoint);delete json.onCuepoint;}each(json,function(key,val){if(typeof val=='function'){bind(listeners,key,val);delete json[key];}});if(index==-1){player.onCuepoint=this.onCuepoint;}};var Plugin=function(name,json,player,fn){var listeners={};var self=this;var hasMethods=false;if(fn){extend(listeners,fn);}each(json,function(key,val){if(typeof val=='function'){listeners[key]=val;delete json[key];}});extend(this,{animate:function(props,speed,fn){if(!props){return self;}if(typeof speed=='function'){fn=speed;speed=500;}if(typeof props=='string'){var key=props;props={};props[key]=speed;speed=500;}if(fn){var fnId=makeId();listeners[fnId]=fn;}if(speed===undefined){speed=500;}json=player._api().fp_animate(name,props,speed,fnId);return self;},css:function(props,val){if(val!==undefined){var css={};css[props]=val;props=css;}json=player._api().fp_css(name,props);extend(self,json);return self;},show:function(){this.display='block';player._api().fp_showPlugin(name);return self;},hide:function(){this.display='none';player._api().fp_hidePlugin(name);return self;},toggle:function(){this.display=player._api().fp_togglePlugin(name);return self;},fadeTo:function(o,speed,fn){if(typeof speed=='function'){fn=speed;speed=500;}if(fn){var fnId=makeId();listeners[fnId]=fn;}this.display=player._api().fp_fadeTo(name,o,speed,fnId);this.opacity=o;return self;},fadeIn:function(speed,fn){return self.fadeTo(1,speed,fn);},fadeOut:function(speed,fn){return self.fadeTo(0,speed,fn);},getName:function(){return name;},_fireEvent:function(evt,arg){if(evt=='onUpdate'){var json=arg||player._api().fp_getPlugin(name);if(!json){return;}extend(self,json);delete self.methods;if(!hasMethods){each(json.methods,function(){var method=""+this;self[method]=function(){var a=[].slice.call(arguments);var ret=player._api().fp_invoke(name,method,a);return ret=='undefined'?self:ret;};});hasMethods=true;}}var fn=listeners[evt];if(fn){fn.call(self,arg);if(evt.substring(0,1)=="_"){delete listeners[evt];}}}});};function Player(wrapper,params,conf){var
+self=this,api=null,html,commonClip,playlist=[],plugins={},listeners={},playerId,apiId,activeIndex,swfHeight;extend(self,{id:function(){return playerId;},isLoaded:function(){return(api!==null);},getParent:function(){return wrapper;},hide:function(){if(api){api.style.height="0px";}return self;},show:function(){if(api){api.style.height=swfHeight+"px";}return self;},isHidden:function(){return api&&parseInt(api.style.height,10)===0;},load:function(fn){if(!api&&self._fireEvent("onBeforeLoad")!==false){each(players,function(){this.unload();});html=wrapper.innerHTML;flashembed(wrapper,params,{config:conf});if(fn){fn.cached=true;bind(listeners,"onLoad",fn);}}return self;},unload:function(){if(api&&html.replace(/\s/g,'')!==''&&!api.fp_isFullscreen()&&self._fireEvent("onBeforeUnload")!==false){api.fp_close();wrapper.innerHTML=html;self._fireEvent("onUnload");api=null;}return self;},getClip:function(index){if(index===undefined){index=activeIndex;}return playlist[index];},getCommonClip:function(){return commonClip;},getPlaylist:function(){return playlist;},getPlugin:function(name){var plugin=plugins[name];if(!plugin&&self.isLoaded()){var json=self._api().fp_getPlugin(name);if(json){plugin=new Plugin(name,json,self);plugins[name]=plugin;}}return plugin;},getScreen:function(){return self.getPlugin("screen");},getControls:function(){return self.getPlugin("controls");},getConfig:function(){return clone(conf);},getFlashParams:function(){return params;},loadPlugin:function(name,url,props,fn){if(typeof props=='function'){fn=props;props={};}var fnId=fn?makeId():"_";self._api().fp_loadPlugin(name,url,props,fnId);var arg={};arg[fnId]=fn;var p=new Plugin(name,null,self,arg);plugins[name]=p;return p;},getState:function(){return api?api.fp_getState():-1;},play:function(clip){function play(){if(clip!==undefined){self._api().fp_play(clip);}else{self._api().fp_play();}}if(api){play();}else{self.load(function(){play();});}return self;},getVersion:function(){var js="flowplayer.js 3.0.0-rc2";if(api){var ver=api.fp_getVersion();ver.push(js);return ver;}return js;},_api:function(){if(!api){throw"Flowplayer "+self.id()+" not loaded. Try moving your call to player's onLoad event";}return api;},_config:function(){return conf;}});each(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,Fullscreen*,FullscreenExit,Error").split(","),function(){var name="on"+this;if(name.indexOf("*")!=-1){name=name.substring(0,name.length-1);var name2="onBefore"+name.substring(2);self[name2]=function(fn){bind(listeners,name2,fn);return self;};}self[name]=function(fn){bind(listeners,name,fn);return self;};});each(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,reset").split(","),function(){var name=this;self[name]=function(arg){if(!api){return self;}var ret=(arg===undefined)?api["fp_"+name]():api["fp_"+name](arg);return ret=='undefined'?self:ret;};});self._fireEvent=function(evt,arg0,arg1,arg2){if(conf.debug){log(arguments);}if(evt=='onLoad'&&!api){api=api||el(apiId);swfHeight=api.clientHeight;each(playlist,function(){this._fireEvent("onLoad");});each(plugins,function(name,p){p._fireEvent("onUpdate");});commonClip._fireEvent("onLoad");}if(evt=='onContextMenu'){each(conf.contextMenu[arg0],function(key,fn){fn.call(self);});return;}if(evt=='onPluginEvent'){var name=arg0.name||arg0;var p=plugins[name];if(p){if(arg0.name){p._fireEvent("onUpdate",arg0);}p._fireEvent(arg1);}return;}if(evt=='onPlaylistReplace'){playlist=[];var index=0;each(arg0,function(){playlist.push(new Clip(this,index++));});}var ret=true;if(arg0===0||(arg0&&arg0>=0)){activeIndex=arg0;var clip=playlist[arg0];if(!clip||clip._fireEvent(evt,arg1,arg2)!==false){ret=commonClip._fireEvent(evt,arg1,arg2,clip);}}var i=0;each(listeners[evt],function(){ret=this.call(self,arg0);if(this.cached){listeners[evt].splice(i,1);}if(ret===false){return false;}i++;});return ret;};function init(){if($f(wrapper)){return null;}players.push(self);if(typeof params=='string'){params={src:params};}playerId=wrapper.id||"fp"+makeId();apiId=params.id||playerId+"_api";params.id=apiId;conf.playerId=playerId;if(typeof conf=='string'){conf={clip:{url:conf}};}conf.clip=conf.clip||{};commonClip=new Clip(conf.clip,-1,self);if(wrapper.getAttribute("href")){conf.playlist=[{url:wrapper.getAttribute("href",2)}];}conf.playlist=conf.playlist||[conf.clip];var index=0;each(conf.playlist,function(){var clip=this;if(typeof clip=='object'&&clip.length){clip=""+clip;}if(!clip.url&&typeof clip=='string'){clip={url:clip};}extend(clip,conf.clip,true);conf.playlist[index]=clip;clip=new Clip(clip,index,self);playlist.push(clip);index++;});each(conf,function(key,val){if(typeof val=='function'){bind(listeners,key,val);delete conf[key];}});each(conf.plugins,function(name,val){if(val){plugins[name]=new Plugin(name,val,self);}});if(!conf.plugins||conf.plugins.controls===undefined){plugins.controls=new Plugin("controls",null,self);}params.bgcolor=params.bgcolor||"#000000";params.version=params.version||[9,0];params.expressInstall='http://www.flowplayer.org/swf/expressinstall.swf';function doClick(e){if(self._fireEvent("onBeforeClick")!==false){self.load();}return stopEvent(e);}html=wrapper.innerHTML;if(html.replace(/\s/g,'')!==''){if(wrapper.addEventListener){wrapper.addEventListener("click",doClick,false);}else if(wrapper.attachEvent){wrapper.attachEvent("onclick",doClick);}}else{if(wrapper.addEventListener){wrapper.addEventListener("click",stopEvent,false);}self.load();}}if(typeof wrapper=='string'){flashembed.domReady(function(){var node=el(wrapper);if(!node){throw"Flowplayer cannot access element: "+wrapper;}else{wrapper=node;init();}});}else{init();}}var players=[];function Iterator(arr){this.length=arr.length;this.each=function(fn){each(arr,fn);};this.size=function(){return arr.length;};}window.flowplayer=window.$f=function(){var instance=null;var arg=arguments[0];if(!arguments.length){each(players,function(){if(this.isLoaded()){instance=this;return false;}});return instance||players[0];}if(arguments.length==1){if(typeof arg=='number'){return players[arg];}else{if(arg=='*'){return new Iterator(players);}each(players,function(){if(this.id()==arg.id||this.id()==arg||this.getParent()==arg){instance=this;return false;}});return instance;}}if(arguments.length>1){var swf=arguments[1];var conf=(arguments.length==3)?arguments[2]:{};if(typeof arg=='string'){if(arg.indexOf(".")!=-1){var instances=[];each(select(arg),function(){instances.push(new Player(this,clone(swf),clone(conf)));});return new Iterator(instances);}else{var node=el(arg);return new Player(node!==null?node:arg,swf,conf);}}else if(arg){return new Player(arg,swf,conf);}}return null;};extend(window.$f,{fireEvent:function(id,evt,a0,a1,a2){var p=$f(id);return p?p._fireEvent(evt,a0,a1,a2):null;},addPlugin:function(name,fn){Player.prototype[name]=fn;return $f;},each:each,extend:extend});if(typeof jQuery=='function'){jQuery.prototype.flowplayer=function(params,conf){if(!arguments.length||typeof arguments[0]=='number'){var arr=[];this.each(function(){var p=$f(this);if(p){arr.push(p);}});return arguments.length?arr[arguments[0]]:new Iterator(arr);}return this.each(function(){$f(this,clone(params),conf?clone(conf):{});});};}})();(function(){var jQ=typeof jQuery=='function';function isDomReady(){if(domReady.done){return false;}var d=document;if(d&&d.getElementsByTagName&&d.getElementById&&d.body){clearInterval(domReady.timer);domReady.timer=null;for(var i=0;i<domReady.ready.length;i++){domReady.ready[i].call();}domReady.ready=null;domReady.done=true;}}var domReady=jQ?jQuery:function(f){if(domReady.done){return f();}if(domReady.timer){domReady.ready.push(f);}else{domReady.ready=[f];domReady.timer=setInterval(isDomReady,13);}};function extend(to,from){if(from){for(key in from){if(from.hasOwnProperty(key)){to[key]=from[key];}}}}function concatVars(vars){var out="";for(var key in vars){if(vars[key]){out+=[key]+'='+toString(vars[key])+'&';}}return out.substring(0,out.length-1);}function toString(obj){switch(typeOf(obj)){case'string':obj=obj.replace(new RegExp('(["\\\\])','g'),'\\$1');obj=obj.replace(/^\s?(\d+)%/,"$1pct");return'"'+obj+'"';case'array':return'['+map(obj,function(el){return toString(el);}).join(',')+']';case'function':return'"function()"';case'object':var str=[];for(var prop in obj){if(obj.hasOwnProperty(prop)){str.push('"'+prop+'":'+toString(obj[prop]));}}return'{'+str.join(',')+'}';}return String(obj).replace(/\s/g," ").replace(/\'/g,"\"");}function typeOf(obj){if(obj===null||obj===undefined){return false;}var type=typeof obj;return(type=='object'&&obj.push)?'array':type;}if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};});}function map(arr,func){var newArr=[];for(var i in arr){if(arr.hasOwnProperty(i)){newArr[i]=func(arr[i]);}}return newArr;}window.flashembed=function(root,userParams,flashvars){function getHTML(){var html="";if(typeof flashvars=='function'){flashvars=flashvars();}params.src+=((params.src.indexOf("?")!=-1?"&":"?")+Math.random());if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){html='<embed type="application/x-shockwave-flash" ';if(params.id){extend(params,{name:params.id});}for(var key in params){if(params[key]!==null){html+=[key]+'="'+params[key]+'"\n\t';}}if(flashvars){html+='flashvars=\''+concatVars(flashvars)+'\'';}html+='/>';}else{html='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ';html+='width="'+params.width+'" height="'+params.height+'"';if(!params.id&&document.all){params.id="_"+(""+Math.random()).substring(5);}if(params.id){html+=' id="'+params.id+'"';}html+='>';html+='\n\t<param name="movie" value="'+params.src+'" />';params.id=params.src=params.width=params.height=null;for(var k in params){if(params[k]!==null){html+='\n\t<param name="'+k+'" value="'+params[k]+'" />';}}if(flashvars){html+='\n\t<param name="flashvars" value=\''+concatVars(flashvars)+'\' />';}html+="</object>";if(debug){alert(html);}}return html;}var params={src:'#',width:'100%',height:'100%',version:null,onFail:null,expressInstall:null,debug:false,allowfullscreen:true,allowscriptaccess:'always',quality:'high',type:'application/x-shockwave-flash',pluginspage:'http://www.adobe.com/go/getflashplayer'};if(typeof userParams=='string'){userParams={src:userParams};}extend(params,userParams);var version=flashembed.getVersion();var required=params.version;var express=params.expressInstall;var debug=params.debug;if(typeof root=='string'){var el=document.getElementById(root);if(el){root=el;}else{domReady(function(){flashembed(root,userParams,flashvars);});return;}}if(!root){return;}if(!required||flashembed.isSupported(required)){params.onFail=params.version=params.expressInstall=params.debug=null;root.innerHTML=getHTML();return root.firstChild;}else if(params.onFail){var ret=params.onFail.call(params,flashembed.getVersion(),flashvars);if(ret===true){root.innerHTML=ret;}}else if(required&&express&&flashembed.isSupported([6,65])){extend(params,{src:express});flashvars={MMredirectURL:location.href,MMplayerType:'PlugIn',MMdoctitle:document.title};root.innerHTML=getHTML();}else{if(root.innerHTML.replace(/\s/g,'')!==''){}else{root.innerHTML="<h2>Flash version "+required+" or greater is required</h2>"+"<h3>"+(version[0]>0?"Your version is "+version:"You have no flash plugin installed")+"</h3>"+"<p>Download latest version from <a href='"+params.pluginspage+"'>here</a></p>";}}return root;};extend(window.flashembed,{getVersion:function(){var version=[0,0];if(navigator.plugins&&typeof navigator.plugins["Shockwave Flash"]=="object"){var _d=navigator.plugins["Shockwave Flash"].description;if(typeof _d!="undefined"){_d=_d.replace(/^.*\s+(\S+\s+\S+$)/,"$1");var _m=parseInt(_d.replace(/^(.*)\..*$/,"$1"),10);var _r=/r/.test(_d)?parseInt(_d.replace(/^.*r(.*)$/,"$1"),10):0;version=[_m,_r];}}else if(window.ActiveXObject){try{var _a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{_a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");version=[6,0];_a.AllowScriptAccess="always";}catch(ee){if(version[0]==6){return;}}try{_a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(eee){}}if(typeof _a=="object"){_d=_a.GetVariable("$version");if(typeof _d!="undefined"){_d=_d.replace(/^\S+\s+(.*)$/,"$1").split(",");version=[parseInt(_d[0],10),parseInt(_d[2],10)];}}}return version;},isSupported:function(version){var now=flashembed.getVersion();var ret=(now[0]>version[0])||(now[0]==version[0]&&now[1]>=version[1]);return ret;},domReady:domReady,toString:toString});if(jQ){jQuery.prototype.flashembed=function(params,flashvars){return this.each(function(){flashembed(this,params,flashvars);});};}})();
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.swf
new file mode 100644 (file)
index 0000000..70f6a17
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc2.swf differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc4.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc4.swf
new file mode 100644 (file)
index 0000000..9c7b3b4
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.0-rc4.swf differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.1.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.1.swf
new file mode 100644 (file)
index 0000000..fcb9cf5
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer-3.0.1.swf differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta5.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta5.swf
new file mode 100644 (file)
index 0000000..c5bec77
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta5.swf differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta7.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta7.swf
new file mode 100644 (file)
index 0000000..703a96a
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.0-beta7.swf differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.1.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.1.swf
new file mode 100644 (file)
index 0000000..9f08f4d
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.controls-3.0.1.swf differ
diff --git a/js2/mwEmbed/binPlayers/flowplayer/flowplayer.pseudostreaming-3.0.0-beta3.swf b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.pseudostreaming-3.0.0-beta3.swf
new file mode 100644 (file)
index 0000000..65a5605
Binary files /dev/null and b/js2/mwEmbed/binPlayers/flowplayer/flowplayer.pseudostreaming-3.0.0-beta3.swf differ
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/LICENSE.txt b/js2/mwEmbed/binPlayers/omtk-fx/LICENSE.txt
new file mode 100644 (file)
index 0000000..6b1065b
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/README.txt b/js2/mwEmbed/binPlayers/omtk-fx/README.txt
new file mode 100644 (file)
index 0000000..2c421f2
--- /dev/null
@@ -0,0 +1,17 @@
+\r
+ *** PRELIMINARY SOFTWARE ***\r
\r
+Please note that this is a prerelease of the OMTK Flash library. No\r
+quality of this software can be guaranteed.\r
+\r
+\r
+ *** haXe notes ***\r
\r
+You need at least haXe 2.01 (with support for the new Flash 10 types)\r
+to compile the haXe source.\r
+\r
+ *** Flash notes ***\r
\r
+I am not able to create a .SWC library from the haXe .SWF file. It's\r
+therefore dynamically linked at runtime and hxmdct.swf must be placed\r
+in the same directory as the "real" Flash movie.\r
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/hxmdct.swf b/js2/mwEmbed/binPlayers/omtk-fx/hxmdct.swf
new file mode 100644 (file)
index 0000000..d314dee
Binary files /dev/null and b/js2/mwEmbed/binPlayers/omtk-fx/hxmdct.swf differ
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/omtkp.swf b/js2/mwEmbed/binPlayers/omtk-fx/omtkp.swf
new file mode 100644 (file)
index 0000000..4ec9bfa
Binary files /dev/null and b/js2/mwEmbed/binPlayers/omtk-fx/omtkp.swf differ
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/Player.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/Player.as
new file mode 100644 (file)
index 0000000..3650517
--- /dev/null
@@ -0,0 +1,106 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package {\r
+\r
+       import org.omtk.vorbis.VorbisSound;\r
+       \r
+       import flash.display.Shape;\r
+       import flash.display.Sprite;\r
+       import flash.display.StageAlign;\r
+       import flash.display.StageQuality;\r
+       import flash.display.StageScaleMode;\r
+       import flash.net.*;\r
+       import flash.events.Event;\r
+       import flash.text.TextField;\r
+       import flash.utils.ByteArray;\r
+       import flash.utils.Endian;\r
+       import flash.utils.getTimer;\r
+       import flash.utils.setTimeout;\r
+       import flash.utils.setInterval;\r
+       import flash.external.ExternalInterface;\r
+       \r
+       [ SWF( backgroundColor = '#ffffff', width = '1', height = '1' ) ]\r
+       \r
+       public class Player extends Sprite {\r
+       \r
+               private var sound: VorbisSound;\r
+               private var initialized: Boolean = false;\r
+               \r
+               public function Player() {\r
+                       if(stage != null) {\r
+                               stage.frameRate = 20;\r
+                       }\r
+                       \r
+                       setTimeout(registerJSCallbacks, 100);\r
+                       initialized = true;\r
+               }\r
+\r
+               private function registerJSCallbacks(): void {\r
+                       if (ExternalInterface.available) {\r
+                               ExternalInterface.addCallback("play", playJS);\r
+                               ExternalInterface.addCallback("getMetaData", getMetaDataJS);\r
+                               ExternalInterface.addCallback("getPosition", getPositionJS);            \r
+                       }\r
+               }\r
+\r
+               public function playJS(url: String): void {\r
+                       if(sound != null) {\r
+                               sound.stop();\r
+                       }\r
+                       sound = new VorbisSound(new URLRequest(url));\r
+                       sound.addEventListener(Event.COMPLETE, complete);       \r
+                       sound.addEventListener(VorbisSound.METADATA_UPDATE, metadataUpdate);\r
+                       sound.play();\r
+               }\r
+\r
+               public function getMetaDataJS(key: String): String {\r
+                       if(sound == null) {\r
+                               return null;\r
+                       }\r
+                       else {\r
+                               return sound.getMetaData(key);\r
+                       }\r
+               }\r
+               \r
+               public function getPositionJS(): int {\r
+                       if(sound == null) {\r
+                               return -1;\r
+                       }\r
+                       else {\r
+                               return sound.position;\r
+                       }\r
+               }\r
+               \r
+               private function complete(event: Event):void {\r
+                       trace("complete");\r
+                       if(ExternalInterface.available) {\r
+                               ExternalInterface.call("OMTK_P_complete");\r
+                       }\r
+               }\r
+\r
+               private function metadataUpdate(event: Event):void {\r
+                       trace("metadata update: " + sound.getMetaData("TITLE"));\r
+                       if(ExternalInterface.available) {\r
+                               ExternalInterface.call("OMTK_P_metadataUpdate");\r
+                       }\r
+               }\r
+\r
+       }\r
+       \r
+}\r
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/EndOfOggStreamError.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/EndOfOggStreamError.as
new file mode 100644 (file)
index 0000000..3c02799
--- /dev/null
@@ -0,0 +1,29 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.ogg {\r
+\r
+       public class EndOfOggStreamError extends Error {\r
+       \r
+               public function EndOfOggStreamError(message:String = null) {\r
+                       super(message);\r
+               }\r
+       \r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/LogicalOggStream.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/LogicalOggStream.as
new file mode 100644 (file)
index 0000000..a568559
--- /dev/null
@@ -0,0 +1,72 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.ogg {\r
+\r
+       import org.omtk.util.BitByteArray;      \r
+       import flash.utils.Endian;\r
+\r
+       public class LogicalOggStream {\r
+       \r
+               private var source:UncachedUrlStream;\r
+               \r
+               private var pageIndex:int;\r
+               private var currentPage:OggPage;\r
+               private var currentSegmentIndex:int;\r
+               \r
+               public function LogicalOggStream(source:UncachedUrlStream) {\r
+                       this.source = source;\r
+               }\r
+               \r
+               public function getNextOggPacket(): OggPacket {\r
+               \r
+                       var res:BitByteArray = new BitByteArray();\r
+\r
+                       var segmentLength:int = 0;\r
+\r
+                       if(currentPage == null) {\r
+                               currentPage = source.getNextOggPage();\r
+                       }\r
+\r
+                       do {\r
+                               if(currentSegmentIndex >= currentPage.segmentOffsets.length) {\r
+                       currentSegmentIndex=0;\r
+\r
+                       if(currentPage.eos) {\r
+                               throw new EndOfOggStreamError("End of OGG stream");\r
+                       }\r
+                       \r
+                               currentPage = source.getNextOggPage();\r
+                               }\r
+\r
+                               segmentLength = currentPage.segmentLengths[currentSegmentIndex];\r
+                               res.writeBytes(currentPage.data, currentPage.segmentOffsets[currentSegmentIndex], segmentLength);\r
+                               currentSegmentIndex++;\r
+                       }\r
+                       while(segmentLength==255);\r
+                       \r
+                       res.position = 0;\r
+                       \r
+                       var lastPacket: Boolean = currentPage.eos && currentSegmentIndex == currentPage.segmentOffsets.length;\r
+                       var lastGranulePosition: int = currentPage.absoluteGranulePosition;\r
+                       \r
+                       return new OggPacket(res, lastPacket, lastGranulePosition);\r
+               }\r
+       \r
+       }\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPacket.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPacket.as
new file mode 100644 (file)
index 0000000..95b53f5
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.ogg {\r
+\r
+       import org.omtk.util.BitByteArray;\r
+\r
+       public class OggPacket {\r
+       \r
+               private var _data: BitByteArray;\r
+               private var _lastPacket: Boolean;\r
+               private var _lastGranulePosition: int;\r
+               \r
+               public function OggPacket(data: BitByteArray, lastPacket: Boolean, lastGranulePosition: int) {\r
+                       _data = data;\r
+                       _lastPacket = lastPacket;\r
+                       _lastGranulePosition = lastGranulePosition;\r
+               }\r
+       \r
+               public function get data(): BitByteArray {\r
+                       return _data;\r
+               }\r
+               \r
+               public function get lastPacket(): Boolean {\r
+                       return _lastPacket;\r
+               }\r
+               \r
+               public function get lastGranulePosition(): int {\r
+                       return _lastGranulePosition;\r
+               }\r
+       \r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPage.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPage.as
new file mode 100644 (file)
index 0000000..54f6387
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.ogg {\r
+\r
+       import flash.net.*;\r
+       import flash.utils.ByteArray;\r
+       \r
+       public class OggPage {\r
+\r
+               private var _version:int;\r
+               private var _continued:Boolean;\r
+               private var _bos:Boolean;\r
+               private var _eos:Boolean;\r
+               private var _absoluteGranulePosition:int;\r
+               private var _streamSerialNumber:int;\r
+               private var _pageSequenceNumber:int;\r
+               private var _pageCheckSum:int;\r
+               private var _segmentOffsets:Array;\r
+               private var _segmentLengths:Array;\r
+               private var _totalLength:int;\r
+               private var _data:ByteArray;\r
+                       \r
+               public function OggPage(stream:URLStream) {\r
+\r
+                       var capture:int = stream.readInt();\r
+                       if(capture != 0x5367674f) {\r
+                               throw new Error("Ogg page does not start with 'OggS': "+capture);\r
+                       }\r
+               \r
+                       _version = stream.readByte()&0xff;\r
+                       var tmp:int = stream.readByte();\r
+               \r
+                       _continued = (tmp&1)!=0;;\r
+                       _bos = (tmp&2)!=0;\r
+                       _eos = (tmp&4)!=0;\r
+                       \r
+                       // absoluteGranulePosition is really 64 bits\r
+                       _absoluteGranulePosition = stream.readUnsignedInt();\r
+                       stream.readUnsignedInt(); // last 32 bits of _absoluteGranulePosition\r
+                       \r
+                       _streamSerialNumber = stream.readUnsignedInt();\r
+                       _pageSequenceNumber = stream.readUnsignedInt();\r
+                       _pageCheckSum = stream.readUnsignedInt();\r
+                       \r
+                       //trace("_pageSequenceNumber: " + _pageSequenceNumber);\r
+                       \r
+                       var pageSegments:int = stream.readUnsignedByte();\r
+                       \r
+                       //stream.waitFor(pageSegments);\r
+                       \r
+                       _segmentOffsets = [];\r
+                       _segmentLengths = [];\r
+                       _data = new ByteArray();\r
+                       \r
+                       var totalLength:int;\r
+                       \r
+                       var i:int;\r
+                       var l:int;\r
+                       \r
+                       for( i= 0 ; i < pageSegments ; i++ ) {\r
+                               l = stream.readUnsignedByte();\r
+                               _segmentLengths.push( l );\r
+                               _segmentOffsets.push( totalLength );\r
+                               totalLength += l;\r
+                       }       \r
+                       \r
+                       stream.readBytes(_data, 0, totalLength);\r
+               }\r
+       \r
+               public function get absoluteGranulePosition():int {\r
+                       return _absoluteGranulePosition;\r
+               }\r
+\r
+               public function get segmentOffsets():Array {\r
+                       return _segmentOffsets;\r
+               }\r
+               \r
+               public function get segmentLengths():Array {\r
+                       return _segmentLengths;\r
+               }\r
+               \r
+               public function get data():ByteArray {\r
+                       return _data;\r
+               }\r
+\r
+               public function get eos():Boolean {\r
+                       return _eos;\r
+               }\r
+               \r
+               public function get bos():Boolean {\r
+                       return _bos;\r
+               }\r
+               \r
+               public function get continued():Boolean {\r
+                       return _continued;\r
+               }\r
+               \r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/UncachedUrlStream.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/UncachedUrlStream.as
new file mode 100644 (file)
index 0000000..30fc448
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.ogg {\r
+\r
+       import flash.net.*;\r
+       import flash.utils.Endian;\r
+       import flash.events.HTTPStatusEvent;\r
+       import flash.events.ProgressEvent;\r
+       \r
+       public class UncachedUrlStream {\r
+               \r
+               private var source:URLStream;\r
+       \r
+               public function UncachedUrlStream(source: URLStream) {\r
+                       this.source = source;\r
+               }\r
+       \r
+               public function get bytesAvailable():int {\r
+                       return source.bytesAvailable;\r
+               }       \r
+       \r
+               public function addEventListener(type:String, listener:Function):void {\r
+                       source.addEventListener(type, listener);\r
+               }\r
+       \r
+               public function getLogicalOggStream():LogicalOggStream {\r
+                       return new LogicalOggStream(this);\r
+               }\r
+       \r
+               public function getNextOggPage():OggPage {\r
+                       return new OggPage(source);\r
+               }\r
+               \r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/BitByteArray.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/BitByteArray.as
new file mode 100644 (file)
index 0000000..d954897
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.util {\r
+\r
+       import flash.utils.ByteArray;\r
+       import flash.utils.Endian;\r
+       import flash.errors.IllegalOperationError;\r
+       \r
+       public class BitByteArray extends ByteArray {\r
+       \r
+               private var currentByte:uint;\r
+               private var bitIndex:int = 8;\r
+       \r
+               public function BitByteArray() {\r
+                       this.endian = Endian.LITTLE_ENDIAN;\r
+               }\r
+\r
+               public function readBit():Boolean {\r
+                       if (bitIndex > 7) {\r
+                               bitIndex = 0;\r
+                               currentByte = readUnsignedByte();\r
+                       }\r
+                       return (currentByte & (1 << (bitIndex++))) != 0;\r
+               }\r
+               \r
+               public function readUnsignedBitwiseInt(bits:int):uint {\r
+       \r
+                       var res:uint = 0;\r
+                       \r
+                       for (var i : int = 0; i < bits; i++) {\r
+                               if (bitIndex > 7) {\r
+                                       bitIndex = 0;\r
+                                       currentByte = readUnsignedByte();\r
+                               }\r
+                               if((currentByte & (1 << (bitIndex++))) != 0) {\r
+                                       res |= (1 << i);\r
+                               }\r
+                       }\r
+                       \r
+                       return res;\r
+               }       \r
+\r
+               public function readUnsignedHuffmanInt(root:HuffmanNode):uint {\r
+\r
+                       while (!root.hasValue) {\r
+                               if (bitIndex > 7) {\r
+                                       bitIndex = 0;\r
+                                       currentByte = readUnsignedByte();\r
+                               }\r
+                               root = (currentByte & (1 << (bitIndex++))) != 0 ? root._o1 : root._o0;\r
+                       }\r
+                       \r
+                       return root._value;                     \r
+               }\r
+       \r
+       }\r
+       \r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/HuffmanNode.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/HuffmanNode.as
new file mode 100644 (file)
index 0000000..14a014d
--- /dev/null
@@ -0,0 +1,92 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+package org.omtk.util {\r
+\r
+       public class HuffmanNode {\r
+       \r
+               private var _parent:HuffmanNode;\r
+       \r
+               public var _o0:HuffmanNode;\r
+               public var _o1:HuffmanNode;\r
+               \r
+               private var _depth:int;\r
+       \r
+               public var _value:int;\r
+               public var hasValue: Boolean;\r
+               private var _full:Boolean = false;\r
+       \r
+               public function HuffmanNode(parent:HuffmanNode = null, value:int = -1) {\r
+                       _parent = parent;\r
+                       if(_parent != null) {\r
+                               _depth = _parent.depth+1;\r
+                       }\r
+                       _value = value;                 \r
+                       _full = value >= 0;\r
+                       hasValue = value >= 0;\r
+               }\r
+       \r
+               public function setNewValue(depth:int, value:uint):Boolean {\r
+             if (full) {\r
+                return false;\r
+             }\r
+             if (depth == 1) {\r
+                if (_o0 == null) {\r
+                   _o0 = new HuffmanNode(this, value);\r
+                   return true;\r
+                } else if (_o1 == null) {\r
+                   _o1 = new HuffmanNode(this, value);\r
+                   return true;\r
+                } else {\r
+                   return false;\r
+                }\r
+             } else {\r
+                return o0.setNewValue(depth - 1, value)\r
+                       ? true : o1.setNewValue(depth - 1, value);\r
+             }\r
+          }    \r
+       \r
+               public function get value():uint {\r
+                       return _value;\r
+               }\r
+       \r
+               public function get o0():HuffmanNode {\r
+                       if(_o0 == null) {\r
+                               _o0 = new HuffmanNode(this);\r
+                       }\r
+                       return _o0;\r
+               }\r
+\r
+               public function get o1():HuffmanNode {\r
+                       if(_o1 == null) {\r
+                               _o1 = new HuffmanNode(this);\r
+                       }\r
+                       return _o1;\r
+               }\r
+       \r
+               public function get depth():int {\r
+                       return _depth;\r
+               }\r
+               \r
+               public function get full():Boolean {\r
+                       return _full ? true\r
+                       : (_full = (_o0 != null && _o0.full && _o1 != null && _o1.full));\r
+               }\r
+               \r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/AudioPacket.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/AudioPacket.as
new file mode 100644 (file)
index 0000000..949b6bd
--- /dev/null
@@ -0,0 +1,340 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.utils.getTimer;\r
+       import flash.utils.ByteArray;\r
+       import org.omtk.ogg.*;\r
+       import org.omtk.util.BitByteArray;\r
+\r
+       public class AudioPacket {\r
+       \r
+               private var modeNumber:int;\r
+               private var mode:Mode;\r
+               private var mapping:Mapping;\r
+               private var n:int;\r
+               \r
+               private var blockFlag:Boolean;\r
+               private var previousWindowFlag:Boolean;\r
+               private var nextWindowFlag:Boolean;\r
+\r
+               private var windowCenter:int;\r
+               private var leftWindowStart:int;\r
+               private var leftWindowEnd:int;\r
+               private var leftN:int;\r
+               private var rightWindowStart:int;\r
+               private var rightWindowEnd:int;\r
+               private var rightN:int;\r
+               \r
+               private var window:Vector.<Number>;\r
+               private var freq0:Vector.<Number>;\r
+               private var freq1:Vector.<Number>;\r
+               private var pcm0:Vector.<Number>;\r
+               private var pcm1:Vector.<Number>;\r
+               \r
+               private var channelFloors:Vector.<Floor>;\r
+               private var noResidues:Vector.<Boolean>;                \r
+\r
+               private var _lastPacket: Boolean;\r
+               private var _lastGranulePosition: int;\r
+\r
+               public function AudioPacket(vorbis:VorbisStream, packet: OggPacket, currentGranulePosition: int) {\r
+               \r
+                       var source: BitByteArray = packet.data;\r
+                       _lastPacket = packet.lastPacket;\r
+                       _lastGranulePosition = packet.lastGranulePosition;\r
+                       \r
+                       var i:int;\r
+                       var j:int;\r
+                       var k:int;\r
+       \r
+                       var sHeader:SetupHeader = vorbis.setupHeader;\r
+                       var iHeader:IdentificationHeader = vorbis.identificationHeader;\r
+                       var modes:Vector.<Mode> = sHeader.modes;\r
+                       var mappings:Vector.<Mapping> = sHeader.mappings;\r
+                       var residues:Vector.<Residue> = sHeader.residues;\r
+                       var channels:int = iHeader.channels;\r
+       \r
+                       if (source.readUnsignedBitwiseInt(1) != 0) {\r
+                               throw new Error("Packet type mismatch when trying to create an audio packet.");\r
+                       }\r
+       \r
+                       modeNumber = source.readUnsignedBitwiseInt(Util.ilog(modes.length - 1));\r
+       \r
+                       mode = modes[modeNumber];\r
+                       \r
+                       if(mode == null) {\r
+                               throw new Error("Reference to invalid mode in audio packet.");\r
+                       }\r
+       \r
+                       mapping = mappings[mode.mapping];\r
+       \r
+                       var magnitudes:Vector.<int> = mapping.magnitudes;\r
+                       var angles:Vector.<int> = mapping.angles;\r
+       \r
+                       blockFlag = mode.blockFlag;\r
+       \r
+                       var blockSize0:int = iHeader.blockSize0;\r
+                       var blockSize1:int = iHeader.blockSize1;\r
+       \r
+                       n = blockFlag ? blockSize1 : blockSize0;\r
+       \r
+                       if (blockFlag) {\r
+                               previousWindowFlag = source.readBit();\r
+                               nextWindowFlag = source.readBit();\r
+                       }\r
+       \r
+                       windowCenter = n / 2;\r
+       \r
+                       if (blockFlag && !previousWindowFlag) {\r
+                               leftWindowStart = n / 4 - blockSize0 / 4;\r
+                               leftWindowEnd = n / 4 + blockSize0 / 4;\r
+                               leftN = blockSize0 / 2;\r
+                       } else {\r
+                               leftWindowStart = 0;\r
+                               leftWindowEnd = n / 2;\r
+                               leftN = windowCenter;\r
+                       }\r
+       \r
+                       if (blockFlag && !nextWindowFlag) {\r
+                               rightWindowStart = n * 3 / 4 - blockSize0 / 4;\r
+                               rightWindowEnd = n * 3 / 4 + blockSize0 / 4;\r
+                               rightN = blockSize0 / 2;\r
+                       } else {\r
+                               rightWindowStart = windowCenter;\r
+                               rightWindowEnd = n;\r
+                               rightN = n / 2;\r
+                       }\r
+       \r
+                       window = getComputedWindow(vorbis);\r
+       \r
+                       channelFloors = new Vector.<Floor>(channels, true);\r
+                       noResidues = new Vector.<Boolean>(channels, true);\r
+       \r
+                       freq0 = new Vector.<Number>(n, true);\r
+                       freq1 = new Vector.<Number>(n, true);\r
+                       pcm0 = new Vector.<Number>(n, true);\r
+                       pcm1 = new Vector.<Number>(n, true);\r
+\r
+                       var allFloorsEmpty: Boolean = true;\r
+                       var submapNumber: int;\r
+                       var floorNumber: int;\r
+                       var decodedFloor: Floor;\r
+       \r
+                       for(i = 0; i < channels; i++) {\r
+                               submapNumber = mapping.mux[i];\r
+                               floorNumber = mapping.submapFloors[submapNumber];\r
+                               decodedFloor = sHeader.floors[floorNumber].decodeFloor(vorbis, source);\r
+                               channelFloors[i] = decodedFloor;\r
+                               noResidues[i] = decodedFloor == null;\r
+                               if (decodedFloor != null) {\r
+                                       allFloorsEmpty = false;\r
+                               }\r
+                       }\r
+       \r
+                       if(allFloorsEmpty) {\r
+                               return;\r
+                       }\r
+                       \r
+                       var mag: int;\r
+                       var ang: int;\r
+\r
+                       for(i = 0; i < magnitudes.length; i++) {\r
+                               mag = magnitudes[i];\r
+                               ang = angles[i];\r
+                               if (!noResidues[mag] || !noResidues[ang]) {\r
+                                       noResidues[mag] = false;\r
+                                       noResidues[ang] = false;\r
+                               }\r
+                       }\r
+       \r
+                       var ch: int;\r
+                       var doNotDecodeFlags: Vector.<Boolean>;\r
+                       var residue:Residue;\r
+                       \r
+                       for(i = 0; i < mapping.submaps; i++) {\r
+                       \r
+                               doNotDecodeFlags = new Vector.<Boolean>();\r
+                               \r
+                               for(j = 0; j < channels; j++) {\r
+                                       if(mapping.mux[j] == i) {\r
+                                               doNotDecodeFlags.push(noResidues[j]);\r
+                                       }\r
+                               }\r
+\r
+                               residue = residues[mapping.submapResidues[i]];\r
+                               \r
+                               residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, freq0, freq1);\r
+                       }\r
+\r
+                       var a: Number;\r
+                       var m: Number;\r
+       \r
+                       for(i = mapping.couplingSteps - 1; i >= 0; i--) {\r
+                       \r
+                               mag = magnitudes[i];\r
+                               ang = angles[i];\r
+                               \r
+                               for (j = 0; j < freq0.length; j++) {\r
+                                       \r
+                                       a = ang == 0 ? freq0[j] : freq1[j];\r
+                                       m = mag == 0 ? freq0[j] : freq1[j];\r
+                                       \r
+                                       if(a > 0) {\r
+                                               if(ang == 0) {\r
+                                                       freq0[j] = m > 0 ? m - a : m + a;\r
+                                               }\r
+                                               else {\r
+                                                       freq1[j] = m > 0 ? m - a : m + a;\r
+                                               }\r
+                                       }\r
+                                       else {\r
+                                               if(mag == 0) {\r
+                                                       freq0[j] = m > 0 ? m + a : m - a;\r
+                                               }\r
+                                               else {\r
+                                                       freq1[j] = m > 0 ? m + a : m - a;\r
+                                               }\r
+                                               \r
+                                               if(ang == 0) {\r
+                                                       freq0[j] = m;\r
+                                               }\r
+                                               else {\r
+                                                       freq1[j] = m;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       if(channelFloors[0] != null) {\r
+                               Floor(channelFloors[0]).computeFloor(freq0);\r
+                       }\r
+                       \r
+                       if(channelFloors[1] != null) {\r
+                               Floor(channelFloors[1]).computeFloor(freq1);\r
+                       }\r
+\r
+                       // perform an inverse mdct to all channels\r
+                       var mdct: Mdct = blockFlag ? iHeader.mdct1 : iHeader.mdct0;\r
+                       mdct.imdct(freq0, window, pcm0);\r
+                       mdct.imdct(freq1, window, pcm1);\r
+\r
+                       if(_lastPacket) {\r
+                               if(leftWindowEnd - leftWindowStart > _lastGranulePosition - currentGranulePosition) {\r
+                                       leftWindowEnd = leftWindowStart + _lastGranulePosition - currentGranulePosition\r
+                               }\r
+                               if(rightWindowStart - leftWindowStart > _lastGranulePosition - currentGranulePosition) {\r
+                                       rightWindowStart = leftWindowStart + _lastGranulePosition - currentGranulePosition\r
+                               }\r
+                       }\r
+\r
+               }       \r
+       \r
+               private function getComputedWindow(vorbis:VorbisStream):Vector.<Number> {\r
+                       \r
+                       var i:int;\r
+                       \r
+                       var ix:int = (blockFlag ? 4 : 0) + (previousWindowFlag ? 2 : 0) + (nextWindowFlag ? 1 : 0);\r
+                       var w:Vector.<Number> = vorbis.windows[ix];\r
+                       \r
+                       var x:Number;\r
+                       \r
+                       if (w == null) {\r
+                               w = new Vector.<Number>(n);\r
+       \r
+                               for(i = 0; i < leftWindowStart; i++) {\r
+                                       w[i] = 0;\r
+                               }\r
+       \r
+                               for (i = 0; i < leftN; i++) {\r
+                                       x = (i + .5) / leftN * Math.PI / 2.;\r
+                                       x = Math.sin(x);\r
+                                       x *= x;\r
+                                       x *= Math.PI / 2.;\r
+                                       x = Math.sin(x);\r
+                                       w[i + leftWindowStart] = x;\r
+                               }\r
+       \r
+                               for (i = leftWindowEnd; i < rightWindowStart; i++) {\r
+                                       w[i] = 1;\r
+                               }\r
+       \r
+                               for (i = 0; i < rightN; i++) {\r
+                                       x = (rightN - i - .5) / rightN * Math.PI / 2.;\r
+                                       x = Math.sin(x);\r
+                                       x *= x;\r
+                                       x *= Math.PI / 2.;\r
+                                       x = Math.sin(x);\r
+                                       w[i + rightWindowStart] = x;\r
+                               }\r
+       \r
+                               for(i = rightN + rightWindowStart; i < n; i++) {\r
+                                       w[i] = 0;\r
+                               }\r
+\r
+                               for(i = 0; i < w.length; i++) {\r
+                                       w[i] *= 0.5;\r
+                               }\r
+       \r
+                               vorbis.windows[ix] = w;\r
+                       }\r
+                       \r
+                       return w;\r
+               }       \r
+               \r
+               \r
+               public function readPcm(previousPacket:AudioPacket, target: ByteArray): int {\r
+               \r
+                       var j:int;\r
+                       var j2:int;\r
+                       var ppcm0:Vector.<Number> = previousPacket.pcm0;\r
+                       var ppcm1:Vector.<Number> = previousPacket.pcm1;\r
+                       \r
+                       j2 = previousPacket.rightWindowStart;\r
+                       \r
+                       for(j = leftWindowStart; j < leftWindowEnd; j++) {\r
+                               target.writeFloat(pcm0[j] + ppcm0[j2]);\r
+                               target.writeFloat(pcm1[j] + ppcm1[j2++]);\r
+                       }\r
+\r
+                       for (j = leftWindowEnd; j < rightWindowStart; j++) {\r
+                               target.writeFloat(pcm0[j]);\r
+                               target.writeFloat(pcm1[j]);\r
+                       }\r
+\r
+                       return numberOfSamples;\r
+\r
+               }\r
+\r
+               public function get numberOfSamples():int {\r
+                       return rightWindowStart - leftWindowStart;\r
+               }\r
+\r
+               public function get lastPacket(): Boolean {\r
+                       return lastPacket;\r
+               }\r
+               \r
+               public function get lastGranulePosition(): int {\r
+                       return lastGranulePosition;\r
+               }\r
+       \r
+       }\r
+\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CodeBook.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CodeBook.as
new file mode 100644 (file)
index 0000000..27137aa
--- /dev/null
@@ -0,0 +1,223 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import org.omtk.util.*;\r
+\r
+       public class CodeBook {\r
+\r
+               private var entries:uint;\r
+               private var entryLengths:Vector.<int>;\r
+               private var valueVector:Vector.<Vector.<Number>>;\r
+\r
+               private var codeBookLookupType:int = -1;\r
+\r
+               public var huffmanRoot:HuffmanNode;\r
+               public var dimensions:uint;\r
+\r
+               public function CodeBook( source: BitByteArray ) {\r
+\r
+                       var i:int;\r
+                       var j:int;\r
+               \r
+                       var syncPattern:uint = source.readUnsignedBitwiseInt(24);\r
+                       if(syncPattern !=0x564342) {\r
+                               throw new IllegalOperationError("Illegal codebook sync pattern: "+syncPattern);\r
+                       }\r
+               \r
+                       dimensions = source.readUnsignedBitwiseInt(16);\r
+                       entries = source.readUnsignedBitwiseInt(24);\r
+                       \r
+                       entryLengths = new Vector.<int>(entries);\r
+                       \r
+                       var ordered:Boolean = source.readBit();\r
+                       \r
+                       if(ordered) {\r
+                               var cl:int = source.readUnsignedBitwiseInt(5)+1;\r
+                               for(i=0; i<entryLengths.length; ) {\r
+                                       var num:int = source.readUnsignedBitwiseInt(Util.ilog(entryLengths.length-i));\r
+                                       if(i+num>entryLengths.length) {\r
+                                               throw new Error("The codebook entry length list is longer than the actual number of entry lengths.");\r
+                                       }\r
+                                       for(j=i; j<i+num; j++) {\r
+                                               entryLengths[j] = cl;\r
+                                       }\r
+                                       //Arrays.fill(entryLengths, i, i+num, cl);\r
+                                       cl++;\r
+                                       i+=num;\r
+                               }\r
+                       }\r
+                       else {\r
+                               // !ordered\r
+                               var sparse:Boolean = source.readBit();\r
+                               \r
+                               if(sparse) {\r
+                                       for(i=0; i<entryLengths.length; i++) {\r
+                                               if(source.readBit()) {\r
+                                                       entryLengths[i]=source.readUnsignedBitwiseInt(5)+1;\r
+                                               }\r
+                                               else {\r
+                                                       entryLengths[i]=-1;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               else {\r
+                                       // !sparse\r
+                                       //Alert.show("entryLengths.length: "+entryLengths.length, "CodeBook");\r
+                                       for(i=0; i<entryLengths.length; i++) {\r
+                                               entryLengths[i]=source.readUnsignedBitwiseInt(5)+1;\r
+                                       }\r
+                               }\r
+                       \r
+                       }\r
+                       \r
+                       if (!createHuffmanTree(entryLengths)) {\r
+                               throw new Error("An exception was thrown when building the codebook Huffman tree.");\r
+                       }       \r
+\r
+                       codeBookLookupType = source.readUnsignedBitwiseInt(4);\r
+\r
+                       switch(codeBookLookupType) {\r
+                       case 0:\r
+                               // codebook has no scalar vectors to be calculated\r
+                               break;\r
+                       case 1:\r
+                       case 2:\r
+                               var codeBookMinimumValue:Number = Util.float32unpack(source.readUnsignedBitwiseInt(32));\r
+                               var codeBookDeltaValue:Number = Util.float32unpack(source.readUnsignedBitwiseInt(32));\r
+\r
+                               var codeBookValueBits:uint = source.readUnsignedBitwiseInt(4)+1;\r
+                               var codeBookSequenceP:Boolean = source.readBit();\r
+\r
+                               var codeBookLookupValues:uint = 0;\r
+\r
+                               if(codeBookLookupType==1) {\r
+                                       codeBookLookupValues=Util.lookup1Values(entries, dimensions);\r
+                               }\r
+                               else {\r
+                                       codeBookLookupValues=entries*dimensions;\r
+                               }\r
+\r
+                               var codeBookMultiplicands:Vector.<int> = new Vector.<int>(codeBookLookupValues);\r
+\r
+                               for(i=0; i < codeBookMultiplicands.length; i++) {\r
+                                       codeBookMultiplicands[i]=source.readUnsignedBitwiseInt(codeBookValueBits);\r
+                               }\r
+\r
+                               valueVector = new Vector.<Vector.<Number>>(entries);\r
+\r
+                               if(codeBookLookupType==1) {\r
+                                       for(i=0; i<entries; i++) {\r
+                                               valueVector[i] = new Vector.<Number>(dimensions);\r
+                                               var last:Number = 0.0;\r
+                                               var indexDivisor:uint = 1;\r
+                                               for(j=0; j<dimensions; j++) {\r
+                                                       var multiplicandOffset:int = (i/indexDivisor)%codeBookLookupValues;\r
+                                                       valueVector[i][j]=\r
+                                                               codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;\r
+                                                       if(codeBookSequenceP) {\r
+                                                               last = valueVector[i][j];\r
+                                                       }\r
+                                                       indexDivisor*=codeBookLookupValues;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               else {\r
+                                       throw new Error("Unsupported codebook lookup type: "+codeBookLookupType);\r
+                                       /** @todo implement */\r
+                               }\r
+                               break;\r
+                       default:\r
+                               throw new Error("Unsupported codebook lookup type: "+codeBookLookupType);\r
+                       }\r
+               }\r
+       \r
+               private function createHuffmanTree(entryLengths:Vector.<int>):Boolean {\r
+               \r
+                       var i:int;\r
+               \r
+                       huffmanRoot = new HuffmanNode();\r
+                       for(i=0; i<entryLengths.length; i++) {\r
+                               var el:int = entryLengths[i];\r
+                               if(el>0) {\r
+                                       if(!huffmanRoot.setNewValue(el, i)) {\r
+                                               return false;\r
+                                       }\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+\r
+\r
+               public function readVvAdd(a0:Vector.<Number>, a1:Vector.<Number>, left:Boolean, right:Boolean, source:BitByteArray, offset:int, length:int):void {\r
+       \r
+                       var i:int;\r
+                       var j:int;\r
+       \r
+                       if (!left && !right) {\r
+                               return;\r
+                       }\r
+\r
+                       // 1 or 2 channels      \r
+                       var ch:int = \r
+                               left && right ? 2 : 1;\r
+\r
+                       var lim:int;\r
+                       var ix:int;\r
+                       var ve:Vector.<Number>;\r
+                       \r
+                       if(left && right) {\r
+                               lim = (offset + length) / 2;\r
+                               var chptr:int = 0;\r
+                               for (i = offset / 2; i < lim;) {\r
+                                       ix = source.readUnsignedHuffmanInt(huffmanRoot);\r
+                                       ve = valueVector[ix];\r
+                                       for (j = 0; j < dimensions; j++) {\r
+                                               if(chptr == 0) {\r
+                                                       a0[i] += ve[j];\r
+                                               }\r
+                                               else {\r
+                                                       a1[i] += ve[j];\r
+                                               }\r
+                                               chptr++;\r
+                                               if(chptr == 2) {\r
+                                                       chptr = 0;\r
+                                                       i++;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       else {\r
+                               var a : Vector.<Number> = left ? a0 : a1;\r
+                               lim = offset + length;\r
+                               for (i = offset; i < lim;) {\r
+                                       ve = valueVector[source.readUnsignedHuffmanInt(huffmanRoot)];\r
+                                       for (j = 0; j < dimensions; j++) {\r
+                                               a[i] += ve[j];\r
+                                               i++;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+               }\r
+               \r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CommentHeader.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CommentHeader.as
new file mode 100644 (file)
index 0000000..81885a6
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.utils.ByteArray;\r
+       import flash.utils.Endian;\r
+       import flash.utils.Dictionary;\r
+       import org.omtk.ogg.*;\r
+\r
+       public class CommentHeader {\r
+       \r
+               private var _vendor:String;\r
+               private var _comments:Dictionary = new Dictionary();\r
+       \r
+               public function CommentHeader(source:ByteArray)\r
+               {\r
+                       init( source );\r
+               }\r
+               \r
+               private function init( source: ByteArray ): void\r
+               {\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+\r
+                       _vendor = readUtf8String(source);\r
+                       \r
+                       var ucLength:int = source.readUnsignedInt();\r
+                       \r
+                       for(var i:int = 0; i < ucLength; i++) {\r
+                               var comment:String = readUtf8String(source);\r
+                               var ix:int = comment.indexOf('=');\r
+                               var key:String = comment.substring(0, ix);\r
+                               var value:String = comment.substring(ix+1);\r
+                               _comments[key.toUpperCase()]=value;\r
+                       }\r
+               }       \r
+       \r
+               private function readUtf8String(source:ByteArray):String {\r
+                       var length:uint = source.readUnsignedInt();\r
+                       return source.readUTFBytes(length);\r
+               }\r
+       \r
+               public function get vendor():String {\r
+                       return _vendor;\r
+               }\r
+               \r
+               public function get comments():Dictionary {\r
+                       return _comments;\r
+               }\r
+       \r
+               public function get artist():String {\r
+                       return _comments["ARTIST"];\r
+               }\r
+               \r
+               public function get title():String {\r
+                       return _comments["TITLE"];\r
+               }\r
+       \r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor.as
new file mode 100644 (file)
index 0000000..24295d5
--- /dev/null
@@ -0,0 +1,122 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import org.omtk.util.BitByteArray;\r
+       \r
+       public class Floor {\r
+       \r
+               public static const DB_STATIC_TABLE:Vector.<Number> = Vector.<Number>([\r
+                       1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07,\r
+                       1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07,\r
+                       1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.128753e-07,\r
+                       2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07,\r
+                       2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07,\r
+                       3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07,\r
+                       4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07,\r
+                       6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07,\r
+                       7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07,\r
+                       1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06,\r
+                       1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06,\r
+                       1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06,\r
+                       2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06,\r
+                       2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06,\r
+                       3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06,\r
+                       4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06,\r
+                       5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06,\r
+                       7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06,\r
+                       9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05,\r
+                       1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05,\r
+                       1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05,\r
+                       2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05,\r
+                       2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05,\r
+                       3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05,\r
+                       4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05,\r
+                       5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05,\r
+                       7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05,\r
+                       9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824,\r
+                       0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085,\r
+                       0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536,\r
+                       0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449,\r
+                       0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787,\r
+                       0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456,\r
+                       0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927,\r
+                       0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058,\r
+                       0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457,\r
+                       0.00092223983, 0.00098217216, 0.0010459992, 0.0011139742,\r
+                       0.0011863665, 0.0012634633, 0.0013455702, 0.0014330129,\r
+                       0.0015261382, 0.0016253153, 0.0017309374, 0.0018434235,\r
+                       0.0019632195, 0.0020908006, 0.0022266726, 0.0023713743,\r
+                       0.0025254795, 0.0026895994, 0.0028643847, 0.0030505286,\r
+                       0.0032487691, 0.0034598925, 0.0036847358, 0.0039241906,\r
+                       0.0041792066, 0.0044507950, 0.0047400328, 0.0050480668,\r
+                       0.0053761186, 0.0057254891, 0.0060975636, 0.0064938176,\r
+                       0.0069158225, 0.0073652516, 0.0078438871, 0.0083536271,\r
+                       0.0088964928, 0.009474637, 0.010090352, 0.010746080,\r
+                       0.011444421, 0.012188144, 0.012980198, 0.013823725,\r
+                       0.014722068, 0.015678791, 0.016697687, 0.017782797,\r
+                       0.018938423, 0.020169149, 0.021479854, 0.022875735,\r
+                       0.024362330, 0.025945531, 0.027631618, 0.029427276,\r
+                       0.031339626, 0.033376252, 0.035545228, 0.037855157,\r
+                       0.040315199, 0.042935108, 0.045725273, 0.048696758,\r
+                       0.051861348, 0.055231591, 0.058820850, 0.062643361,\r
+                       0.066714279, 0.071049749, 0.075666962, 0.080584227,\r
+                       0.085821044, 0.091398179, 0.097337747, 0.10366330,\r
+                       0.11039993, 0.11757434, 0.12521498, 0.13335215,\r
+                       0.14201813, 0.15124727, 0.16107617, 0.17154380,\r
+                       0.18269168, 0.19456402, 0.20720788, 0.22067342,\r
+                       0.23501402, 0.25028656, 0.26655159, 0.28387361,\r
+                       0.30232132, 0.32196786, 0.34289114, 0.36517414,\r
+                       0.38890521, 0.41417847, 0.44109412, 0.46975890,\r
+                       0.50028648, 0.53279791, 0.56742212, 0.60429640,\r
+                       0.64356699, 0.68538959, 0.72993007, 0.77736504,\r
+                       0.82788260, 0.88168307, 0.9389798, 1.0]);\r
+       \r
+               public static function createInstance(source:BitByteArray, header:SetupHeader):Floor {\r
+       \r
+                       var type:int = source.readUnsignedBitwiseInt(16);\r
+       \r
+                       switch (type) {\r
+                       case 0:\r
+                               return new Floor0(source, header);\r
+                       case 1:\r
+                               return new Floor1(source, header);\r
+                       default:\r
+                               throw new Error("Floor type " + type + " is not supported.");\r
+                       }\r
+               }\r
+\r
+               public function get type():int {\r
+                       throw new IllegalOperationError("operation not implemented");\r
+               }\r
+               \r
+               public function decodeFloor(vorbis:VorbisStream, source:BitByteArray):Floor1 {\r
+                       throw new IllegalOperationError("operation not implemented");\r
+               }\r
+       \r
+               public function computeFloor(vector:Vector.<Number>):void {\r
+                       throw new IllegalOperationError("operation not implemented");\r
+               }\r
+               \r
+\r
+       }\r
+\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor0.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor0.as
new file mode 100644 (file)
index 0000000..064a0a1
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import org.omtk.util.BitByteArray;\r
+       \r
+       public class Floor0 extends Floor {\r
+\r
+               private var order:int;\r
+               private var rate:int;\r
+               private var barkMapSize:int;\r
+               private var amplitudeBits:int;\r
+               private var amplitudeOffset:int;\r
+               \r
+               private var bookList:Vector.<int>;\r
+               \r
+               public function Floor0(source:BitByteArray, header:SetupHeader) {\r
+\r
+                       order = source.readUnsignedBitwiseInt(8);\r
+                       rate = source.readUnsignedBitwiseInt(16);\r
+                       barkMapSize = source.readUnsignedBitwiseInt(16);\r
+                       amplitudeBits = source.readUnsignedBitwiseInt(6);\r
+                       amplitudeOffset = source.readUnsignedBitwiseInt(8);\r
+       \r
+                       var bookCount:uint = source.readUnsignedBitwiseInt(4) + 1;\r
+                       bookList = new Vector.<int>(bookCount);\r
+       \r
+                       var i:int;\r
+       \r
+                       for (i = 0; i < bookList.length; i++) {\r
+                               bookList[i] = source.readUnsignedBitwiseInt(8);\r
+                               if (bookList[i] > header.codeBooks.length) {\r
+                                       throw new Error("A floor0_book_list entry is higher than the code book count.");\r
+                               }\r
+                       }\r
+               }\r
+\r
+       }\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor1.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor1.as
new file mode 100644 (file)
index 0000000..068d817
--- /dev/null
@@ -0,0 +1,278 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import org.omtk.util.*;\r
+       \r
+       public class Floor1 extends Floor {\r
+\r
+               private var partitionClassList:Vector.<int>;\r
+               private var maximumClass:int;\r
+               private var multiplier:int;\r
+               private var rangeBits:int;\r
+               private var classDimensions:Vector.<int>;\r
+               private var classSubclasses:Vector.<int>;\r
+               private var classMasterbooks:Vector.<int>;\r
+               private var subclassBooks:Vector.<Vector.<int>>;\r
+               private var xList:Vector.<int>;\r
+               private var yList:Vector.<int>;\r
+               private var lowNeighbours:Vector.<int>;\r
+               private var highNeighbours:Vector.<int>;\r
+               private static var RANGES:Vector.<int> = Vector.<int>([256, 128, 86, 64]);\r
+\r
+               private var xList2:Vector.<int>;\r
+               private var step2Flags:Vector.<Boolean>;\r
+               \r
+               public function Floor1(source:BitByteArray = null, header:SetupHeader = null) {\r
+\r
+                       if(source==null && header==null) {\r
+                               return;\r
+                       }\r
+               \r
+                       var i:int;\r
+                       var j:int;\r
+                       \r
+                       maximumClass = -1;\r
+                       var partitions:int = source.readUnsignedBitwiseInt(5);\r
+                       partitionClassList = new Vector.<int>(partitions);\r
+       \r
+                       for (i = 0; i < partitionClassList.length; i++) {\r
+                               partitionClassList[i] = source.readUnsignedBitwiseInt(4);\r
+                               if (partitionClassList[i] > maximumClass) {\r
+                                       maximumClass = partitionClassList[i];\r
+                               }\r
+                       }\r
+       \r
+                       classDimensions = new Vector.<int>(maximumClass + 1);\r
+                       classSubclasses = new Vector.<int>(maximumClass + 1);\r
+                       classMasterbooks = new Vector.<int>(maximumClass + 1);\r
+                       subclassBooks = new Vector.<Vector.<int>>(maximumClass + 1);\r
+       \r
+                       var xListLength:int = 2;\r
+       \r
+                       for (i = 0; i <= maximumClass; i++) {\r
+                               classDimensions[i] = source.readUnsignedBitwiseInt(3) + 1;\r
+                               xListLength += classDimensions[i];\r
+                               classSubclasses[i] = source.readUnsignedBitwiseInt(2);\r
+       \r
+                               if (classDimensions[i] > header.codeBooks.length || classSubclasses[i] > header.codeBooks.length) {\r
+                                       throw new Error("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");\r
+                               }\r
+                               if (classSubclasses[i] != 0) {\r
+                                       classMasterbooks[i] = source.readUnsignedBitwiseInt(8);\r
+                               }\r
+                               subclassBooks[i] = new Vector.<int>(1 << classSubclasses[i]);\r
+                               for (j = 0; j < subclassBooks[i].length; j++) {\r
+                                       subclassBooks[i][j] = source.readUnsignedBitwiseInt(8) - 1;\r
+                               }\r
+                       }\r
+       \r
+                       multiplier = source.readUnsignedBitwiseInt(2) + 1;\r
+                       rangeBits = source.readUnsignedBitwiseInt(4);\r
+       \r
+                       var floorValues:int = 0;\r
+       \r
+                       xList = Vector.<int>([0, 1<<rangeBits]);\r
+                       \r
+                       for (i = 0; i < partitions; i++) {\r
+                               for (j = 0; j < classDimensions[partitionClassList[i]]; j++) {\r
+                                       xList.push(source.readUnsignedBitwiseInt(rangeBits));\r
+                               }\r
+                       }\r
+       \r
+                       lowNeighbours = new Vector.<int>(xList.length);\r
+                       highNeighbours = new Vector.<int>(xList.length);\r
+       \r
+                       for (i = 0; i < xList.length; i++) {\r
+                               lowNeighbours[i] = Util.lowNeighbour(xList, i);\r
+                               highNeighbours[i] = Util.highNeighbour(xList, i);\r
+                       }\r
+                       \r
+                       xList2 = new Vector.<int>(xList.length, true);\r
+                       step2Flags = new Vector.<Boolean>(xList.length, true);\r
+               }\r
+\r
+               public override function get type():int {\r
+                       return 1;\r
+               }\r
+\r
+               public override function decodeFloor(vorbis:VorbisStream, source:BitByteArray):Floor1 {\r
+\r
+                       var i:int;\r
+                       var j:int;\r
+                       var offset:int;\r
+\r
+                       if (!source.readBit()) {\r
+                               return null;\r
+                       }\r
+       \r
+                       var clone:Floor1 = clone();\r
+       \r
+                       clone.yList = new Vector.<int>(xList.length);\r
+       \r
+                       var range:int = RANGES[multiplier - 1];\r
+       \r
+                       clone.yList[0] = source.readUnsignedBitwiseInt(Util.ilog(range - 1));\r
+                       clone.yList[1] = source.readUnsignedBitwiseInt(Util.ilog(range - 1));\r
+       \r
+                       offset = 2;\r
+       \r
+                       for (i = 0; i < partitionClassList.length; i++) {\r
+                               var cls:int = partitionClassList[i];\r
+                               var cdim:int = classDimensions[cls];\r
+                               var cbits:int = classSubclasses[cls];\r
+                               var csub:int = (1 << cbits) - 1;\r
+                               var cval:int = 0;\r
+                               if (cbits > 0) {\r
+                                       cval = source.readUnsignedHuffmanInt(vorbis.setupHeader.codeBooks[classMasterbooks[cls]].huffmanRoot);\r
+                               }\r
+\r
+                               for (j = 0; j < cdim; j++) {\r
+                                       var book:int = subclassBooks[cls][cval & csub];\r
+                                       cval >>>= cbits;\r
+                                       if (book >= 0) {\r
+                                               clone.yList[j + offset] = source.readUnsignedHuffmanInt(vorbis.setupHeader.codeBooks[book].huffmanRoot);\r
+                                       } else {\r
+                                               clone.yList[j + offset] = 0;\r
+                                       }\r
+                               }\r
+                               offset += cdim;\r
+                       }\r
+               \r
+                       return clone;\r
+               }\r
+       \r
+               public override function computeFloor(vector:Vector.<Number>):void {\r
+\r
+                       var i:int;\r
+                       var j:int;\r
+\r
+                       var n:int = vector.length;\r
+                       var values:int = xList.length;\r
+                       //var step2Flags:Vector.<Boolean> = new Vector.<Boolean>(values);\r
+\r
+                       var range:int = RANGES[multiplier - 1];\r
+       \r
+                       for (i = 2; i < values; i++) {\r
+\r
+                               var lowNeighbourOffset:int = lowNeighbours[i];\r
+                               var highNeighbourOffset:int = highNeighbours[i];\r
+                               \r
+                               var predicted:int = Util.renderPoint(\r
+                                       xList[lowNeighbourOffset], xList[highNeighbourOffset], \r
+                                       yList[lowNeighbourOffset], yList[highNeighbourOffset], xList[i]);\r
+                               \r
+                               var val:int = yList[i];\r
+                               var highRoom:int = range - predicted;\r
+                               var lowRoom:int = predicted;\r
+                               var room:int = highRoom < lowRoom ? highRoom * 2 : lowRoom * 2;\r
+                               \r
+                               if (val != 0) {\r
+                                       step2Flags[lowNeighbourOffset] = true;\r
+                                       step2Flags[highNeighbourOffset] = true;\r
+                                       step2Flags[i] = true;\r
+                                       if (val >= room) {\r
+                                               yList[i] = highRoom > lowRoom ? val - lowRoom + predicted\r
+                                                               : -val + highRoom + predicted - 1;\r
+                                       } else {\r
+                                               yList[i] = (val & 1) == 1 ? predicted - ((val + 1) >> 1)\r
+                                                               : predicted + (val >> 1);\r
+                                       }\r
+                               } else {\r
+                                       step2Flags[i] = false;\r
+                                       yList[i] = predicted;\r
+                               }\r
+                       }\r
+       \r
+                       for(i=0; i<xList.length; i++) {\r
+                               xList2[i] = xList[i];\r
+                       }\r
+\r
+                       sort(xList2, yList, step2Flags);\r
+       \r
+                       var hx:int = 0;\r
+                       var hy:int = 0;\r
+                       var lx:int = 0;\r
+                       var ly:int = yList[0] * multiplier;\r
+       \r
+                       for (i = 1; i < values; i++) {\r
+                               if (step2Flags[i]) {\r
+                                       hy = yList[i] * multiplier;\r
+                                       hx = xList2[i];\r
+                                       Util.renderLine(lx, ly, hx, hy, vector);\r
+                                       lx = hx;\r
+                                       ly = hy;\r
+                               }\r
+                       }\r
+       \r
+                       var r:Number = DB_STATIC_TABLE[hy];\r
+\r
+                       while(hx < n/2) {\r
+                               vector[hx++] = r;\r
+                       }\r
+\r
+               }\r
+\r
+               public function clone():Floor1 {\r
+                       var clone:Floor1 = new Floor1();\r
+                       clone.classDimensions = classDimensions;\r
+                       clone.classMasterbooks = classMasterbooks;\r
+                       clone.classSubclasses = classSubclasses;\r
+                       clone.maximumClass = maximumClass;\r
+                       clone.multiplier = multiplier;\r
+                       clone.partitionClassList = partitionClassList;\r
+                       clone.rangeBits = rangeBits;\r
+                       clone.subclassBooks = subclassBooks;\r
+                       clone.xList = xList;\r
+                       clone.yList = yList;\r
+                       clone.lowNeighbours = lowNeighbours;\r
+                       clone.highNeighbours = highNeighbours;\r
+                       clone.xList2 = xList2;\r
+                       clone.step2Flags = step2Flags;\r
+                       return clone;\r
+               }\r
+               \r
+               private function sort(x:Vector.<int>, y:Vector.<int>, b:Vector.<Boolean>):void {\r
+                       var off:int = 0;\r
+                       var len:int = x.length;\r
+                       var lim:int = len + off;\r
+                       var itmp:int;\r
+                       var btmp:Boolean;\r
+                       var i:int;\r
+                       var j:int;\r
+                       // Insertion sort on smallest arrays\r
+                       for (i = off; i < lim; i++) {\r
+                               for (j = i; j > off && x[j - 1] > x[j]; j--) {\r
+                                       itmp = x[j];\r
+                                       x[j] = x[j - 1];\r
+                                       x[j - 1] = itmp;\r
+                                       itmp = y[j];\r
+                                       y[j] = y[j - 1];\r
+                                       y[j - 1] = itmp;\r
+                                       btmp = b[j];\r
+                                       b[j] = b[j - 1];\r
+                                       b[j - 1] = btmp;\r
+                               }\r
+                       }\r
+               }\r
+\r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/IdentificationHeader.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/IdentificationHeader.as
new file mode 100644 (file)
index 0000000..e78ff2e
--- /dev/null
@@ -0,0 +1,87 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.utils.ByteArray;\r
+       \r
+       public class IdentificationHeader {\r
+       \r
+               private var _version:uint;\r
+               private var _channels:uint;\r
+               private var _sampleRate:uint;\r
+               private var _bitrateMaximum:int;\r
+               private var _bitrateMinimum:int;\r
+               private var _bitrateNominal:int;\r
+               private var _blockSize0:uint;\r
+               private var _blockSize1:uint;\r
+       \r
+               private var _mdct:Vector.<Mdct>;\r
+\r
+               public function IdentificationHeader(source:ByteArray) {\r
+\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+       \r
+                       _version = source.readUnsignedInt();\r
+                       _channels = source.readUnsignedByte();\r
+                       _sampleRate = source.readUnsignedInt();\r
+                       _bitrateMaximum = source.readUnsignedInt();\r
+                       _bitrateNominal = source.readUnsignedInt();\r
+                       _bitrateMinimum = source.readUnsignedInt();\r
+                       var bs:int = source.readUnsignedByte();\r
+                       _blockSize0 = 1<<(bs&0xf);\r
+                       _blockSize1 = 1<<(bs>>4);\r
+               \r
+                       _mdct = new Vector.<Mdct>(2, false);\r
+                       _mdct[0] = new Mdct(_blockSize0);\r
+                       _mdct[1] = new Mdct(_blockSize1);\r
+               }\r
+               \r
+               public function get channels():uint {\r
+                       return _channels;\r
+               }\r
+               \r
+               public function get sampleRate():uint {\r
+                       return _sampleRate;\r
+               }\r
+               \r
+               public function get blockSize0():uint {\r
+                       return _blockSize0;\r
+               }\r
+               \r
+               public function get blockSize1():uint {\r
+                       return _blockSize1;\r
+               }\r
+               \r
+               public function get mdct0():Mdct {\r
+                       return _mdct[0];\r
+               }\r
+       \r
+               public function get mdct1():Mdct {\r
+                       return _mdct[1];\r
+               }\r
+\r
+       }\r
+\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Look.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Look.as
new file mode 100644 (file)
index 0000000..0f50452
--- /dev/null
@@ -0,0 +1,136 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import org.omtk.util.BitByteArray;\r
+       \r
+       public class Look {\r
+       \r
+               private var _map:int;\r
+               private var _parts:int;\r
+               private var _stages:int;\r
+               private var _fullbooks:Vector.<CodeBook>;\r
+               private var _phrasebook:CodeBook;\r
+               private var _partbooks:Vector.<Vector.<int>>;\r
+               private var _partvals:int;\r
+               private var _decodemap:Vector.<Vector.<int>>;\r
+               private var _postbits:int;\r
+               private var _phrasebits:int;\r
+               private var _frames:int;\r
+\r
+               public function Look(source:VorbisStream, residue:Residue, mode:Mode) {\r
+               \r
+                       var i:int;\r
+                       var j:int;\r
+                       var k:int;\r
+                       \r
+                       var dim:int = 0;\r
+                       var acc:int = 0;\r
+                       var maxstage:int = 0;\r
+\r
+                       _map = mode.mapping;\r
+                       \r
+                       _parts = residue.classifications;\r
+                       _fullbooks = source.setupHeader.codeBooks;\r
+                       _phrasebook = _fullbooks[residue.classBook];\r
+                       dim = _phrasebook.dimensions;\r
+\r
+                       _partbooks = new Vector.<Vector.<int>>(_parts);\r
+\r
+                       for (j = 0; j < _parts; j++) {\r
+                               var s:int = Util.ilog(residue.cascade[j]);\r
+                               if (s != 0) {\r
+                                       if (s > maxstage) {\r
+                                               maxstage = s;\r
+                                       }\r
+                                       _partbooks[j] = new Vector.<int>(s);\r
+                                       for (k = 0; k < s; k++) {\r
+                                               if ((residue.cascade[j] & (1 << k)) != 0) {\r
+                                                       _partbooks[j][k] = residue.books[j][k];\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       _partvals = Math.round(Math.pow(_parts, dim));\r
+                       _stages = maxstage;\r
+\r
+                       _decodemap = new Vector.<Vector.<int>>(_partvals, true);\r
+\r
+                       for (j = 0; j < _partvals; j++) {\r
+                               var val:int = j;\r
+                               var mult:int = _partvals / _parts;\r
+                               _decodemap[j] = new Vector.<int>(dim);\r
+\r
+                               for (k = 0; k < dim; k++) {\r
+                                       var deco:int = val / mult;\r
+                                       val -= deco * mult;\r
+                                       mult /= _parts;\r
+                                       _decodemap[j][k] = deco;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               public function get map():int {\r
+                       return _map;\r
+               }\r
+               \r
+               public function get parts():int {\r
+                       return _parts;\r
+               }\r
+               \r
+               public function get stages():int {\r
+                       return _stages;\r
+               }\r
+               \r
+               public function get fullbooks():Vector.<CodeBook> {\r
+                       return _fullbooks;\r
+               }\r
+               \r
+               public function get phrasebook():CodeBook {\r
+                       return _phrasebook;\r
+               }\r
+               \r
+               public function get partbooks():Vector.<Vector.<int>> {\r
+                       return _partbooks;\r
+               }\r
+               \r
+               public function get partvals():int {\r
+                       return _partvals;\r
+               }\r
+               \r
+               public function get decodemap():Vector.<Vector.<int>> {\r
+                       return _decodemap;\r
+               }\r
+               \r
+               public function get postbits():int {\r
+                       return _postbits;\r
+               }\r
+                       \r
+               public function get phrasebits():int {\r
+                       return _phrasebits;\r
+               }\r
+               \r
+               public function get frames():int {\r
+                       return _frames;\r
+               }\r
+                       \r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping.as
new file mode 100644 (file)
index 0000000..8b2c5ae
--- /dev/null
@@ -0,0 +1,73 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import org.omtk.util.BitByteArray;\r
+\r
+       public class Mapping {\r
+       \r
+               public static function createInstance(stream:VorbisStream, source:BitByteArray, header:SetupHeader):Mapping {\r
+               \r
+                       var type:int = source.readUnsignedBitwiseInt(16);\r
+                       switch (type) {\r
+                       case 0:\r
+                               return new Mapping0(stream, source, header);\r
+                       default:\r
+                               throw new Error("Mapping type " + type + " is not supported.");\r
+                       }\r
+               \r
+               }\r
+       \r
+               public function get type():int {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+       \r
+               public function get couplingSteps():int {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+               public function get submaps():int {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+               public function get angles():Vector.<int> {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+               public function get magnitudes():Vector.<int> {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+               public function get mux():Vector.<int> {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+               public function get submapFloors():Vector.<int> {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+               public function get submapResidues():Vector.<int> {\r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+\r
+       \r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping0.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping0.as
new file mode 100644 (file)
index 0000000..13dd013
--- /dev/null
@@ -0,0 +1,136 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import org.omtk.util.BitByteArray;\r
+\r
+       public class Mapping0 extends Mapping {\r
+       \r
+               private var _magnitudes:Vector.<int>;\r
+               private var _angles:Vector.<int>;\r
+               private var _mux:Vector.<int>;\r
+               private var _submapFloors:Vector.<int>;\r
+               private var _submapResidues:Vector.<int>;\r
+       \r
+               public function Mapping0(stream:VorbisStream, source:BitByteArray, header:SetupHeader) {\r
+\r
+                       var i:int;\r
+                       var j:int;\r
+               \r
+                       var submaps:int = 1;\r
+       \r
+                       if (source.readBit()) {\r
+                               submaps = source.readUnsignedBitwiseInt(4) + 1;\r
+                       }\r
+       \r
+                       var channels:int = stream.identificationHeader.channels;\r
+                       var ilogChannels:int = Util.ilog(channels - 1);\r
+       \r
+                       if (source.readBit()) {\r
+                               var couplingSteps:int = source.readUnsignedBitwiseInt(8) + 1;\r
+                               _magnitudes = new Vector.<int>(couplingSteps);\r
+                               _angles = new Vector.<int>(couplingSteps);\r
+       \r
+                               for (i = 0; i < couplingSteps; i++) {\r
+                                       magnitudes[i] = source.readUnsignedBitwiseInt(ilogChannels);\r
+                                       angles[i] = source.readUnsignedBitwiseInt(ilogChannels);\r
+                                       if (magnitudes[i] == angles[i] || magnitudes[i] >= channels\r
+                                                       || angles[i] >= channels) {\r
+                                               throw new Error("The channel magnitude and/or angle mismatch.");\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               _magnitudes = Vector.<int>([]);\r
+                               _angles = Vector.<int>([]);\r
+                       }\r
+       \r
+                       if (source.readUnsignedBitwiseInt(2) != 0) {\r
+                               throw new Error("A reserved mapping field has an invalid value.");\r
+                       }\r
+       \r
+                       _mux = new Vector.<int>(channels);\r
+                       if (submaps > 1) {\r
+                               for (i = 0; i < channels; i++) {\r
+                                       _mux[i] = source.readUnsignedBitwiseInt(4);\r
+                                       if (_mux[i] > submaps) {\r
+                                               throw new Error("A mapping mux value is higher than the number of submaps");\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               for (i = 0; i < channels; i++) {\r
+                                       _mux[i] = 0;\r
+                               }\r
+                       }\r
+       \r
+                       _submapFloors = new Vector.<int>(submaps);\r
+                       _submapResidues = new Vector.<int>(submaps);\r
+       \r
+                       var floorCount:int = header.floors.length;\r
+                       var residueCount:int = header.residues.length;\r
+       \r
+                       for (i = 0; i < submaps; i++) {\r
+                               source.readUnsignedBitwiseInt(8); // discard time placeholder\r
+                               _submapFloors[i] = source.readUnsignedBitwiseInt(8);\r
+                               _submapResidues[i] = source.readUnsignedBitwiseInt(8);\r
+       \r
+                               if (_submapFloors[i] > floorCount) {\r
+                                       throw new Error("A mapping floor value is higher than the number of floors.");\r
+                               }\r
+       \r
+                               if (_submapResidues[i] > residueCount) {\r
+                                       throw new Error("A mapping residue value is higher than the number of residues.");\r
+                               }\r
+                       }\r
+               }\r
+       \r
+               public override function get type():int {\r
+                       return 0;\r
+               }\r
+       \r
+               public override function get couplingSteps():int {\r
+                       return _angles.length;\r
+               }\r
+\r
+               public override function get submaps():int {\r
+                       return _submapFloors.length;\r
+               }\r
+\r
+               public override function get angles():Vector.<int> {\r
+                       return _angles;\r
+               }\r
+\r
+               public override function get magnitudes():Vector.<int> {\r
+                       return _magnitudes;\r
+               }\r
+\r
+               public override function get mux():Vector.<int> {\r
+                       return _mux;\r
+               }\r
+\r
+               public override function get submapFloors():Vector.<int> {\r
+                       return _submapFloors;\r
+               }\r
+\r
+               public override function get submapResidues():Vector.<int> {\r
+                       return _submapResidues;\r
+               }       \r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mdct.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mdct.as
new file mode 100644 (file)
index 0000000..329c276
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.events.*;\r
+       import flash.system.*;\r
+       import flash.display.*;\r
+       import flash.net.*;\r
+       import flash.utils.getTimer;\r
+       \r
+       /*\r
+        * Wrapper for the haXe compiled class org.omtk.vorbis.MdctHX\r
+        */\r
+       public class Mdct {\r
+       \r
+               public static var initialized : Boolean = false;\r
+               private static var hxClass : Class;\r
+               \r
+               public static function initialize() : void {\r
+                       var ldr:Loader = new Loader();\r
+                       var swfUrl:String = "hxmdct.swf";\r
+                       var req:URLRequest = new URLRequest(swfUrl);\r
+                       var ldrContext:LoaderContext = \r
+                       new LoaderContext(false, ApplicationDomain.currentDomain);\r
+                       ldr.load(req, ldrContext);\r
+                       ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);\r
+                       \r
+                       function swfLoaded(e:Event):void {\r
+                               hxClass = ApplicationDomain.currentDomain.getDefinition("org.omtk.vorbis.MdctHX") as Class;\r
+                               initialized = true;\r
+                       }               \r
+               }\r
+\r
+               private var delegate : Object;\r
+               \r
+               public function Mdct(n:int) { \r
+                       delegate = new hxClass(n);\r
+               }\r
+               \r
+               public function imdct(frq:Vector.<Number>, window:Vector.<Number>, pcm:Vector.<Number>):void {\r
+                       delegate.imdct(frq, window, pcm);\r
+               }\r
+\r
+       }\r
+               \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mode.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mode.as
new file mode 100644 (file)
index 0000000..6da6abf
--- /dev/null
@@ -0,0 +1,70 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import flash.utils.Dictionary;\r
+       import org.omtk.util.BitByteArray;\r
+       \r
+       public class Mode\r
+       {\r
+               private var _blockFlag:Boolean;\r
+               private var _windowType:uint;\r
+               private var _transformType:uint;\r
+               private var _mapping:uint;\r
+               \r
+               public function Mode(source:BitByteArray, header:SetupHeader) {\r
+\r
+                       _blockFlag=source.readBit();\r
+                       _windowType=source.readUnsignedBitwiseInt(16);\r
+                       _transformType=source.readUnsignedBitwiseInt(16);\r
+                       _mapping=source.readUnsignedBitwiseInt(8);\r
+                       \r
+                       if(_windowType!=0) {\r
+                               throw new Error("Window type = "+windowType+", != 0");\r
+                       }\r
+                       \r
+                       if(_transformType!=0) {\r
+                               throw new Error("Transform type = "+transformType+", != 0");\r
+                       }\r
+                       \r
+                       if(_mapping > header.mappings.length) {\r
+                               throw new Error("Mode mapping number is higher than total number of mappings.");\r
+                       }\r
+               }\r
+       \r
+               public function get blockFlag():Boolean {\r
+                       return _blockFlag;\r
+               }\r
+               \r
+               public function get windowType():uint {\r
+                       return _windowType;\r
+               }\r
+               \r
+               public function get transformType():uint {\r
+                       return _transformType;\r
+               }\r
+               \r
+               public function get mapping():uint {\r
+                       return _mapping;\r
+               }\r
+       \r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue.as
new file mode 100644 (file)
index 0000000..9c87ad9
--- /dev/null
@@ -0,0 +1,142 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import flash.utils.Dictionary;\r
+       import org.omtk.util.BitByteArray;\r
+       \r
+       public class Residue {\r
+\r
+               private var _begin:int;\r
+               private var _end:int;\r
+               private var _partitionSize:int;\r
+               private var _classifications:int;\r
+               private var _classBook:int;\r
+               private var _cascade:Vector.<int>;\r
+               private var _books:Vector.<Vector.<int>>;\r
+               \r
+               private var _looks:Dictionary;\r
+\r
+       \r
+               public function Residue(source:BitByteArray, header:SetupHeader) {\r
+\r
+                       _begin = source.readUnsignedBitwiseInt(24);\r
+                       _end = source.readUnsignedBitwiseInt(24);\r
+                       _partitionSize = source.readUnsignedBitwiseInt(24) + 1;\r
+                       _classifications = source.readUnsignedBitwiseInt(6) + 1;\r
+                       _classBook = source.readUnsignedBitwiseInt(8);\r
+       \r
+                       _cascade = new Vector.<int>(classifications);\r
+       \r
+                       var acc:int = 0;\r
+                       var i:int;\r
+                       var j:int;\r
+                       \r
+                       for (i = 0; i < classifications; i++) {\r
+                               var highBits:int = 0;\r
+                               var lowBits:int = 0;\r
+                               \r
+                               lowBits = source.readUnsignedBitwiseInt(3);\r
+                               if (source.readBit()) {\r
+                                       highBits = source.readUnsignedBitwiseInt(5);\r
+                               }\r
+                               _cascade[i] = (highBits << 3) | lowBits;\r
+                               acc += Util.icount(cascade[i]);\r
+                       }\r
+       \r
+                       _books = new Vector.<Vector.<int>>(classifications);\r
+       \r
+                       for (i = 0; i < classifications; i++) {\r
+                               books[i] = new Vector.<int>(8);\r
+                               for (j = 0; j < 8; j++) {\r
+                                       if ((cascade[i] & (1 << j)) != 0) {\r
+                                               books[i][j] = source.readUnsignedBitwiseInt(8);\r
+                                               if (books[i][j] > header.codeBooks.length) {\r
+                                                       throw new Error(\r
+                                                                       "Reference to invalid codebook entry in residue header.");\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       _looks = new Dictionary();\r
+               }\r
+       \r
+               public static function createInstance(source:BitByteArray, header:SetupHeader):Residue {\r
+       \r
+                       var type:int = source.readUnsignedBitwiseInt(16);\r
+                       switch (type) {\r
+                       case 2:\r
+                               return new Residue2(source, header);\r
+                       default:\r
+                               throw new Error("Residue type " + type + " is not supported.");\r
+                       }\r
+               }\r
+               \r
+               public function decodeResidue(\r
+                       vorbis:VorbisStream, source:BitByteArray, \r
+                       mode:Mode, ch:int,\r
+                       doNotDecodeFlags:Vector.<Boolean>, vectors0:Vector.<Number>, vectors1:Vector.<Number>):void {\r
+                               \r
+                       throw new IllegalOperationError("not implemented");\r
+               }\r
+               \r
+               \r
+               public function getLook(stream:VorbisStream, key:Mode):Look {\r
+                       var look:Look = _looks[key];\r
+                       if (look == null) {\r
+                               look = new Look(stream, this, key);\r
+                               _looks[key] = look;\r
+                       }\r
+                       return new Look(stream, this, key);//look;\r
+               }\r
+       \r
+       \r
+               public function get begin():int {\r
+                       return _begin;\r
+               }\r
+               \r
+               public function get end():int {\r
+                       return _end;\r
+               }\r
+               \r
+               public function get partitionSize():int {\r
+                       return _partitionSize;\r
+               }\r
+               \r
+               public function get classifications():int {\r
+                       return _classifications;\r
+               }\r
+               \r
+               public function get classBook():int {\r
+                       return _classBook;\r
+               }\r
+               \r
+               public function get cascade():Vector.<int> {\r
+                       return _cascade;\r
+               }\r
+               \r
+               public function get books():Vector.<Vector.<int>> {\r
+                       return _books;\r
+               }\r
+                       \r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue2.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue2.as
new file mode 100644 (file)
index 0000000..7bec7c5
--- /dev/null
@@ -0,0 +1,109 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.errors.IllegalOperationError;\r
+       import flash.utils.Dictionary;\r
+       import org.omtk.util.BitByteArray;\r
+\r
+       public class Residue2 extends Residue {\r
+       \r
+               public function Residue2(source:BitByteArray, header:SetupHeader) {\r
+                       super(source, header);\r
+               }\r
+\r
+               public override function decodeResidue(\r
+                       vorbis:VorbisStream, source:BitByteArray, \r
+                       mode:Mode, ch:int,\r
+                       doNotDecodeFlags:Vector.<Boolean>, vectors0:Vector.<Number>, vectors1:Vector.<Number>):void {\r
+\r
+                       var i:int;\r
+                       var j:int;\r
+                       var k:int;\r
+                       var l:int;\r
+                       var s:int;\r
+                       var slim:int;\r
+\r
+                       var look:Look = getLook(vorbis, mode);\r
+       \r
+                       var codeBook:CodeBook = vorbis.setupHeader.codeBooks[classBook];\r
+       \r
+                       var classvalsPerCodeword:int = codeBook.dimensions;\r
+                       var nToRead:int = end - begin;\r
+                       var partitionsToRead:int = nToRead / partitionSize; // partvals\r
+       \r
+                       var samplesPerPartition:int = partitionSize;\r
+                       var partitionsPerWord:int = look.phrasebook.dimensions;\r
+       \r
+                       var partWords:int = (partitionsToRead + partitionsPerWord - 1) / partitionsPerWord;\r
+       \r
+                       var offset:int;\r
+                       \r
+                       var left:Boolean = false;\r
+                       var right:Boolean = false;\r
+                       \r
+                       for (i = 0; i < doNotDecodeFlags.length; i++) {\r
+                               if (!doNotDecodeFlags[i]) {\r
+                                       if(i==0) {\r
+                                               left = true;\r
+                                       }\r
+                                       else if (i==1) {\r
+                                               right = true;\r
+                                       }\r
+                               }\r
+                       }\r
+       \r
+                       var partword:Array = new Array(partWords);\r
+                       \r
+                       var pb:int = source.position;\r
+                       \r
+                       slim = look.stages;\r
+                       for (s = 0; s < slim; s++) {\r
+                               \r
+                               for (i = 0, l = 0; i < partitionsToRead; l++) {\r
+                               \r
+                                       if (s == 0) {\r
+                                               var temp:int = source.readUnsignedHuffmanInt(look.phrasebook.huffmanRoot);\r
+                                               if (temp == -1) {\r
+                                                       throw new Error("Foo??");\r
+                                               }\r
+                                               partword[l] = look.decodemap[temp];\r
+                                               if (partword[l] == null) {\r
+                                                       throw new Error("Foo??");\r
+                                               }\r
+                                       }\r
+       \r
+                                       for (k = 0; k < partitionsPerWord && i < partitionsToRead; k++, i++) {\r
+                                               offset = begin + i * samplesPerPartition;\r
+\r
+                                               if ((cascade[partword[l][k]] & (1 << s)) != 0) {\r
+                                                       var stagebook:CodeBook = \r
+                                                               vorbis.setupHeader.codeBooks[look.partbooks[partword[l][k]][s]];\r
+                                                       if (stagebook != null) {\r
+                                                               stagebook.readVvAdd(vectors0, vectors1, left, right, source, offset, samplesPerPartition);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               \r
+               }\r
+               \r
+       }\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/SetupHeader.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/SetupHeader.as
new file mode 100644 (file)
index 0000000..885c182
--- /dev/null
@@ -0,0 +1,118 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import org.omtk.util.BitByteArray;\r
+\r
+       public class SetupHeader {\r
+       \r
+               private var _codeBooks:Vector.<CodeBook>;\r
+               private var _floors:Vector.<Floor>;\r
+               private var _residues:Vector.<Residue>;\r
+               private var _mappings:Vector.<Mapping>;\r
+               private var _modes:Vector.<Mode>;\r
+               \r
+               public function SetupHeader(stream:VorbisStream, source:BitByteArray) {\r
+\r
+                       var i:int;\r
+               \r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+                       source.readByte();\r
+       \r
+                       var codeBookCount:uint = source.readUnsignedBitwiseInt(8)+1;\r
+                       _codeBooks = new Vector.<CodeBook>(codeBookCount);\r
+                       \r
+                       for(i = 0; i < codeBookCount; i++) {\r
+                               _codeBooks[i] = new CodeBook(source);\r
+                       }\r
+                       \r
+                       // read the time domain transformations,\r
+                       // these should all be 0\r
+       \r
+                       var timeCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
+                       for (i = 0; i < timeCount; i++) {\r
+                               if (source.readUnsignedBitwiseInt(16) != 0) {\r
+                                       throw new Error(\r
+                                                       "Time domain transformation != 0");\r
+                               }\r
+                       }\r
+                       \r
+                       // read floor entries\r
+       \r
+                       var floorCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
+                       _floors = new Vector.<Floor>(floorCount);\r
+       \r
+                       for (i = 0; i < floorCount; i++) {\r
+                               _floors[i] = Floor.createInstance(source, this);\r
+                       }\r
+\r
+                       var residueCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
+                       _residues = new Vector.<Residue>(residueCount);\r
+\r
+                       for (i = 0; i < residueCount; i++) {\r
+                               _residues[i] = Residue.createInstance(source, this);\r
+                       }\r
+                       \r
+                       var mappingCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
+                       _mappings = new Vector.<Mapping>(mappingCount);\r
+       \r
+                       for (i = 0; i < mappingCount; i++) {\r
+                               _mappings[i] = Mapping.createInstance(stream, source, this);\r
+                       }\r
+                       \r
+                       var modeCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
+                       _modes = new Vector.<Mode>(modeCount);\r
+       \r
+                       for (i = 0; i < modeCount; i++) {\r
+                               _modes[i] = new Mode(source, this);\r
+                       }\r
+       \r
+                       if (!source.readBit()) {\r
+                               throw new Error("The setup header framing bit is incorrect.");\r
+                       }\r
+               }\r
+       \r
+               public function get codeBooks():Vector.<CodeBook> {\r
+                       return _codeBooks;\r
+               }\r
+       \r
+               public function get floors():Vector.<Floor> {\r
+                       return _floors;\r
+               }\r
+\r
+               public function get mappings():Vector.<Mapping> {\r
+                       return _mappings;\r
+               }\r
+       \r
+               public function get residues():Vector.<Residue> {\r
+                       return _residues;\r
+               }\r
+\r
+               public function get modes():Vector.<Mode> {\r
+                       return _modes;\r
+               }\r
+               \r
+       }\r
+\r
+\r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Util.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Util.as
new file mode 100644 (file)
index 0000000..698f78b
--- /dev/null
@@ -0,0 +1,122 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       public class Util {\r
+\r
+               public static function ilog(x:uint):uint {\r
+                       var res:int = 0;\r
+                       for(; x>0; x>>=1, res++);\r
+                       return res;\r
+               }       \r
+               \r
+               public static function float32unpack(x:uint):Number {\r
+                       var mantissa:Number = x&0x1fffff;\r
+                       var e:Number = (x&0x7fe00000)>>21;\r
+                       if((x&0x80000000)!=0) {\r
+                               mantissa=-mantissa;\r
+                       }\r
+                       return mantissa*Math.pow(2.0, e-788.0);\r
+               }\r
+\r
+               public static function lookup1Values(a:int, b:int):uint {\r
+                       var res:uint = Math.pow(Math.E, Math.log(a)/b);\r
+                       return intPow(res+1, b)<=a?res+1:res;\r
+               }\r
+\r
+               public static function intPow(base:uint, e:uint):uint {\r
+                       var res:uint = 1;\r
+                       for(; e>0; e--, res*=base);\r
+                       return res;\r
+               }\r
+\r
+               public static function isBitSet(value:uint, bit:uint):Boolean {\r
+                       return (value&(1<<bit))!=0;\r
+               }\r
+               \r
+               public static function icount(value:uint):uint {\r
+                       var res:uint = 0;\r
+                       while (value > 0) {\r
+                               res += value & 1;\r
+                               value >>= 1;\r
+                       }\r
+                       return res;\r
+               }\r
+\r
+               public static function lowNeighbour(v:Vector.<int>, x:int):int {\r
+\r
+                       var max:int = -1;\r
+                       var n:int = 0;\r
+                       var i:int;\r
+                       \r
+                       for (i = 0; i < v.length && i < x; i++) {\r
+                               if (v[i] > max && v[i] < v[x]) {\r
+                                       max = v[i];\r
+                                       n = i;\r
+                               }\r
+                       }\r
+                       return n;\r
+               }\r
+\r
+               public static function highNeighbour(v:Vector.<int>, x:int):int {\r
+                       \r
+                       var min:int = int.MAX_VALUE;\r
+                       var n:int = 0;\r
+                       var i:int;\r
+                       \r
+                       for (i = 0; i < v.length && i < x; i++) {\r
+                               if (v[i] < min && v[i] > v[x]) {\r
+                                       min = v[i];\r
+                                       n = i;\r
+                               }\r
+                       }\r
+                       return n;\r
+               }\r
+\r
+               public static function renderPoint(x0:int, x1:int, y0:int, y1:int, x:int):int {\r
+                       return y0 + int(((y1-y0) * (x - x0)) / (x1 - x0));\r
+               }\r
+\r
+               public static function renderLine(x0:int, y0:int, x1:int, y1:int, v:Vector.<Number>):void {\r
+               \r
+                       var dy:int = y1 - y0;\r
+                       var adx:int = x1 - x0;\r
+                       var b:int = dy / adx;\r
+                       var sy:int = dy < 0 ? b - 1 : b + 1;\r
+                       var x:int = x0;\r
+                       var y:int = y0;\r
+                       var err:int = 0;\r
+                       var ady:int = (dy < 0 ? -dy : dy) - (b > 0 ? b * adx : -b * adx);\r
+       \r
+                       v[x] *= Floor.DB_STATIC_TABLE[y];\r
+                       for (x = x0 + 1; x < x1; x++) {\r
+                               err += ady;\r
+                               if (err >= adx) {\r
+                                       err -= adx;\r
+                                       v[x] *= Floor.DB_STATIC_TABLE[y += sy];\r
+                               } else {\r
+                                       v[x] *= Floor.DB_STATIC_TABLE[y += b];\r
+                               }\r
+                       }\r
+\r
+               }\r
+\r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisSound.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisSound.as
new file mode 100644 (file)
index 0000000..8a802f9
--- /dev/null
@@ -0,0 +1,136 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.net.URLRequest;\r
+       import flash.net.URLStream;\r
+       import flash.utils.ByteArray;\r
+       import flash.utils.Endian;\r
+       import flash.events.Event;\r
+       import flash.events.ProgressEvent;\r
+       import flash.events.SampleDataEvent;\r
+       \r
+       import flash.external.ExternalInterface;\r
+\r
+       import flash.media.Sound;\r
+       \r
+       import org.omtk.ogg.UncachedUrlStream;\r
+       import org.omtk.ogg.EndOfOggStreamError;\r
+       import flash.utils.setTimeout;\r
+       \r
+       public class VorbisSound extends Sound {\r
+       \r
+               public static var METADATA_UPDATE: String = "metadata_update";\r
+       \r
+               private var urlStream: URLStream;\r
+               \r
+               private var oggStream:UncachedUrlStream;\r
+               private var vorbisStream:VorbisStream;\r
+\r
+               private var bytesAvailable:int;\r
+\r
+               private var initialized:Boolean = false;\r
+               private var playing:Boolean = false;\r
+               \r
+               private var fill1:Boolean = true;\r
+               private var fill2:Boolean = true;\r
+               \r
+               private var stopped: Boolean = false;\r
+               private var completeEventDispatched: Boolean = false;\r
+               \r
+               public function VorbisSound(url: URLRequest ) {\r
+                       urlStream = new URLStream();\r
+                       urlStream.endian = Endian.LITTLE_ENDIAN;\r
+                       urlStream.load(url);\r
+\r
+                       Mdct.initialize();\r
+\r
+                       oggStream = new UncachedUrlStream(urlStream);\r
+                       oggStream.addEventListener('progress', progress);\r
+                       bytesAvailable = oggStream.bytesAvailable;\r
+                       addEventListener("sampleData", sampleGenerator);\r
+               }\r
+               \r
+               private function initialize():void {\r
+                       vorbisStream = new VorbisStream(oggStream.getLogicalOggStream());\r
+                       setTimeout(dispatchEvent, 100, new Event(METADATA_UPDATE));\r
+                       initialized = true;\r
+               }\r
+               \r
+               private var samplesPlayed: int = 0;\r
+               \r
+               private function sampleGenerator(event:SampleDataEvent):void {\r
+                       \r
+                       if(stopped) {\r
+                               return;\r
+                       }\r
+                       \r
+                       if(Mdct.initialized && !initialized && bytesAvailable > 64*1024) {\r
+                               initialize();\r
+                       }\r
+                       \r
+                       if(initialized && bytesAvailable > 16*1024 && !vorbisStream.finished) {\r
+                               var cnt: int;\r
+                               cnt = vorbisStream.readPcm(event.data);\r
+                               samplesPlayed += cnt;\r
+                               if(cnt < 2048 && oggStream.bytesAvailable > 0) {\r
+                                       vorbisStream = new VorbisStream(oggStream.getLogicalOggStream());\r
+                                       setTimeout(dispatchEvent, 100, new Event(METADATA_UPDATE));\r
+                                       samplesPlayed += vorbisStream.readPcm(event.data);\r
+                               }\r
+                       }\r
+                       else if(vorbisStream == null || !vorbisStream.finished) {\r
+                           for(var c:int=0; c<2048; c++) {\r
+                               event.data.writeFloat(0);\r
+                               event.data.writeFloat(0);\r
+                           }\r
+                       }\r
+                       \r
+                       if(initialized && vorbisStream.finished && oggStream.bytesAvailable == 0 && !completeEventDispatched) {\r
+                               dispatchEvent(new Event(Event.COMPLETE));\r
+                               completeEventDispatched = true;\r
+                       }\r
+                       \r
+                       //trace("samples played: " + samplesPlayed + "/" + oggStream.bytesAvailable);\r
+                       \r
+               }\r
+\r
+               public function stop(): void {\r
+                       stopped = true;\r
+               }\r
+\r
+               public function progress(event:ProgressEvent):void {\r
+                       bytesAvailable = oggStream.bytesAvailable;\r
+               }\r
+\r
+               public function get position(): int {\r
+                       return samplesPlayed * 1000 / 44100;\r
+               }\r
+\r
+               public function getMetaData(key: String):String {\r
+                       if(vorbisStream != null) {\r
+                               return vorbisStream.commentHeader.comments[key];\r
+                       }\r
+                       else {\r
+                               return null;\r
+                       }\r
+               }\r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisStream.as b/js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisStream.as
new file mode 100644 (file)
index 0000000..ea7a208
--- /dev/null
@@ -0,0 +1,130 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis {\r
+\r
+       import flash.events.SampleDataEvent;\r
+       import flash.utils.ByteArray;\r
+       import flash.utils.Endian;\r
+       import org.omtk.util.*;\r
+       import org.omtk.ogg.*;\r
+       \r
+       public class VorbisStream {\r
+       \r
+               private const IDENTIFICATION_HEADER:int = 1;\r
+               private const COMMENT_HEADER:int = 3;\r
+               private const SETUP_HEADER:int = 5;\r
+               \r
+               private var source:LogicalOggStream;\r
+       \r
+               private var _identificationHeader:IdentificationHeader;\r
+               private var _commentHeader:CommentHeader;\r
+               private var _setupHeader:SetupHeader;\r
+               \r
+               private var _lastAudioPacket:AudioPacket;\r
+               \r
+               private var _currentGranulePosition:int=0;\r
+               private var packetCounter:int;\r
+               \r
+               private var _finished: Boolean = false;\r
+               \r
+               public var windows:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(8);\r
+\r
+               public function VorbisStream(source:LogicalOggStream) {\r
+\r
+                       this.source = source;\r
+\r
+                       for (var i:int = 0; i < 3; i++) {\r
+\r
+                               var data:BitByteArray = source.getNextOggPacket().data;\r
+                               var headerType:int = data.readUnsignedByte();\r
+\r
+                               switch(headerType) {\r
+                               case IDENTIFICATION_HEADER:\r
+                                       _identificationHeader = new IdentificationHeader(data);\r
+                                       break;\r
+                               case COMMENT_HEADER:\r
+                                       _commentHeader = new CommentHeader(data);\r
+                                       break;\r
+                               case SETUP_HEADER:\r
+                                       _setupHeader = new SetupHeader(this, data);\r
+                                       break;\r
+                               }\r
+                       }\r
+                       \r
+               }\r
+       \r
+               public function get identificationHeader():IdentificationHeader {\r
+                       return _identificationHeader;\r
+               }\r
+               \r
+               public function get commentHeader():CommentHeader {\r
+                       return _commentHeader;\r
+               }\r
+               \r
+               public function get setupHeader():SetupHeader {\r
+                       return _setupHeader;\r
+               }\r
+       \r
+               public function readPcm(data:ByteArray): int {\r
+               \r
+                       var total:int;\r
+                       var i:int;\r
+                       \r
+                       if(_lastAudioPacket == null) {\r
+                               _lastAudioPacket = getNextAudioPacket();\r
+                       }\r
+\r
+                       total = 0;\r
+                       \r
+                       while(total < 2048 && !_finished) {\r
+                               try {\r
+                                       var ap:AudioPacket = getNextAudioPacket();\r
+                                       total += ap.readPcm(_lastAudioPacket, data);\r
+                                       _lastAudioPacket = ap;\r
+                               }\r
+                               catch(e: EndOfOggStreamError) {\r
+                                       // ok, stream finished\r
+                                       _finished = true;\r
+                               }\r
+                       }\r
+                                               \r
+                       return total;\r
+               }\r
+\r
+               private function getNextAudioPacket():AudioPacket {\r
+                       packetCounter++;\r
+                       var packet:OggPacket = source.getNextOggPacket();\r
+                       var res:AudioPacket = new AudioPacket(this, packet, _currentGranulePosition);\r
+                       if(_lastAudioPacket != null) {\r
+                               // don't count the first packet, since it doesn't contain any "real" samples\r
+                               _currentGranulePosition += res.numberOfSamples;\r
+                       }\r
+                       return res;\r
+               }       \r
+               \r
+               public function get finished() : Boolean {\r
+                       return _finished;\r
+               }\r
+               \r
+               public function get currentGranulePosition(): int {\r
+                       return _currentGranulePosition;\r
+               }\r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/haXe/build.hxml b/js2/mwEmbed/binPlayers/omtk-fx/src/haXe/build.hxml
new file mode 100644 (file)
index 0000000..be51ca9
--- /dev/null
@@ -0,0 +1,3 @@
+-main org.omtk.vorbis.MdctHX
+-swf-version 10
+-swf hxmdct.swf
diff --git a/js2/mwEmbed/binPlayers/omtk-fx/src/haXe/org/omtk/vorbis/MdctHX.hx b/js2/mwEmbed/binPlayers/omtk-fx/src/haXe/org/omtk/vorbis/MdctHX.hx
new file mode 100644 (file)
index 0000000..a932a6f
--- /dev/null
@@ -0,0 +1,337 @@
+/*\r
+\r
+Copyright 2008 Tor-Einar Jarnbjo\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+*/\r
+\r
+package org.omtk.vorbis;\r
+\r
+import flash.Vector;\r
+\r
+class MdctHX {\r
+\r
+       private static var cPI1_8:Float = 0.92387953251128675613;\r
+       private static var cPI2_8:Float = 0.70710678118654752441;\r
+       private static var cPI3_8:Float = 0.38268343236508977175;\r
+       \r
+       private var n:Int;\r
+       private var log2n:Int;\r
+       private var trig:Vector<Float>;\r
+       private var bitrev:Vector<Int>;\r
+       \r
+       private var dtmp1:Float;\r
+       private var dtmp2:Float;\r
+       private var dtmp3:Float;\r
+       private var dtmp4:Float;\r
+\r
+       private var x:Vector<Float>;\r
+       private var w:Vector<Float>;\r
+\r
+       public function new(n:Int) { \r
+               this.n = n;\r
+       \r
+               var i:Int;\r
+               var j:Int;\r
+               \r
+               bitrev = new Vector<Int>();\r
+               trig = new Vector<Float>(Std.int(n+n/4), true);\r
+\r
+               for(i in 0...Std.int(n+n/4)) {\r
+                       trig[i] = 0;\r
+               }\r
+\r
+               x = new Vector<Float>(Std.int(n/2), true);\r
+               w = new Vector<Float>(Std.int(n/2), true);\r
+\r
+               for(i in 0...Std.int(n/2)) {\r
+                       x[i] = 0;\r
+                       w[i] = 0;\r
+               }\r
+               \r
+               var n2:Int = n >>> 1;\r
+               log2n = Math.round(Math.log(n) / Math.log(2));\r
+\r
+               var AE:Int = 0;\r
+               var AO:Int = 1;\r
+               var BE:Int = Std.int(AE + n / 2);\r
+               var BO:Int = BE + 1;\r
+               var CE:Int = Std.int(BE + n / 2);\r
+               var CO:Int = CE + 1;\r
+               \r
+               for (i in 0...Std.int(n/4)) {\r
+                       trig[AE + i * 2] = Math.cos((Math.PI / n) * (4 * i));\r
+                       trig[AO + i * 2] = -Math.sin((Math.PI / n) * (4 * i));\r
+                       trig[BE + i * 2] = Math.cos((Math.PI / (2 * n)) * (2 * i + 1));\r
+                       trig[BO + i * 2] = Math.sin((Math.PI / (2 * n)) * (2 * i + 1));\r
+               }\r
+\r
+               for (i in 0...Std.int(n/8)) {\r
+                       trig[CE + i * 2] = Math.cos((Math.PI / n) * (4 * i + 2));\r
+                       trig[CO + i * 2] = -Math.sin((Math.PI / n) * (4 * i + 2));\r
+               }\r
+               \r
+               var mask:Int = (1 << (log2n - 1)) - 1;\r
+               var msb:Int = 1 << (log2n - 2);\r
+               \r
+               for (i in 0...Std.int(n/8)) {\r
+                       var acc:Int = 0;\r
+                       j = 0;\r
+                       while(msb>>>j!=0) {\r
+                               if (((msb >>> j) & i) != 0) {\r
+                                       acc |= 1 << j;\r
+                               }\r
+                               j++;\r
+                       }\r
+                       bitrev[i * 2] = ((~acc) & mask);\r
+                       bitrev[i * 2 + 1] = acc;\r
+               }\r
+               \r
+       } \r
+\r
+       public function imdct(frq:Vector<Float>, window:Vector<Float>, pcm:Vector<Float>):Void {\r
+       \r
+               var i:Int;\r
+\r
+               var n2:Int;\r
+               var n4:Int;\r
+               var n8:Int;\r
+\r
+               var inO:Int;\r
+               var xO:Int;\r
+               var A:Int;\r
+\r
+               var temp1:Float;\r
+               var temp2:Float;\r
+\r
+               var B:Int;\r
+               var o1:Int;\r
+               var o2:Int;\r
+               var o3:Int;\r
+               var o4:Int;\r
+\r
+               var xx:Int;\r
+               var xxx:Vector<Float>;\r
+               \r
+               n2 = n >> 1;\r
+               n4 = n >> 2;\r
+               n8 = n >> 3;\r
+\r
+               inO = -1;\r
+               xO = 0;\r
+               A = n2;\r
+               \r
+               temp1 = 0.0;\r
+               temp2 = 0.0;\r
+               \r
+               for (i in 0...n8) {\r
+                       dtmp1 = frq[inO += 2];\r
+                       dtmp2 = frq[inO += 2];\r
+                       dtmp3 = trig[--A];\r
+                       dtmp4 = trig[--A];\r
+                       x[xO++] = -dtmp2 * dtmp3 - dtmp1 * dtmp4;\r
+                       x[xO++] = dtmp1 * dtmp3 - dtmp2 * dtmp4;\r
+               }\r
+\r
+               inO = n2;\r
+\r
+               for(i in 0...n8) {\r
+                       dtmp1 = frq[inO -= 2];\r
+                       dtmp2 = frq[inO -= 2];\r
+                       dtmp3 = trig[--A];\r
+                       dtmp4 = trig[--A];\r
+                       x[xO++] = dtmp2 * dtmp3 + dtmp1 * dtmp4;\r
+                       x[xO++] = dtmp2 * dtmp4 - dtmp1 * dtmp3;\r
+               }\r
+\r
+               xxx = kernel(x, w, n, n2, n4, n8);\r
+               xx = 0;\r
+               \r
+               B = n2;\r
+               o1 = n4;\r
+               o2 = o1 - 1;\r
+               o3 = n4 + n2;\r
+               o4 = o3 - 1;\r
+\r
+               for (i in 0...n4) {\r
+                       dtmp1 = xxx[xx++];\r
+                       dtmp2 = xxx[xx++];\r
+                       dtmp3 = trig[B++];\r
+                       dtmp4 = trig[B++];\r
+\r
+                       temp1 = (dtmp1 * dtmp4 - dtmp2 * dtmp3);\r
+                       temp2 = -(dtmp1 * dtmp3 + dtmp2 * dtmp4);\r
+\r
+                       pcm[o1] = -temp1 * window[o1];\r
+                       pcm[o2] = temp1 * window[o2];\r
+                       pcm[o3] = temp2 * window[o3];\r
+                       pcm[o4] = temp2 * window[o4];\r
+\r
+                       o1++;\r
+                       o2--;\r
+                       o3++;\r
+                       o4--;\r
+               }\r
+               \r
+       }\r
+\r
+       private inline function kernel(x:Vector<Float>, w:Vector<Float>, n:Int, n2:Int, n4:Int, n8:Int):Vector<Float> {\r
+\r
+               var i:Int;\r
+               var r:Int;\r
+               var s:Int;\r
+               var rlim:Int;\r
+               var slim:Int;\r
+               \r
+               var xA:Int = n4;\r
+               var xB:Int = 0;\r
+               var w1:Int = 0;\r
+               var w2:Int = n4;\r
+               var A:Int = n2;\r
+\r
+               var x0:Float;\r
+               var x1:Float;\r
+               var wA:Float;\r
+               var wB:Float;\r
+               var wC:Float;\r
+               var wD:Float;\r
+               var k0:Int;\r
+               var k1:Int;\r
+               var t1:Int;\r
+               var t2:Int;\r
+               \r
+               var wbase:Int;\r
+               var temp:Vector<Float>;\r
+               \r
+               var wACE:Float;\r
+               var wBCE:Float;\r
+               var wACO:Float;\r
+               var wBCO:Float;\r
+                       \r
+               var AEv:Float;\r
+               var AOv:Float;\r
+                       \r
+               i=0;\r
+               while(i < n4) {\r
+                       x0 = x[xA] - x[xB];\r
+                       \r
+                       w[w2 + i] = x[xA++] + x[xB++];\r
+\r
+                       x1 = x[xA] - x[xB];\r
+                       A -= 4;\r
+\r
+                       w[i++] = x0 * trig[A] + x1 * trig[A + 1];\r
+                       w[i] = x1 * trig[A] - x0 * trig[A + 1];\r
+\r
+                       w[w2 + i] = x[xA++] + x[xB++];\r
+                       i++;\r
+               }\r
+\r
+               for (i in 0...log2n-3) {\r
+                       k0 = n >>> (i + 2);\r
+                       k1 = 1 << (i + 3);\r
+                       wbase = n2 - 2;\r
+\r
+                       A = 0;\r
+\r
+                       rlim = k0 >>> 2;\r
+                       for (r in 0...rlim) {\r
+                       \r
+                               w1 = wbase;\r
+                               w2 = w1 - (k0 >> 1);\r
+                               AEv = trig[A];\r
+                               AOv = trig[A + 1];\r
+                               wbase -= 2;\r
+\r
+                               k0++;\r
+                               \r
+                               slim = 2 << i;\r
+                               for (s in 0...slim) {\r
+                                       dtmp1 = w[w1];\r
+                                       dtmp2 = w[w2];\r
+                                       wB = dtmp1 - dtmp2;\r
+                                       x[w1] = dtmp1 + dtmp2;\r
+                                       dtmp1 = w[++w1];\r
+                                       dtmp2 = w[++w2];\r
+                                       wA = dtmp1 - dtmp2;\r
+                                       x[w1] = dtmp1 + dtmp2;\r
+                                       x[w2] = wA * AEv - wB * AOv;\r
+                                       x[w2-1] = wB * AEv + wA * AOv;\r
+                                       w1 -= k0;\r
+                                       w2 -= k0;\r
+                               }\r
+                               k0--;\r
+                               A += k1;\r
+                       }\r
+\r
+                       temp = w;\r
+                       w = x;\r
+                       x = temp;\r
+               }\r
+               \r
+\r
+               var C:Int = n;\r
+               var bit:Int = 0;\r
+               var xx1:Int = 0;\r
+               var xx2:Int = n2 - 1;\r
+               \r
+               var wt1: Float;\r
+               var wt2: Float;\r
+               var wt12: Float;\r
+               var wt21: Float;\r
+               var trigV: Float;\r
+\r
+               for (i in 0...n8) {\r
+                       t1 = bitrev[bit++];\r
+                       t2 = bitrev[bit++];\r
+                       \r
+                       wt1 = w[t1];\r
+                       wt2 = w[t2];\r
+                       wt12 = w[t1-1];\r
+                       wt21 = w[t2+1];\r
+\r
+                       wA = wt1 - wt21;\r
+                       wB = wt12 + wt2;\r
+                       wC = wt1 + wt21;\r
+                       wD = wt12 - wt2;\r
+                       \r
+                       trigV = trig[C];\r
+\r
+                       wACE = wA * trigV;\r
+                       wBCE = wB * trigV;\r
+                       \r
+                       trigV = trig[++C];\r
+                       \r
+                       wACO = wA * trigV;\r
+                       wBCO = wB * trigV;\r
+                       \r
+                       ++C;\r
+\r
+                       x[xx1++] = (wC + wACO + wBCE);\r
+                       x[xx2--] = (-wD + wBCO - wACE);\r
+                       x[xx1++] = (wD + wBCO - wACE);\r
+                       x[xx2--] = (wC - wACO - wBCE);\r
+               }\r
+\r
+               return x;\r
+       }       \r
+\r
+       /*\r
+        * Dummy function required for the haXe compiler to build this to\r
+        * a .SWF file.\r
+        */\r
+       public static function main() : Void {  \r
+       }\r
+       \r
+}\r
diff --git a/js2/mwEmbed/example_usage/Add_Media_Wizard.html b/js2/mwEmbed/example_usage/Add_Media_Wizard.html
new file mode 100644 (file)
index 0000000..a05b53b
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>sample mv embed</title>
+       <style type="text/css">
+               body{
+                       font-size:80%;
+               }
+               img  {
+                       border:medium none;
+               }
+       </style>
+       <script type="text/javascript" src="../mv_embed.js?debug=true"></script>                 
+       <script type="text/javascript">
+       mwAddOnloadHook(function(){
+               $j('#add_media_link').addMediaWiz( {
+                       'profile':'html_edit',                  
+                       'target_textbox': '#wpTextbox1',
+                       'target_render_area':'#inline_append',                  
+                       'import_url_mode':'remote_link',        
+                       //note selections in the textbox will take over the default query
+                       'default_query': 'fish',        
+                       //here we can setup the conten provider overides
+                       'cpconfig': {},                                 
+                       
+                       //the local wiki api url: 
+                       'local_wiki_api_url': 'none'
+               });                     
+       });     
+       
+       </script> 
+</head>
+<body>
+<h3> Sample Add Media Wizard </h3>
+
+<a id="add_media_link" href="#">Add Media</a><br>
+<table border="1" width="800">
+<tr>
+<td valign="top" width="50%" id="inline_append">Asset Output</td>
+<td  valign="top" width="50%" >Html Output:<textarea id="wpTextbox1" cols="60" rows="6" id="code_append" name="wpTextbox1" tabindex="3"/></textarea></td>
+</tr>
+</table>
+</body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/Firefogg_Make_Advanced.html b/js2/mwEmbed/example_usage/Firefogg_Make_Advanced.html
new file mode 100644 (file)
index 0000000..669bf12
--- /dev/null
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <title>Firefogg - Make Ogg Video in your Browser</title>    
+       <script type="text/javascript" src="../jsScriptLoader.php?debug=true&class=mv_embed,window.jQuery,mvBaseUploadInterface,mvFirefogg,mvAdvFirefogg,$j.ui,$j.ui.progressbar,$j.ui.dialog,$j.cookie,$j.ui.accordion,$j.ui.slider,$j.ui.datepicker"></script>                 
+<style type="text/css" media="all">body {
+  margin: 0;
+  padding: 0;
+  font-family: Vera Sans, sans-serif;
+  font-size: 12px;
+  color: #000;
+  background: #fff;
+}
+
+a {
+  color: #000;
+}
+img {
+  border: 0;
+}
+h1, h2 {
+  text-align: center;
+}
+h1 {
+  font-size: 48px;
+  letter-spacing: 0.25em;
+  margin-bottom: 0;
+  line-height: 0.8em;
+}
+h2 {
+  margin-left: -11px;
+  font-size: 12px;
+  font-weight: normal;
+  letter-spacing: 0.1em;
+}
+
+#main {
+  margin-top: 10px;
+}
+
+.install {
+  margin-left: auto;
+  margin-right: auto;
+  width: 180px;
+  padding: 8px;
+  background-color: #fe0000;
+  font-size: 12px;
+  font-weight: bold;
+  text-align: center;
+}
+
+.install a {
+  color: #000;
+}
+
+#nav {
+  margin-left: -11px;
+  text-align: center;
+  padding-bottom: 20px;
+}
+</style>
+<style type="text/css" media="all">
+.install{
+display:none;
+}
+</style>
+<script type="text/javascript">
+mwAddOnloadHook(function(){
+       $j('#firefogg_app').firefogg({
+                       'encoder_interface'     : true,
+                       'encode_local'          : true
+       },function(){
+               $j('#loadFogg').hide();
+       });             
+       $j('#doThemeRoller').click(function(){
+               if(window.jquitr){ 
+                       jquitr.addThemeRoller(); 
+               } else{ 
+                       loadExternalJs('http://jqueryui.com/themeroller/developertool/developertool.js.php');                   
+               }
+       }).html('custom themes');       
+});
+</script>
+</head><body>
+<div id="main">
+  <h1><a href="http://www.firefogg.org/index.html"><img 
+src="http://www.firefogg.org/png/firefogg.png" alt="Firefogg"></a><br>
+Make Ogg Video</h1>
+<br>   
+       <br>
+       <div style="margin-right:auto;margin-left:auto;width:500px;" id="loadFogg">Loading firefogg<blink>...</blink></div>     
+       <div style="margin-right:auto;margin-left:auto;width:500px;height:250px"  id="firefogg_app"></div>
+       
+       <div style="height:250px"></div>
+       <center><span style="font:size:80%">Built using <a href="http://firefogg.org">firefogg</a>, <a href="http://www.mediawiki.org/wiki/Media_Projects_Overview#MwEmbed">MwEmbed</a> and <a href="http://jqueryui.com/">jquery.ui</a>. Supports  
+               <a href="#" id="doThemeRoller">...</a>
+       </span>
+       </center>
+</body></html>
+
diff --git a/js2/mwEmbed/example_usage/Firefogg_Make_Simple.html b/js2/mwEmbed/example_usage/Firefogg_Make_Simple.html
new file mode 100644 (file)
index 0000000..fb3bab3
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <title>Firefogg - Make Ogg Video in your Browser</title>
+       <!--  <script type="text/javascript" src="../jsScriptLoader.php?class=mv_embed&urid=da&debug=true"></script> -->
+       <script type="text/javascript" src="../mv_embed.js"></script> 
+<style type="text/css" media="all">@import "http://www.firefogg.org/css/style.css";</style>
+<style type="text/css" media="all">
+.install{
+display:none;
+}
+input{
+font-size:150%;
+}
+</style>
+<script type="text/javascript">
+mwAddOnloadHook(function(){
+       $j('#control_container').firefogg({
+                       'encoder_interface'     : false,
+                       'encode_local'          : true
+       }, function(){
+               $j('#loadFogg').hide();
+       });     
+});
+</script>
+</head><body>
+<div id="main">
+  <h1><a href="http://www.firefogg.org/index.html"><img 
+src="http://www.firefogg.org/png/firefogg.png" alt="Firefogg"></a><br>
+Make Ogg Video</h1>
+<br><br><br>
+<center>
+       <div style="width:500px">
+               <span id="loadFogg">Loading firefogg <blink>...</blink></span>
+               <div style="float:left;height:400px" id="control_container"></div>
+       <br><br>
+       </div>
+</center>
+</body></html>
diff --git a/js2/mwEmbed/example_usage/Firefogg_ReWriteForm.php b/js2/mwEmbed/example_usage/Firefogg_ReWriteForm.php
new file mode 100644 (file)
index 0000000..b90a048
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+if($_FILES){
+       print "file uploaded oky:<pre>";
+       print_r($_FILES);
+       print "</pre>";
+       die();
+}
+?>
+
+<!DOCTYPE HTML>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <title>Firefogg - Make Ogg Video in your Browser</title>   
+       <script type="text/javascript" src="../mv_embed.js?debug=true"></script> 
+<style type="text/css" media="all">@import "http://www.firefogg.org/css/style.css";</style>
+<style type="text/css" media="all">
+.install{
+display:none;
+}
+input{
+font-size:110%;
+}
+</style>
+<script type="text/javascript">
+mwAddOnloadHook(function(){
+       $j('#fogg-file').firefogg();    
+});
+</script>
+</head><body>
+<div id="main">
+  <h1>Rewrite Form example</h1>
+<br><br><br>
+<center>
+       <div style="width:500px">               
+               <!--  we submit it to ourselves (ie do nothing)  -->
+               <form action="Firefogg_ReWriteForm.php" method="POST" enctype='multipart/form-data'>
+               <table> 
+                       <tr><td>
+                 Video Name:</td><td> <input type="text" name="fname" /></td>
+                       </tr>
+                       <tr>
+                 <td>Video File :</td><td> <input type="file" name="fogg-file" id="fogg-file"/></td>
+                 </tr>
+                 <tr>
+                 <td>
+                 <input type="submit" value="Submit" />
+                 </td>
+                 </tr>
+                </table>
+               </form>
+       <br><br>
+       </div>
+</center>
+</body></html>
diff --git a/js2/mwEmbed/example_usage/Player_Remote_Content_ogg_flv.html b/js2/mwEmbed/example_usage/Player_Remote_Content_ogg_flv.html
new file mode 100644 (file)
index 0000000..503f852
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>remote_metavid_ogg_flv_timed_text</title>
+       <script type="text/javascript" src="../mv_embed.js"></script>
+</head>
+<body>
+<h3> Remote Metavid Embed with Timed Text over ROE xml (json encapuslated) </h3>
+
+<span id="default_attr">
+</span> <br />
+<br />
+  <table border="1" cellpadding="6" width="600">
+                   <tr>
+             <td valign="top"><video  id="embed_vid" 
+thumbnail="http://metavid.org/wiki/index.php?action=ajax&rs=mv_frame_server&stream_id=501&t=0:01:32&amp;size=400x300" 
+roe="http://metavid.org/wiki/index.php?title=Special:MvExportStream&stream_name=House_proceeding_01-28-08&feed_format=roe&t=0:01:32/0:03:20" 
+style="width:400px;height:300px" 
+controls="true" embed_link="true" >    
+       <source type="video/x-flv" src="http://mvbox2.cse.ucsc.edu/mvFlvServer.php/house_proceeding_01-28-08.flv?t=0:01:32/0:03:20"></source>
+       <source type="video/ogg" src="http://metavidstorage01.ucsc.edu/media/house_proceeding_01-28-08.ogg?t=0:01:32/0:03:20"></source>
+
+</video></td>
+             <td valign="top"><b>Sample Embed 0</b><br />
+             Sample Similar to <a href="http://metavid.org">metavid usage</a><br />
+             &lt;-- code used: <br />
+            <pre> &lt;video  id=&quot;embed_vid&quot; 
+thumbnail=&quot;http://metavid.org/wiki/index.php?action=ajax&amp;rs=mv_frame_server&amp;stream_id=501&amp;t=0:01:32&amp;amp;size=400x300&quot; 
+
+roe=&quot;http://metavid.org/wiki/index.php?title=Special:MvExportStream&amp;stream_name=House_proceeding_01-28-08&amp;feed_format=roe&amp;t=0:01:32/0:03:20&quot; 
+style=&quot;width:400px;height:300px&quot; 
+controls=&quot;true&quot; embed_link=&quot;true&quot; &gt;     
+       &lt;source type=&quot;video/x-flv&quot; src=&quot;http://mvbox2.cse.ucsc.edu/mvFlvServer.php/house_proceeding_01-28-08.flv?t=0:01:32/0:03:20&quot;&gt;&lt;/source&gt;
+
+       &lt;source type=&quot;video/ogg&quot; src=&quot;http://metavidstorage01.ucsc.edu/media/house_proceeding_01-28-08.ogg?t=0:01:32/0:03:20&quot;&gt;&lt;/source&gt;
+&lt;/video&gt;</pre>
+             </td>
+             </table>
+       <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />&nbsp;
+  </body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/Player_Simple_Video_Tag.html b/js2/mwEmbed/example_usage/Player_Simple_Video_Tag.html
new file mode 100644 (file)
index 0000000..60a791f
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>Simple Video Tag Usage</title>
+       <script type="text/javascript" src="../mv_embed.js?debug=true"></script>
+</head>
+<body>
+<h3> Simple Video Tag Usage </h3>
+once you include: mv_embed.js on any remote page you can then use the video tag like so: 
+<span id="default_attr">
+</span> <br />
+<br />
+  <table border="1" cellpadding="6" width="600">
+                   <tr>
+             <td valign="top"><video duration="26" poster="http://metavid.org/w/index.php?action=ajax&rs=mv_frame_server&stream_id=71&t=1:23:16&size=400x300" src="http://metavidstorage01.ucsc.edu/media/house_proceeding_07-18-06_00.ogg?t=1:23:16/1:23:44"></video></video></td>
+             <td valign="top"><b>Sample Embed</b><br />
+             Simple video Embed: 
+               <pre>&lt;video poster="http://metavid.org/w/index.php?action=ajax&rs=mv_frame_server&stream_id=71&t=1:23:16&size=400x300" 
+src="http://metavidstorage01.ucsc.edu/media/house_proceeding_07-18-06_00.ogg?t=1:23:16/1:23:44"&gt;&lt;/video&gt;</pre>
+             </td>
+             </table>
+       <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />&nbsp;
+  </body>
+</html>        
+
diff --git a/js2/mwEmbed/example_usage/Player_Themable.html b/js2/mwEmbed/example_usage/Player_Themable.html
new file mode 100644 (file)
index 0000000..e7d3167
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>Sample Themed Player</title>
+       <script type="text/javascript" src="../mv_embed.js?debug=true"></script>         
+</head>
+<script type="text/javascript">
+mwAddOnloadHook(function(){
+       $j('#doThemeRoller').click(function(){
+               if(window.jquitr){ 
+                       jquitr.addThemeRoller(); 
+               } else{
+                       loadExternalJs('http://jqueryui.com/themeroller/developertool/developertool.js.php');                   
+               }
+       }).html('<span class="ui-icon ui-icon-newwin"/>Run Theme Roller</span>');
+});
+</script>
+<body bgcolor="#FFF">
+<h3> Sample Themed Player:</h3>
+<a id="doThemeRoller" class="ui-icon_link ui-state-default ui-corner-all" href="#">loading theme editor<blink>...</blink></a><p><p>
+<video src="media/sample_fish.ogg" thumbnail="media/sample_fish.jpg" durationHint="26"></video>        
+ </table>
+
+</body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/Player_Timed_Text.html b/js2/mwEmbed/example_usage/Player_Timed_Text.html
new file mode 100644 (file)
index 0000000..9caa925
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>sample mv embed</title>
+       <script type="text/javascript" src="../mv_embed.js?debug=true"></script>                 
+</head>
+<body>
+<h3> Mv_Embed Timed Text Examples:</h3>
+Click on the little lower right "CC" icon to expose the timed text
+ <table border="1" cellpadding="6" width="950">
+       <tr>            
+               <td valign="top" width="410">
+
+                       <video roe="http://metavid.org/w/index.php?title=Special:MvExportStream&stream_name=House_proceeding_07-18-06_00&t=1:23:16/1:23:44&feed_format=roe" ></video>           </td>
+               <td valign="top">
+                       Metavid based ROE file using CMML<br> <pre>&lt;video roe=&quot;http://metavid.org/w/index.php?title=Special:MvExportStream&amp;stream_name=House_proceeding_07-18-06_00&amp;t=1:23:16/1:23:44&amp;feed_format=roe&quot; &gt;&lt;/video&gt;</pre><iframe width="600" height="250" src="http://metavid.org/w/index.php?title=Special:MvExportStream&stream_name=House_proceeding_07-18-06_00&t=1:23:16/1:23:44&feed_format=roe" ></iframe>                </td>
+
+       </tr>
+       <tr>            
+               <td valign="top" width="410">
+               <video poster="http://ia340929.us.archive.org/0/items/princess_iron_fan/princess_iron_fan.thumbs/princess_iron_fan_000360.jpg"
+               duration="1:13:0" linkback="http://www.archive.org/details/princess_iron_fan" >
+                       <source type="video/ogg" src="http://www.archive.org/download/princess_iron_fan/princess_iron_fan.ogv" ></source>
+                       <source type="video/h264" src="http://www.archive.org/download/princess_iron_fan/princess_iron_fan_512kb.mp4"></source>
+                       <text category="SUB" lang="en" type="text/x-srt" default="true"
+                               title="English subtitles" src="media/princess_archive_org/princess_iron_fan.srt">
+                       </text>
+                       <text category="SUB" lang="cs" type="text/x-srt"
+                               title="Czech subtitles" src="media/princess_archive_org/princess_iron_fan-cs.srt">
+                       </text>
+                       <text category="SUB" lang="ru" type="text/x-srt"
+                               title="Russian subtitles" src="media/princess_archive_org/princess_iron_fan-ru.srt">
+                       </text>
+               </video>                
+               </td>
+
+               <td valign="top">
+                       <h4>Archive.org video with local SRTs (copied locally until we get srt over json for archive.org ;)</h4> 
+                       <textarea cols="120" rows="12">
+<video poster="http://www.archive.org/download/princess_iron_fan/format=thumbnail"  URLTimeEncoding="true"
+       duration="1:13:0" linkback="http://www.archive.org/details/princess_iron_fan">
+               <source type="video/ogg" src="http://www.archive.org/download/princess_iron_fan/princess_iron_fan.ogv"></source>
+               <source type="video/h264" src="http://www.archive.org/download/princess_iron_fan/princess_iron_fan_512kb.mp4"></source>
+       <text category="SUB" lang="en" type="text/x-srt" default="true"
+               title="English subtitles" src="media/princess_archive_org/princess_iron_fan.srt">
+       </text>
+       <text category="SUB" lang="cs" type="text/x-srt"
+               title="Czech subtitles" src="media/princess_archive_org/princess_iron_fan-cs.srt">
+       </text>
+       <text category="SUB" lang="ru" type="text/x-srt"
+               title="Russian subtitles" src="media/princess_archive_org/princess_iron_fan-ru.srt">
+       </text>
+</video> 
+                       </textarea>             </td>
+       </tr>
+ </table>
+
+</body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/README b/js2/mwEmbed/example_usage/README
new file mode 100644 (file)
index 0000000..4339941
--- /dev/null
@@ -0,0 +1 @@
+@@Example usage of mv_embed
diff --git a/js2/mwEmbed/example_usage/Sequence_Editor.html b/js2/mwEmbed/example_usage/Sequence_Editor.html
new file mode 100644 (file)
index 0000000..d6f79e0
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>SMIL Sequence Editor example</title>
+       <script type="text/javascript" src="../mv_embed.js?debug=true"></script>
+       <script type="text/javascript">
+               mwAddOnloadHook(function(){
+                       $j('#seqcontainer').sequencer({
+                       'mv_pl_src':'media/sample_smil.xml'                     
+               });
+               });
+       </script>
+<style>
+       body {
+               font: x-small sans-serif;
+               background: #f9f9f9 url(headbg.jpg) 0 0 no-repeat;
+               color: black;
+               margin: 0;
+               padding: 0;
+       }
+       img {
+                       border:medium none;
+               }
+</style>
+       
+</head>
+<body>
+<h3> Simple SMIL example</h3>
+       <div id="seqcontainer" style="position:absolute;top:50px;bottom:10px;left:10px;right:10px;">
+               Loading sequence editor <blink>...</blink>
+       </div>
+       
+  </body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/SequencerPlayer_Seeking.html b/js2/mwEmbed/example_usage/SequencerPlayer_Seeking.html
new file mode 100644 (file)
index 0000000..a420fb6
--- /dev/null
@@ -0,0 +1,78 @@
+<!doctype html>
+<html>
+<head>
+    <title>mv_embed Seeking Example</title>
+         <script type="text/javascript" src="../mv_embed.js?debug=true"></script>      
+  <style>
+    #render_box {
+      position:absolute;
+      width:400px;
+      height:300px;
+    }
+    #frame_overlay {
+      position:absolute;
+      width:400px;
+      height:300px;
+      top: 28px;
+      left: 9px;
+    }
+
+  </style>
+  <script>
+var pos = 0;
+var duration = 2;
+var step = 0.04;
+var render = false;
+
+function renderNext() {
+  $j('#pos').val(pos);
+  document.getElementById('render_box').setCurrentTime(pos, function(currentTime) {
+      return function() {
+        //ogg.addFrame('frame_overlay');
+        pos += step;
+        if(render && pos <= duration)
+          renderNext();
+      };
+  }(pos));
+}
+
+function startRender() {
+  //ogg = new Firefogg();
+  //ogg.initRender('{"videoQuality": 10, "framerate": 25, "width": 400, "height": 300}', 'sample_smil.ogv');
+  $j("#buttonStart").attr("disabled", true); 
+  if(!render) {
+      //document.getElementById('render_box').play();
+      //document.getElementById('render_box').pause();
+      setTimeout(function() {
+        //duration = document.getElementById('render_box').getDuration();
+        render = true;
+        pos = 0;
+        renderNext();
+      }, 1000);
+  }
+}
+function stopRender() {
+  render = false;
+  $j("#buttonStart").attr("disabled", false); 
+  $j("#buttonSop").attr("disabled", true); 
+}
+function seek() {
+  var seekTo = $j('#pos').val();
+  document.getElementById('render_box').setCurrentTime(seekTo, function() { js_log('seeked'); });
+}
+  </script>
+</head>
+<body>
+<playlist id="render_box" src="media/sample_smil.xml" controls="false"></playlist>
+<div id="frame_overlay"></div>
+
+<div id="info" style="position: absolute; top:360px">
+    <button onclick="startRender()" id="buttonStart">Start</button>
+    <button onclick="stopRender()" id="buttonStart">Stop</button>
+    position: <input type="text" id="pos" value="6.6" />
+    <button onclick="seek()">seek</button>
+    <span id="status"></span><br>
+</div>
+</body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/SequencerPlayer_Simple.html b/js2/mwEmbed/example_usage/SequencerPlayer_Simple.html
new file mode 100644 (file)
index 0000000..ede6795
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>Simple SMIL example</title>
+       <script type="text/javascript" src="../mv_embed.js"></script>
+</head>
+<body>
+<h3> Simple SMIL example</h3>
+
+<span id="default_attr">
+</span> <br />
+<br />
+  <table border="1" cellpadding="6" width="600">
+                   <tr>
+             <td valign="top"><playlist id="smil_pl" src="media/sample_smil.xml"></td>
+
+             <td valign="top"><b>Sample Embed 8</b><br />
+              <br><b>Crossfading Videos</b><br/>
+                       The first video fades up from green when it starts to play, 
+                       and the second video fades down to green when it ends. 
+                       When the first video stops and the second video starts, 
+                       though, the two videos crossfade into each other<br><iframe width="500" height="200" src="media/sample_smil.xml">sample smil here</iframe><br />
+             &lt;-- code used: <br />
+            <pre> &lt;playlist id=&quot;smil_pl&quot; src=&quot;media/sample_smil.xml&quot;&gt;</pre>
+
+             </td>
+           </tr>
+
+             </table>
+       <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />&nbsp;
+  </body>
+</html>
+
diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-cs.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-cs.srt
new file mode 100644 (file)
index 0000000..6cc0494
--- /dev/null
@@ -0,0 +1,1397 @@
+1
+00:00:01,080 --> 00:00:09,070
+Princezna Železný Vějíř
+
+2
+00:02:03,109 --> 00:02:09,280
+Cesta na Východ je báječný dětský příběh,
+
+3
+00:02:09,280 --> 00:02:15,280
+ale svět ho často chybně označuje jako fantasy román.
+
+4
+00:02:15,280 --> 00:02:19,240
+Tento film byl vyroben za účelem
+
+5
+00:02:19,240 --> 00:02:24,240
+tréninku dětských srdcí a myslí.
+
+6
+00:02:24,240 --> 00:02:29,280
+Příběh je pravý, nezkažený fantazií.
+
+7
+00:02:29,280 --> 00:02:32,560
+Ohnivá hora, která brání v cestě skupině Tanga Senga
+
+8
+00:02:32,560 --> 00:02:41,039
+je metafora pro obtíže v životě.
+
+9
+00:02:41,039 --> 00:02:46,439
+Abychom je překonali, musíme si uchovat víru.
+Musíme spolupracovat
+
+10
+00:02:46,439 --> 00:02:52,430
+abychom získali vějíř z palmových listů a udusili plameny.
+
+11
+00:02:52,839 --> 00:02:58,178
+Tripikata True Sutra
+
+12
+00:03:34,479 --> 00:03:37,789
+Už je přece podzim. Jakto, že je pořád takové vedro?
+
+13
+00:03:37,840 --> 00:03:42,349
+Hlupáku, neplácej nesmysly. Musíme si pospíšit a postupovat dál.
+
+14
+00:04:06,919 --> 00:04:09,349
+Wukongu, kde je to místo?
+
+15
+00:04:09,400 --> 00:04:13,669
+Musíme přejít tudy a dál na západ. Zaručeně.
+
+16
+00:04:13,719 --> 00:04:18,110
+A nemohli jsme zabloudit? 
+
+17
+00:04:18,149 --> 00:04:21,700
+Proč je tu takové horko?
+
+18
+00:04:30,029 --> 00:04:31,649
+Mistře, podívejte!
+
+19
+00:04:31,650 --> 00:04:33,779
+Není to domek? Tam nahoře...
+
+20
+00:04:33,829 --> 00:04:38,100
+Pojďme si dovnitř na chvilku odpočinout. Souhlasíte?
+
+21
+00:04:59,389 --> 00:05:02,899
+Tohle místo se nazývá Ohnivá hora.
+
+22
+00:05:02,949 --> 00:05:06,019
+Oheň dosahuje stovky mil daleko.
+
+23
+00:05:06,069 --> 00:05:08,740
+Ani jediné stéblo trávy zde nemůže vyrůst.
+
+24
+00:05:08,790 --> 00:05:11,620
+Všechny čtyři roční období je tu horko.
+
+25
+00:05:11,680 --> 00:05:19,629
+Přes horu by nešlo projít ani s měděnou hlavou ani s železnýma rukama.
+
+26
+00:05:19,670 --> 00:05:23,579
+Co je tohle jenom za místo? Mistře, nebojte.
+
+27
+00:05:23,629 --> 00:05:27,139
+My tři jsme dost silní abychom dokázali projít.
+
+28
+00:05:27,189 --> 00:05:30,699
+Mistře, půjdu a podívám se na to.
+
+29
+00:08:06,310 --> 00:08:09,579
+Wukongu, jaké to bylo?
+
+30
+00:08:09,629 --> 00:08:11,819
+Špatné, špatné, moc špatné.
+
+31
+00:08:11,879 --> 00:08:15,910
+Kdybych byl jenom trochu pomalejší, měl bych kůži na ocase spálenou.
+
+32
+00:08:42,720 --> 00:08:47,600
+Urozený hostiteli, ohně jsou zde tak velké.
+
+33
+00:08:47,600 --> 00:08:49,669
+Jak zde mohou vyrůst nějaké plodiny?
+
+34
+00:08:49,710 --> 00:08:53,980
+Tisíc mil odsud žije princezna Železný Vějíř.
+
+35
+00:08:54,039 --> 00:08:56,500
+Ona má vějíř z palmových listů.
+
+36
+00:08:56,559 --> 00:08:59,070
+Zamávej s ním jednou a oheň ustane.
+
+37
+00:08:59,120 --> 00:09:01,629
+Dvakrát a začne foukat vítr.
+
+38
+00:09:01,679 --> 00:09:03,980
+Třikrát a spustí se déšť.
+
+39
+00:09:04,039 --> 00:09:07,509
+V nadcházejícím období pak pěstujeme a sklízíme.
+
+40
+00:09:07,559 --> 00:09:11,340
+Nicméně... požádat, aby princezna přišla
+
+41
+00:09:11,399 --> 00:09:14,870
+není tak úplně jednoduché.
+
+42
+00:09:14,909 --> 00:09:16,820
+Kde ona žije?
+
+43
+00:09:16,879 --> 00:09:20,190
+Žije v jeskyni Palmových Listů v hoře Smaragdových Mračen.
+
+44
+00:09:20,240 --> 00:09:23,669
+Žije tam sama?
+
+45
+00:09:23,720 --> 00:09:25,750
+Ona nemá manžela?
+
+46
+00:09:25,799 --> 00:09:29,580
+Její manžel je Král, Býčí Démon.
+
+47
+00:09:29,639 --> 00:09:32,200
+Cože? Její manžel je Starý Býk?
+
+48
+00:09:32,240 --> 00:09:36,789
+Hlupáku, ty ho znáš? Pojď si se mnou vypůjčit ten vějíř!
+
+49
+00:09:36,840 --> 00:09:41,750
+Vlastně... Starý Býk tam nežije.
+
+50
+00:09:41,799 --> 00:09:46,350
+Vyhledávat jeho ženu, když on není doma
+
+51
+00:09:46,399 --> 00:09:51,519
+není moc ... vhodné.
+
+52
+00:09:51,559 --> 00:09:58,309
+Ty... ty... Vy dva, jděte už.
+
+53
+00:09:58,360 --> 00:10:04,290
+Já... Já zůstanu a postarám se o mistra.
+
+54
+00:10:04,440 --> 00:10:11,269
+Sha Wujingu, jdi se svými dvěma učedníky.
+
+55
+00:10:38,571 --> 00:10:44,978
+jeskyně Palmových Listů
+
+56
+00:10:47,200 --> 00:10:51,549
+Hlupáku. První jdu vždy já.
+
+57
+00:10:51,600 --> 00:10:54,350
+Tentokrát jsi na řadě ty.
+
+58
+00:10:58,519 --> 00:11:04,909
+Juniore. Vždycky jdu první já, tak teď jsi na řadě ty.
+
+59
+00:11:04,960 --> 00:11:06,830
+Seniore...
+
+60
+00:11:06,879 --> 00:11:10,990
+Žádám tě, abys pro mistra udělal malou službu. Nemůžeš to udělat?
+
+61
+00:11:11,039 --> 00:11:14,309
+Dělej!
+
+62
+00:11:39,639 --> 00:11:43,039
+Prostý mnichu, odkud jsi přišel?
+
+63
+00:11:43,039 --> 00:11:49,870
+Velký Mudrc... Tang Seng... si žádá vaši princeznu...
+
+64
+00:11:49,919 --> 00:11:52,480
+Nesmysl!
+
+65
+00:12:47,549 --> 00:12:52,059
+Seniore... proč raději nejde vy?
+
+66
+00:12:52,120 --> 00:12:56,950
+Hlupáku, jdi ty!
+
+67
+00:12:57,000 --> 00:13:00,700
+Seiore, proč vy ne?
+
+68
+00:13:04,029 --> 00:13:07,460
+Líný hlupáku!
+
+69
+00:13:54,279 --> 00:13:57,899
+Velká Matko Hromů! Nezabíjejte mě, nechte mě jít!
+
+70
+00:13:57,960 --> 00:13:59,950
+Jdi a řekni tvé princezně, 
+
+71
+00:14:00,000 --> 00:14:03,279
+že Sun Wukong si přišel půjčit její vějíř.
+
+72
+00:14:03,279 --> 00:14:08,399
+Ano, ano! Nech mě zmizet. Já hned půjdu.
+
+73
+00:14:29,559 --> 00:14:37,059
+Babičko, venku je Sun Wukong a ptá se na půjčení vějíře.
+
+74
+00:14:41,519 --> 00:14:44,149
+Rychle, přines mi můj meč.
+
+75
+00:15:01,639 --> 00:15:04,149
+Sune Wukongu, ty jsi zranil mého syna!
+
+76
+00:15:04,200 --> 00:15:08,549
+Ty se odvažuješ přijít si sem pro svou smrt?
+
+77
+00:15:08,600 --> 00:15:12,039
+Nikdy jsem tě nepotkal. Jak bych mohl ublížit tvému synovi?
+
+78
+00:15:12,039 --> 00:15:15,789
+Život mého syna Červeného Dítěte byl zničen. Není to to co děláš? 
+
+79
+00:15:15,840 --> 00:15:20,389
+Tvůj syn je nyní s Bohyní Milosrdenství. Jak můžeš říci, že jsem ho zranil?
+
+80
+00:15:20,440 --> 00:15:23,750
+Dost řečí! Pojď sem ať tě můžu seknout svým mečem.
+
+81
+00:15:23,799 --> 00:15:26,149
+Pokud to podstoupíš tak ti půjčím svůj vějíř.
+
+82
+00:15:26,200 --> 00:15:28,549
+Opravdu?
+
+83
+00:15:56,799 --> 00:16:00,629
+Zastav! Rychle, dej mi vějíř.
+
+84
+00:17:53,630 --> 00:18:00,099
+Velký mudrci, nešli jste na západ? Proč jste se vrátili?
+
+85
+00:18:11,150 --> 00:18:17,140
+Princezna Železný Vějíř mě sem odfoukla jedním mávnutím svého vějíře.
+
+86
+00:18:17,190 --> 00:18:23,859
+To je skutečně úžasné, velký mudrci. Něco pro Vás mám.
+
+87
+00:18:28,509 --> 00:18:33,450
+Tohle je větrná perla. Když ji použijete
+
+88
+00:18:33,509 --> 00:18:36,140
+vaše srdce se zastaví jako kámen.
+
+89
+00:18:36,190 --> 00:18:39,180
+Princezna Železný Vějíř nebude schopná s Vámi vůbec pohnout.
+
+90
+00:18:39,230 --> 00:18:42,849
+Velký mudrci, podívejte se.
+
+91
+00:19:00,430 --> 00:19:02,539
+Děkuji.
+
+92
+00:19:06,069 --> 00:19:12,299
+Seniore... kde...
+
+93
+00:19:12,349 --> 00:19:18,690
+Kam ho to odfouklo?
+
+94
+00:19:18,750 --> 00:19:26,099
+Kdo by se o něj staral. Ať se opičák postará sám o sebe. Pojďme.
+
+95
+00:19:35,190 --> 00:19:37,259
+Seniore... seniore...
+
+96
+00:19:37,309 --> 00:19:43,470
+Vy... vy...
+
+97
+00:19:43,470 --> 00:19:50,220
+Kam vás ta stará paní odfoukla?
+
+98
+00:19:50,269 --> 00:19:57,180
+Hlupáku, teď je rozhodně řada na tobě abys šel.
+
+99
+00:19:57,230 --> 00:20:00,930
+Já nejdu. Jediné mávnutí vějíře
+
+100
+00:20:00,990 --> 00:20:03,450
+by mě mohlo odfouknout do nějaké daleké země.
+
+101
+00:20:03,509 --> 00:20:09,710
+Možná by bylo lepší, kdyby jste šel znovu.
+
+102
+00:20:09,710 --> 00:20:12,220
+Já nepůjdu.
+
+103
+00:20:17,789 --> 00:20:22,779
+Příště už tě nenechám odpálit.
+
+104
+00:20:56,150 --> 00:21:00,140
+Tentokrát se nepohnu a nezáleží na tom jak moc máchneš.
+
+105
+00:21:00,190 --> 00:21:05,210
+Buď si jistá mým slovem, slovem muže.
+
+106
+00:21:33,670 --> 00:21:38,579
+Seniore, jakto že její vějíř vás neodfouknul?
+
+107
+00:21:46,829 --> 00:21:50,099
+Dostaňme se dovnitř.
+
+108
+00:23:59,630 --> 00:24:04,180
+Rychle, dones vějíř Sunu Wukongovi.
+
+109
+00:24:14,869 --> 00:24:16,900
+Sune Wukongu, kde jsi?
+
+110
+00:24:16,950 --> 00:24:19,980
+Jsem ve tvém žaludku!
+
+111
+00:24:45,750 --> 00:24:48,539
+Sune Wukongu, ušetři mě!
+
+112
+00:24:48,589 --> 00:24:51,180
+Jenom tehdy, když mi dáš ten vějíř.
+
+113
+00:24:51,230 --> 00:24:56,539
+Slibuji. Dám ti to. Prosím, jdi ven!
+
+114
+00:25:00,230 --> 00:25:02,819
+Honem a přines vějíř.
+
+115
+00:25:07,430 --> 00:25:09,220
+Přinesli jsme vějíř.
+
+116
+00:25:09,279 --> 00:25:12,069
+Porč jsi ještě nevylezl?
+
+117
+00:25:12,109 --> 00:25:16,619
+Otevři ústa a já vylezu.
+
+118
+00:25:25,349 --> 00:25:29,420
+Sune Wukongu, proč jsi dosud nevylezl?
+
+119
+00:25:50,349 --> 00:25:55,579
+Já jsem zde. Půjč mi na chvíli ten vějíř a já ti ho vrátím.
+
+120
+00:26:32,549 --> 00:26:36,579
+Mistr už čekal dost dlouho. Pojďme už.
+
+121
+00:27:01,869 --> 00:27:04,900
+Posvátná kniha... Co je to posvátná kniha?
+
+122
+00:27:04,950 --> 00:27:10,029
+Posvátná kniha je zásadní pro spojení mezi nebem a zemí.
+
+123
+00:27:10,029 --> 00:27:14,180
+To je princip lidí.
+
+124
+00:27:14,230 --> 00:27:18,700
+Jenom ten, kdo se těch principů drží,
+
+125
+00:27:18,750 --> 00:27:25,339
+se může zbavit bolesti a žije dobrý život.
+
+126
+00:27:25,390 --> 00:27:29,940
+Žije správný a čestný život.
+
+127
+00:27:34,680 --> 00:27:36,349
+Naproti tomu...
+
+128
+00:27:36,390 --> 00:27:40,089
+ten, kdo tyto zásady nezná,
+
+129
+00:27:40,150 --> 00:27:46,380
+bude žít život plný utrpení.
+
+130
+00:27:46,430 --> 00:27:52,609
+A dokonce ani jeho syn a vnuk nedosáhnou štěstí.
+
+131
+00:27:52,670 --> 00:27:55,660
+Proč já chci dosáhnout posvátné knihy?
+
+132
+00:27:55,710 --> 00:28:01,299
+Protože lidé jsou nyní chyceni v utrpení.
+
+133
+00:28:01,349 --> 00:28:04,180
+Abychom dosáhni tohoto cíle, jdeme...
+
+134
+00:28:04,230 --> 00:28:12,500
+navštívit císaře Tangu a povíme mu o této komplikované záležitosti.
+
+135
+00:28:15,670 --> 00:28:17,819
+Dostali jste vějíř z palmových listů?
+
+136
+00:28:17,869 --> 00:28:19,400
+Máme ho.
+
+137
+00:28:19,401 --> 00:28:20,779
+To je ono?
+
+138
+00:28:22,829 --> 00:28:27,980
+Vznešený hostiteli, teď, když máme vějíř,
+
+139
+00:28:28,029 --> 00:28:32,140
+můžeme již jít.
+
+140
+00:28:32,190 --> 00:28:34,039
+Počkejte.
+
+141
+00:28:34,039 --> 00:28:39,789
+Všichni. Rád bych požádal Sage Senga, aby jste na pár dní zůstali.
+
+142
+00:28:39,829 --> 00:28:41,339
+Souhlasíte?
+
+143
+00:28:41,390 --> 00:28:43,460
+Ujednáno!
+
+144
+00:28:43,509 --> 00:28:45,890
+Děkuji Vám za Vaši laskavost.
+
+145
+00:28:45,950 --> 00:28:51,779
+Ale odejdeme dříve abychom dokončili náš úkol.
+
+146
+00:28:51,829 --> 00:28:56,180
+Dobrá tedy. Čestný učeň půjde nejprve k Ohnivé hoře. 
+
+147
+00:28:56,230 --> 00:29:02,140
+Až uhasíš plameny, následuj Sage Senga.
+
+148
+00:29:02,190 --> 00:29:05,460
+V pořádku. Pokračujte.
+
+149
+00:30:24,470 --> 00:30:30,029
+Princezna Železný Vějíř je opravdu opovrženíhodná. Dala nám falešný vějíř!
+
+150
+00:30:30,029 --> 00:30:32,779
+Já ji zabiju! To je jisté.
+
+151
+00:30:32,829 --> 00:30:36,299
+Ne, zabíjení je špatná věc.
+
+152
+00:30:36,349 --> 00:30:39,579
+Nedovolím ti nikoho zabít.
+
+153
+00:30:39,630 --> 00:30:42,980
+Vymysleme něco jiného.
+
+154
+00:30:52,150 --> 00:30:56,220
+Seniore, jakto že Vás oklamala?
+
+155
+00:30:56,269 --> 00:30:58,539
+Po vší té námaze
+
+156
+00:30:58,589 --> 00:31:02,099
+jediné co jsme získali je falešný vějíř.
+
+157
+00:31:02,150 --> 00:31:06,500
+Směšné, směšné.
+
+158
+00:31:08,910 --> 00:31:10,420
+Pak tedy jděte!
+
+159
+00:31:10,470 --> 00:31:14,380
+Ano, půjdu, jdu, odcházím!
+
+160
+00:31:14,430 --> 00:31:16,908
+Jdu najít Krále Býčího Démona.
+
+161
+00:31:16,909 --> 00:31:19,940
+To je dobré řešení.
+
+162
+00:31:21,390 --> 00:31:24,439
+Parťáku, co si o tom myslíš?
+
+163
+00:31:24,440 --> 00:31:27,380
+Uvidíme jak to půjde.
+
+164
+00:33:07,190 --> 00:33:11,150
+Co myslíš, jsem dnes půvabná?
+
+165
+00:33:11,150 --> 00:33:13,779
+Nádherná, má drahá.
+
+166
+00:33:13,829 --> 00:33:17,059
+Doprovoď mě na procházku mimo jeskyni, ano?
+
+167
+00:33:17,109 --> 00:33:21,539
+Má drahá, proč nejdeš sama?
+
+168
+00:33:21,589 --> 00:33:24,819
+To je jasné proč. Jsem obyčejná venkovská holka.
+
+169
+00:33:24,869 --> 00:33:28,019
+Když půjdu ven tak to může způsobit, že ztratíš tvář.
+
+170
+00:33:28,069 --> 00:33:32,029
+Miláčku, proč to říkáš?
+
+171
+00:33:32,029 --> 00:33:37,500
+Pokračuj a já přijdu ven za chvilku, ano?
+
+172
+00:33:39,852 --> 00:33:44,557
+Jeskyně Smaragdových Mračen
+
+173
+00:35:28,030 --> 00:35:35,659
+Bohyně, ty jsi skutečný anděl co slétl dolů z nebes.
+
+174
+00:35:35,710 --> 00:35:37,900
+Kdo... kdo jsi?
+
+175
+00:35:37,949 --> 00:35:41,460
+Přišel jsem z jeskyně Palmových Listů abych našel krále Býčího Démona.
+
+176
+00:35:41,519 --> 00:35:43,980
+Jdi ode mě!
+
+177
+00:35:49,550 --> 00:35:52,940
+Bohyně, zpomal!
+
+178
+00:36:38,768 --> 00:36:40,133
+Jeskyně Smaragdových Mračen
+
+179
+00:36:44,230 --> 00:36:49,219
+Miláčku, kdo tě vystrašil?
+
+180
+00:36:49,269 --> 00:36:50,820
+Ty!
+
+181
+00:36:50,869 --> 00:36:54,340
+Jak bych tě mohl vystrašit?
+
+182
+00:36:56,909 --> 00:36:59,260
+Proč nejdeš zpátky do jeskyně Palmových Listů?
+
+183
+00:36:59,320 --> 00:37:01,699
+To by ti ušetřilo rozpaky.
+
+184
+00:37:01,750 --> 00:37:07,659
+Oni často posílají lidi aby tě našli a vystrašili mě.
+
+185
+00:37:07,710 --> 00:37:11,059
+Tady byl někdo kdo mě hledal?
+
+186
+00:37:11,110 --> 00:37:15,059
+Venku je prasečí mnich, který tě hledá.
+
+187
+00:37:15,119 --> 00:37:18,510
+On mě k smrti vyděsil.
+
+188
+00:37:18,550 --> 00:37:22,739
+Jak je tohle možné? Počkej chvíli. Půjdu se podívat ven.
+
+189
+00:37:50,670 --> 00:37:53,780
+Býku, starý příteli.
+
+190
+00:37:53,829 --> 00:37:58,139
+Tady vevnitř je nějaká moc krásná mladá dáma.
+
+191
+00:37:58,199 --> 00:38:03,889
+Hej, to je moje paní. Neopovažuj se ji obtěžovat.
+
+192
+00:38:03,930 --> 00:38:08,550
+Oh, to jsem nevěděl, prosím promiň mi!
+
+193
+00:38:08,550 --> 00:38:11,940
+Ty's to nevěděl, tak tě nemůžu obviňovat. A teď už jdi.
+
+194
+00:38:11,989 --> 00:38:16,099
+Ne, ne. Stále mám něco s čím potřebuji tvou pomoc.
+
+195
+00:38:18,469 --> 00:38:24,710
+Byli jsme na cestě získat posvátnou knihu když v tom jsme dorazili k Ohnivé hoře.
+
+196
+00:38:24,710 --> 00:38:27,300
+Prosím, požádej svou choť,
+
+197
+00:38:27,349 --> 00:38:30,820
+aby nám na chvíli půjčila vějíř z palmových listů.
+
+198
+00:38:30,880 --> 00:38:33,510
+V žádném případě! Tang Seng a Sun Wukong
+
+199
+00:38:33,510 --> 00:38:35,179
+jsou nepřátelé mého syna.
+
+200
+00:38:35,230 --> 00:38:38,739
+Moc rád bych na nich vykonal svou pomstu.
+
+201
+00:38:38,789 --> 00:38:44,969
+Tvůj syn je nyní s Bohyní Milosrdenství. Prosím, nebojuj.
+
+202
+00:38:45,030 --> 00:38:48,940
+Dobrá. Jsme staří přátelé tak s tebou nebudu bojovat.
+
+203
+00:38:49,000 --> 00:38:51,710
+Nyní jdi pryč!
+
+204
+00:39:38,389 --> 00:39:44,179
+Miláčku, ten prasečí mnich je můj přítel.
+
+205
+00:39:44,230 --> 00:39:46,500
+On vůbec nebyl poslán z jeskyně Palmových Listů.
+
+206
+00:39:46,550 --> 00:39:47,739
+Nevěřím ti.
+
+207
+00:39:47,789 --> 00:39:50,940
+Já ti nelžu!
+
+208
+00:39:50,989 --> 00:39:54,019
+Kde je ten mnich teď?
+
+209
+00:39:54,110 --> 00:39:57,780
+Už jsem ho zastrašil.
+
+210
+00:43:34,814 --> 00:43:40,987
+Jeskyně Palmových Listů
+
+211
+00:43:58,630 --> 00:44:01,340
+Král se vrátil.
+
+212
+00:44:01,389 --> 00:44:02,369
+Kde je babička?
+
+213
+00:44:02,429 --> 00:44:04,780
+Je uvnitř.
+
+214
+00:44:42,989 --> 00:44:48,219
+Jaká čest, že nás dnes navštívil král.
+
+215
+00:44:48,269 --> 00:44:52,260
+Slyšel jsem, že sem jsou Sun Wukong a Tang Seng.
+
+216
+00:44:52,320 --> 00:44:56,909
+Obávám se, že chtějí použít vějíř z palmových listů a přejít Ohnivou horu.
+
+217
+00:44:56,949 --> 00:45:00,860
+Ten opičák je jeden z těch co zranil našeho syna.
+
+218
+00:45:00,909 --> 00:45:08,489
+Dostanu ho dříve či později. Dosáhnu naší msty.
+
+219
+00:45:08,550 --> 00:45:12,699
+Miláčku, proč pláčeš?
+
+220
+00:45:12,750 --> 00:45:15,699
+Ten opičák už tady byl.
+
+221
+00:45:15,750 --> 00:45:18,860
+Odmítla jsem mu vějíř dát.
+
+222
+00:45:18,909 --> 00:45:22,260
+Nevím jak, ale dostal se mi do žaludku.
+
+223
+00:45:22,309 --> 00:45:25,500
+Bolelo to tak strašně, že jsem myslela že umřu.
+
+224
+00:45:25,550 --> 00:45:30,589
+Nakonec jsem neměla na výběr a dala jsem mu vějíř.
+
+225
+00:45:30,789 --> 00:45:35,260
+To je strašné. Jak's mu mohla dát vějíř?
+
+226
+00:45:38,320 --> 00:45:40,469
+Dala jsem mu falešný.
+
+227
+00:45:40,720 --> 00:45:43,019
+Falešný?
+
+228
+00:46:14,190 --> 00:46:19,860
+Večírek na oslavu návratu krále
+
+229
+00:46:19,909 --> 00:46:25,619
+Prosím, napijte se dobrého vína. 
+
+230
+00:46:25,670 --> 00:46:34,179
+Kuřecí je voňavé, kachna je skvostná a vepřové je tučné. 
+
+231
+00:46:34,239 --> 00:46:45,670
+Zkusím si zazpívat. Zkusím si dobře zatančit.
+
+232
+00:46:45,710 --> 00:46:54,500
+Musíš také ochutnat náš nejlepší nápoj.
+
+233
+00:47:03,590 --> 00:47:16,389
+Můj králi. Ty's pustil k vodě tu starou.
+
+234
+00:47:16,429 --> 00:47:22,610
+Ty miluješ jinou ženu.
+
+235
+00:47:22,670 --> 00:47:34,659
+Nespočet slz jsem pro tebe naplakala.
+
+236
+00:47:46,710 --> 00:47:55,699
+Když světlo zhasne a spustí se závěs,
+
+237
+00:47:55,750 --> 00:48:00,869
+budeš spát sám.
+
+238
+00:48:00,869 --> 00:48:05,510
+Ty také okusíš samotu.
+
+239
+00:48:05,510 --> 00:48:13,420
+Omluv mě, že ti nedělám společnost.
+
+240
+00:48:18,550 --> 00:48:24,619
+Dokonce i když jsme ve stejné posteli,
+
+241
+00:48:24,670 --> 00:48:34,340
+budeme spát pod oddělenými přikrývkami.
+
+242
+00:48:38,389 --> 00:48:42,380
+Králi. Jsem opilá.
+
+243
+00:48:55,070 --> 00:48:58,139
+Miláčku, kam jsi dala skutečný vějíř?
+
+244
+00:48:58,190 --> 00:49:05,460
+Ten opičák je velmi podvodný a prase je dokonce mnohem nadanější.
+
+245
+00:49:05,510 --> 00:49:09,780
+Když si nebudeš dávat pozor tak tě mohou obelstít.
+
+246
+00:49:18,360 --> 00:49:21,980
+Náš poklad je přímo tady.
+
+247
+00:49:31,429 --> 00:49:39,309
+Králi, na co myslíš? Proč si jej nevezmeš?
+
+248
+00:49:39,309 --> 00:49:40,847
+Můj poklade.
+
+249
+00:49:41,514 --> 00:49:44,150
+Jeskyně Smaragdových Mračen
+
+250
+00:49:44,250 --> 00:49:49,019
+Miláčku, dej si další pohár. Pij.
+
+251
+00:49:53,909 --> 00:49:59,510
+Zlatý drak mě požádal abych s ním dnes večer pil.
+
+252
+00:49:59,510 --> 00:50:01,420
+Potom bys měl jít.
+
+253
+00:50:01,469 --> 00:50:02,860
+Dobrá.
+
+254
+00:50:02,909 --> 00:50:06,610
+Měl bys pro dědečka připravit zlatooké zvíře.
+
+255
+00:50:06,670 --> 00:50:08,260
+Připravím.
+
+256
+00:50:08,320 --> 00:50:12,590
+Měl bys dnes večer pít trochu méně.
+
+257
+00:50:12,630 --> 00:50:15,739
+Jinak tě nebudu moci probudit.
+
+258
+00:50:15,800 --> 00:50:19,110
+To je strašné. Dědečkova zlatooká nestvůra zmizela!
+
+259
+00:50:19,150 --> 00:50:20,900
+Jste všichni hluší a slepí?
+
+260
+00:50:20,949 --> 00:50:24,030
+Jak mohla zmizet?
+
+261
+00:50:24,030 --> 00:50:27,900
+Miláčku, nestrachuj se o ně.
+
+262
+00:50:27,960 --> 00:50:31,710
+Bojím se, že Zhu Bajie ho mohl ukrást.
+
+263
+00:50:31,750 --> 00:50:35,260
+Možná bych měl prohledat jeskyni Palmových Listů.
+
+264
+00:50:35,320 --> 00:50:39,309
+Cože? Ty's to plánoval celou dobu.
+
+265
+00:50:42,280 --> 00:50:48,150
+Stále to chceš prohledat u té nestoudné ženy?
+
+266
+00:50:48,190 --> 00:50:50,699
+Prosím miláčku, neplakej.
+
+267
+00:50:50,750 --> 00:50:54,059
+Vrátím se brzy.
+
+268
+00:50:57,624 --> 00:51:01,194
+Jeskyně Palmových Listů
+
+269
+00:51:02,670 --> 00:51:07,300
+Pojď sem, napij se trochu!
+
+270
+00:51:10,349 --> 00:51:12,460
+Teď si můžu odpočinout.
+
+271
+00:51:12,510 --> 00:51:16,699
+Nemusíme se obávat, že jsme byli oloupeni o náš poklad.
+
+272
+00:51:16,750 --> 00:51:21,300
+Dokonce i když ho ukradli, tak nebudou vědět, že mají zatáhnout za hedvábnou nit.
+
+273
+00:51:21,360 --> 00:51:26,269
+Mají perlu, ale nebudou ji moci použít.
+
+274
+00:51:26,309 --> 00:51:31,780
+Zatáhnutí za nit ji promění na vějíř, že?
+
+275
+00:51:35,119 --> 00:51:38,070
+Králi, jsi opilý.
+
+276
+00:51:38,110 --> 00:51:44,019
+Zapomněl jsi na svůj vlastní poklad a ptáš se mě...
+
+277
+00:51:49,989 --> 00:51:53,690
+Madam, podívej se kdo já jsem.
+
+278
+00:52:00,320 --> 00:52:03,750
+Kdo jsi?
+
+279
+00:52:03,789 --> 00:52:09,889
+Já jsem Zhu Bajie, druhý pomocník Tanga Senga.
+
+280
+00:52:09,949 --> 00:52:14,780
+Omlouvám se, že jsem Vás rušil a díky!
+
+281
+00:52:19,079 --> 00:52:21,710
+Na shledanou!
+
+282
+00:53:06,829 --> 00:53:10,699
+Býkova žena je příliš koketní.
+
+283
+00:53:10,760 --> 00:53:14,710
+Všichni její podřízení jsou krásní.
+
+284
+00:53:14,750 --> 00:53:24,809
+Starý Čuník to skoro nedokázal.
+
+285
+00:53:24,869 --> 00:53:28,860
+Použil jsem chytré triky a taktiky.
+
+286
+00:53:28,909 --> 00:53:32,820
+Uloupil jsem jejich poklad.
+
+287
+00:53:32,880 --> 00:53:36,789
+To je ohromný výkon.
+
+288
+00:53:36,829 --> 00:53:38,300
+Písečný by měl klečet.
+
+289
+00:53:38,349 --> 00:53:40,730
+Opice by se měla učit ode mě.
+
+290
+00:53:40,789 --> 00:53:45,219
+Dokonce i Mistr bude v úžasu.
+
+291
+00:53:45,280 --> 00:53:49,190
+Starý Čuník je skutečně mistrovský.
+
+292
+00:53:49,230 --> 00:53:54,349
+Starý Čuník je skutečně mistrovský.
+
+293
+00:54:36,719 --> 00:54:40,469
+Hlupáku, jak to jde?
+
+294
+00:54:40,510 --> 00:54:42,809
+Nejen že jsem získal vějíř,
+
+295
+00:54:42,880 --> 00:54:48,789
+ale princezna Železný Vějíř byla půl dne mou ženou.
+
+296
+00:54:48,829 --> 00:54:51,699
+Udělal jsi to dobře.
+
+297
+00:54:58,150 --> 00:55:01,579
+Hej, ukaž mi ten vějíř.
+
+298
+00:55:16,030 --> 00:55:20,219
+Proč jsi ho smrštil?
+
+299
+00:55:40,550 --> 00:55:45,340
+Starý Čuníku, ty mě nepoznáváš, že?
+
+300
+00:55:45,389 --> 00:55:49,170
+Nedělej si ze mě legraci.
+
+301
+00:55:49,230 --> 00:55:52,139
+A kdo si z tebe dělá legraci?
+
+302
+00:56:42,869 --> 00:56:45,380
+Hlupáku, jak se to stalo?
+
+303
+00:56:45,429 --> 00:56:47,099
+Všechno bylo k ničemu.
+
+304
+00:56:47,150 --> 00:56:49,980
+Wunengu, vypůjčil jsi ten vějíř?
+
+305
+00:56:50,030 --> 00:56:53,340
+Našel jsem krále Býčího démona, ale on odmítl.
+
+306
+00:56:53,400 --> 00:56:59,190
+Potom jsem na sebe vzal jeho podobu.
+
+307
+00:56:59,230 --> 00:57:03,539
+Oklamal jsem princeznu Železný Vějíř aby mi dala vějíř.
+
+308
+00:57:03,590 --> 00:57:10,590
+Ale potom si Starý Býk vzal tvou podobu a vylákal ho na mě zpátky.
+
+309
+00:57:10,590 --> 00:57:12,739
+Schopnosti Starého Býka jsou vynikající.
+
+310
+00:57:12,800 --> 00:57:16,150
+Potom mě ještě zbil.
+
+311
+00:57:16,190 --> 00:57:21,380
+Jak jsi mohl získat vějíř a přitom zůstat tak hloupý?
+
+312
+00:57:21,429 --> 00:57:25,659
+Všechno se neotáčí kolem tebe!
+
+313
+00:57:30,750 --> 00:57:34,369
+Nebojuj. Musíme rychle vymyslet nějaké řešení.
+
+314
+00:57:34,429 --> 00:57:40,260
+Ve kterém směru není oheň?
+
+315
+00:57:40,320 --> 00:57:47,070
+Východ, jih, západ, sever. Oheň není jenom na západě.
+
+316
+00:57:47,119 --> 00:57:50,739
+Tak to nemáme jinou možnost než se vrátit.
+
+317
+00:57:50,789 --> 00:57:52,940
+Tato stezka je zablokovaná. Jaké máme jiné možnosti?
+
+318
+00:57:52,989 --> 00:57:55,219
+Bajie, nemluv tak.
+
+319
+00:57:55,269 --> 00:57:59,139
+Na naší cestě budou vždy překážky.
+
+320
+00:57:59,190 --> 00:58:04,539
+Abychom dokončili náš posvátný úkol, musíme být silní v naší víře.
+
+321
+00:58:04,590 --> 00:58:09,219
+Nemůžeme změnit náš plán jenom kvůli tomu, že jsme narazili na pár překážek.
+
+322
+00:58:09,280 --> 00:58:14,590
+Důvod proč jsme byli poraženi je ten, že jsme nespolupracovali.
+
+323
+00:58:14,630 --> 00:58:17,139
+Pokud tři z nás budou jako jeden,
+
+324
+00:58:17,190 --> 00:58:20,500
+dáme síly dohromady a zdoláme krále Býčího Démona.
+
+325
+00:58:20,550 --> 00:58:22,849
+A vítězství bude naše.
+
+326
+00:58:22,909 --> 00:58:26,030
+Slyšeli jsme Mistrův rozkaz 
+
+327
+00:58:26,030 --> 00:58:30,139
+a budeme s králem Býčím Démonem bojovat až do konce.
+
+328
+00:58:30,190 --> 00:58:34,260
+až... až do konce.
+
+329
+00:58:34,320 --> 00:58:37,710
+To je skvělé!
+
+330
+00:58:37,750 --> 00:58:40,980
+Všichni jsme dokázali překonat nesnáze.
+
+331
+00:58:41,039 --> 00:58:43,869
+Doufám, že každý vynaloží veškeré úsilí
+
+332
+00:58:43,869 --> 00:58:49,579
+společně s mými učedníky k porážce krále Býčího Démona a uhasíme plameny Ohnivé hory.
+
+333
+00:58:49,630 --> 00:58:52,820
+Jinak toto neštěstí nikdy neskončí.
+
+334
+00:58:53,869 --> 00:58:57,489
+Slyšeli jsme Mistrovo nařízení na dosažení štěstí pro všechny.
+
+335
+00:58:57,550 --> 00:58:58,860
+Společně to dokážeme!
+
+336
+00:58:58,909 --> 00:59:00,519
+Hurá!
+
+337
+01:08:23,229 --> 01:08:25,609
+Babičko, to je strašné!
+
+338
+01:08:25,670 --> 01:08:30,789
+Dědeček je chycen. Pojď se rychle podívat.
+
+339
+01:08:54,470 --> 01:08:56,699
+Ještě není po boji. Ještě ne.
+
+340
+01:08:56,760 --> 01:08:58,710
+Pozor. Opatrně.
+
+341
+01:08:59,760 --> 01:09:05,789
+Nestvůro, jediné co musíš udělat je dát nám vějíř a ušetříme tvůj život.
+
+342
+01:09:05,840 --> 01:09:12,750
+Starý Býku, kde je vějíř? Odevzdej ho!
+
+343
+01:09:12,789 --> 01:09:19,340
+Moje ... moje choť... jej má.
+
+344
+01:09:25,239 --> 01:09:27,989
+Drahoušku, drahoušku!
+
+345
+01:09:28,029 --> 01:09:32,260
+Zachraň mě, rychle!
+
+346
+01:09:32,319 --> 01:09:35,109
+Dej jim vějíř.
+
+347
+01:09:35,149 --> 01:09:39,619
+Králi! Ano, ano.
+
+348
+01:09:43,399 --> 01:09:47,229
+Wukongu, jdi na to ještě jednou!
+
+349
+01:12:30,850 --> 01:12:46,599
+Konec
+
diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-ru.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-ru.srt
new file mode 100644 (file)
index 0000000..9a9f8ab
--- /dev/null
@@ -0,0 +1,1414 @@
+1
+00:00:01,080 --> 00:00:09,070
+Принцесса Железный Веер
+
+2
+00:02:03,109 --> 00:02:09,280
+Путешествие на Запад это замечательная детская история
+
+3
+00:02:09,280 --> 00:02:15,280
+но мир часто неправильно воспринимает ее, как фантастическую.
+
+4
+00:02:15,280 --> 00:02:19,240
+Этот фильм был сделан для того, чтобы
+
+5
+00:02:19,240 --> 00:02:24,240
+воспитать сердца и ума детей.
+
+6
+00:02:24,240 --> 00:02:29,280
+История чиста, не испорчена фантазией.
+
+7
+00:02:29,280 --> 00:02:32,560
+Огненная Гора, преграждающая дорогу Танскому монаху и его ученикам -  
+
+8
+00:02:32,560 --> 00:02:41,039
+это аллегория жизненных трудностей.
+
+9
+00:02:41,039 --> 00:02:46,439
+Чтобы преодолеть их, нужно хранить веру. 
+Каждый должен сделать все, 
+
+10
+00:02:46,439 --> 00:02:52,430
+чтобы получить веер пальмового листа и потушить огонь.
+
+11
+00:02:52,839 --> 00:02:58,178
+Tрипитака Истинная Сутра
+
+12
+00:03:34,479 --> 00:03:37,789
+Уже осень, как еще может быть так жарко?
+
+13
+00:03:37,840 --> 00:03:42,349
+Дурень, не болтай ерунды! Нам надо поспешить и найти верную дорогу.
+
+14
+00:04:06,919 --> 00:04:09,349
+Укун, где мы?
+
+15
+00:04:09,400 --> 00:04:13,669
+Наш путь на Запад лежит через эту местность, это уж точно.
+
+16
+00:04:13,719 --> 00:04:18,110
+Может, мы идем не в ту сторону ?
+
+17
+00:04:18,149 --> 00:04:21,700
+Почему здесь так жарко?
+
+18
+00:04:30,029 --> 00:04:31,649
+Наставник, смотрите!
+
+19
+00:04:31,650 --> 00:04:33,779
+Разве там не дом, впереди?
+
+20
+00:04:33,829 --> 00:04:38,100
+Давайте, зайдем и отдохнем немного, ладно?
+
+21
+00:04:59,389 --> 00:05:02,899
+Это место носит название Огненная Гора.
+
+22
+00:05:02,949 --> 00:05:06,019
+Огонь распространяется на сотни миль.
+
+23
+00:05:06,069 --> 00:05:08,740
+Ни одна травинка не может расти здесь.
+
+24
+00:05:08,790 --> 00:05:11,620
+Целый год жарко.
+
+25
+00:05:11,680 --> 00:05:19,629
+Вы не сможете пройти через эту гору даже если у вас голова из меди, а тело из железа.
+
+26
+00:05:19,670 --> 00:05:23,579
+Что это за место? Наставник, не волнуйся!
+
+27
+00:05:23,629 --> 00:05:27,139
+Трое из нас достаточно сильны, чтобы прокладывать дорогу!
+
+28
+00:05:27,189 --> 00:05:30,699
+Наставник, я пойду взглянуть!
+
+29
+00:08:06,310 --> 00:08:09,579
+Укун, ну что?
+
+30
+00:08:09,629 --> 00:08:11,819
+Плохо, плохо, очень плохо.
+
+31
+00:08:11,879 --> 00:08:15,910
+Если бы я немного замешкался, мой хвост бы сгорел. 
+
+32
+00:08:42,720 --> 00:08:47,600
+Почтеный хозяин, огонь в ваших краях так велик. 
+
+33
+00:08:47,600 --> 00:08:49,669
+Как вы можете что-то выращивать? 
+
+34
+00:08:49,710 --> 00:08:53,980
+Тысяча миль отсюда живет принцесса Железный Веер. 
+
+35
+00:08:54,039 --> 00:08:56,500
+У нее есть веер из листа пальмы.
+
+36
+00:08:56,559 --> 00:08:59,070
+Махнешь им раз, и огонь прекращается. 
+
+37
+00:08:59,120 --> 00:09:01,629
+Два раза, и поднимается ветер. 
+
+38
+00:09:01,679 --> 00:09:03,980
+Три раза, и начинает идти дождь.
+
+39
+00:09:04,039 --> 00:09:07,509
+И вот тогда, мы сеем и собираем урожай.
+
+40
+00:09:07,559 --> 00:09:11,340
+Однако уговорить эту принцессу прийти
+
+41
+00:09:11,399 --> 00:09:14,870
+довольно трудно.
+
+42
+00:09:14,909 --> 00:09:16,820
+Где она живет? 
+
+43
+00:09:16,879 --> 00:09:20,190
+Она живет в Пещере Листа Пальмы на Горе Изумрудных Облаков.
+
+44
+00:09:20,240 --> 00:09:23,669
+Она там одна живет?
+
+45
+00:09:23,720 --> 00:09:25,750
+Разве у нее нет мужа?
+
+46
+00:09:25,799 --> 00:09:29,580
+Ее муж - Князь демонов с головой быка.
+
+47
+00:09:29,639 --> 00:09:32,200
+Значит, ее муж - Старый Бык?
+
+48
+00:09:32,240 --> 00:09:36,789
+Ты знаком с ним, дурень? Иди со мной за веером! 
+
+49
+00:09:36,840 --> 00:09:41,750
+Фактически... Старый Бык не живет там.
+
+50
+00:09:41,799 --> 00:09:46,350
+Прийти к его жене, когда он не дома -
+
+51
+00:09:46,399 --> 00:09:51,519
+не очень ... осторожный поступок.
+
+52
+00:09:51,559 --> 00:09:58,309
+Вы ... вы ... двое идите
+
+53
+00:09:58,360 --> 00:10:04,290
+А я... я останусь здесь и буду охранять учителя.
+
+54
+00:10:04,440 --> 00:10:11,269
+Ша Удзин, иди вместе с братьями.
+
+
+
+55
+00:10:38,571 --> 00:10:44,978
+Пещера Листа Пальмы
+
+56
+00:10:47,200 --> 00:10:51,549
+Дурень, я всегда иду первым.
+
+57
+00:10:51,600 --> 00:10:54,350
+Теперь твоя очередь!
+
+58
+00:10:58,519 --> 00:11:04,909
+Младший! Я всегда иду первым, теперь твоя очередь!
+
+59
+00:11:04,960 --> 00:11:06,830
+Старший...
+
+60
+00:11:06,879 --> 00:11:10,990
+Я хочу, чтобы ты тоже немного постарался для наставника. Неужели это так трудно? 
+
+61
+00:11:11,039 --> 00:11:14,309
+Веселей!
+
+62
+00:11:39,639 --> 00:11:43,039
+Бедный монах, откуда ты пришел?
+
+63
+00:11:43,039 --> 00:11:49,870
+Великий Мудрец... Танский монах ... хочет вашу принцессу...
+
+64
+00:11:49,919 --> 00:11:52,480
+Глупости!
+
+65
+00:12:47,549 --> 00:12:52,059
+Старший ... может тебе пойти следующим?
+
+66
+00:12:52,120 --> 00:12:56,950
+Дурень, иди ты!
+
+67
+00:12:57,000 --> 00:13:00,700
+Старший, почему не идешь? 
+
+68
+00:13:04,029 --> 00:13:07,460
+Ленивый дурень!
+
+69
+00:13:54,279 --> 00:13:57,899
+Великий Бог Грома! Не убивай меня, позволь мне уйти!
+
+70
+00:13:57,960 --> 00:13:59,950
+Иди и доложи своей принцессе,
+
+71
+00:14:00,000 --> 00:14:03,279
+что явился Сунь Укун одолжить у нее веер. 
+
+72
+00:14:03,279 --> 00:14:08,399
+Да, да! Отпусти, я сразу пойду.
+
+73
+00:14:29,559 --> 00:14:37,059
+Госпожа, пришел Сунь Укун, чтобы одолжить веер. 
+
+74
+00:14:41,519 --> 00:14:44,149
+Живо принесите мне мой меч.
+
+75
+00:15:01,639 --> 00:15:04,149
+Сунь Укун, ты погубил моего сына!
+
+76
+00:15:04,200 --> 00:15:08,549
+И ты еще смеешь являться сюда на свою погибель?
+
+77
+00:15:08,600 --> 00:15:12,039
+Я никогда не встречал тебя прежде, как же я мог навредить твоему сыну? 
+
+78
+00:15:12,039 --> 00:15:15,789
+Разве жизнь моего сына, Красного Ребенка, была разрушена не из-за тебя? 
+
+79
+00:15:15,840 --> 00:15:20,389
+Твой сын теперь во власти Богини Милосердия, как ты можешь говорить, что я погубил его? 
+
+80
+00:15:20,440 --> 00:15:23,750
+Довольно болтовни! Иди сюда и нагнись, я разрублю тебя своим мечом.
+
+81
+00:15:23,799 --> 00:15:26,149
+Если останешься жив, отдам тебе веер.
+
+82
+00:15:26,200 --> 00:15:28,549
+Правда? 
+
+83
+00:15:56,799 --> 00:16:00,629
+Стой! Сейчас же отдавай веер!
+
+
+84
+00:17:53,630 --> 00:18:00,099
+Великий Мудрец, разве вы не на Запад шли? Почему вы вернулись сюда? 
+
+85
+00:18:11,150 --> 00:18:17,140
+Принцесса махнула веером, и поднялся страшный ветер, который принес меня сюда.
+
+86
+00:18:17,190 --> 00:18:23,859
+Это действительно странно, Великий Мудрец. У меня есть кое-что для тебя. 
+
+87
+00:18:28,509 --> 00:18:33,450
+Это жемчужина против ветра. Когда ты примешь ее, 
+
+88
+00:18:33,509 --> 00:18:36,140
+твое сердце станет устойчивым, как скала.
+
+89
+00:18:36,190 --> 00:18:39,180
+Веер принцессы не сможет сдвинуть тебя с места.
+
+90
+00:18:39,230 --> 00:18:42,849
+Великий Мудрец, подойди и посмотри. 
+
+91
+00:19:00,430 --> 00:19:02,539
+Спасибо тебе.
+
+92
+00:19:06,069 --> 00:19:12,299
+Старший... где... к? 
+
+93
+00:19:12,349 --> 00:19:18,690
+где его... носит? 
+
+94
+00:19:18,750 --> 00:19:26,099
+Кто заботится о нем? Спасение обезьяны в ее руках. Пойдем.
+
+95
+00:19:35,190 --> 00:19:37,259
+Старший ... старший...
+
+96
+00:19:37,309 --> 00:19:43,470
+Ты... ты...
+
+97
+00:19:43,470 --> 00:19:50,220
+Куда тебя унесло из за той старухи?
+
+98
+00:19:50,269 --> 00:19:57,180
+Дурень, теперь определенно твоя очередь идти.
+
+99
+00:19:57,230 --> 00:20:00,930
+Я не пойду, одна воздушная волна ее веера 
+
+100
+00:20:00,990 --> 00:20:03,450
+может унести меня на край света.
+
+101
+00:20:03,509 --> 00:20:09,710
+Наверное, лучше, если ты снова пойдешь.
+
+102
+00:20:09,710 --> 00:20:12,220
+Я не пойду. 
+
+103
+00:20:17,789 --> 00:20:22,779
+В следующий раз я тебя не отпущу!
+
+104
+00:20:56,150 --> 00:21:00,140
+На сей раз я с места не сдвинусь, сколько бы ты ни махала, 
+
+105
+00:21:00,190 --> 00:21:05,210
+это так же верно, как то, что я - человек! 
+
+106
+00:21:33,670 --> 00:21:38,579
+Старший, почему ветер в этот раз не унес тебя? 
+
+107
+00:21:46,829 --> 00:21:50,099
+Давай, взломим дверь.
+
+108
+00:23:59,630 --> 00:24:04,180
+Живо доставайте веер для Сунь Укуна! 
+
+109
+00:24:14,869 --> 00:24:16,900
+Сунь Укун, где ты? 
+
+110
+00:24:16,950 --> 00:24:19,980
+Я у тебя в животе! 
+
+111
+00:24:45,750 --> 00:24:48,539
+Сунь Укун, смилуйся надо мной! 
+
+112
+00:24:48,589 --> 00:24:51,180
+Только, если отдашь веер! 
+
+113
+00:24:51,230 --> 00:24:56,539
+Я клянусь, я отдам. Пожалуйста, выходи!
+
+114
+00:25:00,230 --> 00:25:02,819
+Живо принесите веер. 
+
+115
+00:25:07,430 --> 00:25:09,220
+Мы принесли веер.
+
+116
+00:25:09,279 --> 00:25:12,069
+Почему же ты не выходишь? 
+
+117
+00:25:12,109 --> 00:25:16,619
+Открой рот, и я выйду.
+
+118
+00:25:25,349 --> 00:25:29,420
+Сунь Укун, почему ты не вышел? 
+
+119
+00:25:50,349 --> 00:25:55,579
+Я здесь. Одолжи мне веер ненадолго и я верну его.
+
+120
+00:26:32,549 --> 00:26:36,579
+Наставник заждался, давайте поспешим!
+
+
+
+121
+00:27:01,869 --> 00:27:04,900
+Что такое священные книги?
+
+122
+00:27:04,950 --> 00:27:10,029
+Священные книги это законы неба и земли.
+
+123
+00:27:10,029 --> 00:27:14,180
+Они являются принципами человека. 
+
+124
+00:27:14,230 --> 00:27:18,700
+Только тот, кто признает эти принципы,  
+
+125
+00:27:18,750 --> 00:27:25,339
+сможет избавить себя от боли и жить хорошо,
+
+126
+00:27:25,390 --> 00:27:29,940
+жить честной, истинной жизнью. 
+
+127
+00:27:34,680 --> 00:27:36,349
+И наоборот, 
+
+128
+00:27:36,390 --> 00:27:40,089
+тот, кто не знает эти принципы, 
+
+129
+00:27:40,150 --> 00:27:46,380
+будет жить жизнью, полной страдания.
+
+130
+00:27:46,430 --> 00:27:52,609
+Даже его сын или внук не достигнут счастья.
+
+131
+00:27:52,670 --> 00:27:55,660
+Почему я надеюсь получить священные книги? 
+
+132
+00:27:55,710 --> 00:28:01,299
+Люди в наше время пойманы в ловушку страданий.
+
+133
+00:28:01,349 --> 00:28:04,180
+И чтобы это изменить, мы идем поклониться
+
+134
+00:28:04,230 --> 00:28:12,500
+Танскому императору и обсудить этот очень сложный вопрос.
+
+
+
+
+135
+00:28:15,670 --> 00:28:17,819
+Вы добыли веер?  
+
+136
+00:28:17,869 --> 00:28:19,400
+Он у нас. 
+
+137
+00:28:19,401 --> 00:28:20,779
+Что это?
+
+138
+00:28:22,829 --> 00:28:27,980
+Благородные хозяева, теперь, когда у нас есть веер, 
+
+139
+00:28:28,029 --> 00:28:32,140
+мы можем отдохнуть.
+
+140
+00:28:32,190 --> 00:28:34,039
+Держитесь. 
+
+141
+00:28:34,039 --> 00:28:39,789
+Народ, я хотел бы попросить мудрого Сэнга погостить у нас еще нескольких дней. 
+
+142
+00:28:39,829 --> 00:28:41,339
+Вы согласны? 
+
+143
+00:28:41,390 --> 00:28:43,460
+Согласны! 
+
+144
+00:28:43,509 --> 00:28:45,890
+Спасибо вам за вашу доброту.
+
+145
+00:28:45,950 --> 00:28:51,779
+Но чем скорее я уеду, тем скорее мы сможем завершить нашу задачу.
+
+146
+00:28:51,829 --> 00:28:56,180
+Очень хорошо, пусть благородный ученик сначала пойдет на Огненную Гору. 
+
+147
+00:28:56,230 --> 00:29:02,140
+После гашения огней, продолжите следовать за мудрым Сэнгом. 
+
+148
+00:29:02,190 --> 00:29:05,460
+Хорошо, вперед! 
+
+149
+00:30:24,470 --> 00:30:30,029
+Принцесса действительно коварна, она дала нам фальшивый веер! 
+
+150
+00:30:30,029 --> 00:30:32,779
+Я точно убью ее! 
+
+151
+00:30:32,829 --> 00:30:36,299
+Нет, убивать нельзя. 
+
+152
+00:30:36,349 --> 00:30:39,579
+Я не позволю вам никого убивать.
+
+153
+00:30:39,630 --> 00:30:42,980
+Давайте придумаем что-нибудь другое. 
+
+154
+00:30:52,150 --> 00:30:56,220
+Старший, как она могла тебя одурачить? 
+
+155
+00:30:56,269 --> 00:30:58,539
+После стольких усилий
+156
+00:30:58,589 --> 00:31:02,099
+все, чего мы достигли, оказалось фальшивым веером. 
+
+157
+00:31:02,150 --> 00:31:06,500
+Смешно, смешно. 
+
+158
+00:31:08,910 --> 00:31:10,420
+Тогда идешь ты! 
+
+159
+00:31:10,470 --> 00:31:14,380
+Хорошо, я пойду, я пойду, я иду! 
+
+160
+00:31:14,430 --> 00:31:16,908
+Я пойду искать Князя Демонов с головой быка. 
+
+161
+00:31:16,909 --> 00:31:19,940
+Это хорошее решение.
+
+162
+00:31:21,390 --> 00:31:24,439
+Братец, что скажешь?
+
+163
+00:31:24,440 --> 00:31:27,380
+Мы будем следить за тобой.
+
+
+
+164
+00:33:07,190 --> 00:33:11,150
+Как ты считаешь, я хороша сегодня? 
+
+165
+00:33:11,150 --> 00:33:13,779
+Ты красавица, крошка. 
+
+166
+00:33:13,829 --> 00:33:17,059
+Пойди со мной на прогулку, ладно? 
+
+167
+00:33:17,109 --> 00:33:21,539
+Моя крошка, может тебе лучше пойти одной.
+
+168
+00:33:21,589 --> 00:33:24,819
+Конечно, я всего лишь бедная девушка страны. 
+
+169
+00:33:24,869 --> 00:33:28,019
+Сопровождение меня вне пещеры может скомпрометировать тебя. 
+
+170
+00:33:28,069 --> 00:33:32,029
+Милая, что ты говоришь?
+
+171
+00:33:32,029 --> 00:33:37,500
+Иди вперед, а я выйду следом, хорошо?
+
+172
+00:33:39,852 --> 00:33:44,557
+Пещера Изумрудных Облаков
+
+173
+00:35:28,030 --> 00:35:35,659
+Божественная, вы и вправду ангел, сошедший с небес. 
+
+174
+00:35:35,710 --> 00:35:37,900
+Кто ... кто вы? 
+
+175
+00:35:37,949 --> 00:35:41,460
+Я пришел из Пещеры Листа Пальмы к Князю Демонов с головой быка. 
+
+176
+00:35:41,519 --> 00:35:43,980
+Пустите меня! 
+
+177
+00:35:49,550 --> 00:35:52,940
+Божественная, подожди! 
+
+178
+00:36:38,768 --> 00:36:40,133
+Пещера Изумрудных Облаков
+
+179
+00:36:44,230 --> 00:36:49,219
+Крошка, кто тебя обидел? 
+
+180
+00:36:49,269 --> 00:36:50,820
+Ты!
+
+181
+00:36:50,869 --> 00:36:54,340
+Чем я мог обидеть тебя?
+
+182
+00:36:56,909 --> 00:36:59,260
+Почему ты не возвращаешься в Пещеру Листа Пальмы?
+
+183
+00:36:59,320 --> 00:37:01,699
+У тебя было бы меньше хлопот. 
+
+184
+00:37:01,750 --> 00:37:07,659
+За вами специально посылают людей, чтобы измываться надо мной. 
+
+185
+00:37:07,710 --> 00:37:11,059
+За мной кто-то приходил? 
+
+186
+00:37:11,110 --> 00:37:15,059
+Пришел монах с мордой свиньи, он ищет вас. 
+
+187
+00:37:15,119 --> 00:37:18,510
+Он почти испугал меня до смерти.
+
+188
+00:37:18,550 --> 00:37:22,739
+Как это может быть? Подожди, я выйду взглянуть.
+
+189
+00:37:50,670 --> 00:37:53,780
+Бык, старина!
+
+190
+00:37:53,829 --> 00:37:58,139
+Здесь есть очень красивая девушка.
+
+191
+00:37:58,199 --> 00:38:03,889
+Эй, это же моя женщина! Зачем ты ее тиранишь?
+
+192
+00:38:03,930 --> 00:38:08,550
+Ой, я не знал, прости меня!
+
+193
+00:38:08,550 --> 00:38:11,940
+Ну раз не знал, не могу тебя винить. Можешь идти!
+
+194
+00:38:11,989 --> 00:38:16,099
+Нет, нет. Мне все еще нужна твоя помощь в одном деле.
+
+195
+00:38:18,469 --> 00:38:24,710
+Мы продолжаем наш путь за священными книгами и дошли до Огненной Горы. 
+
+196
+00:38:24,710 --> 00:38:27,300
+Пожалуйста, попроси свою жену
+
+197
+00:38:27,349 --> 00:38:30,820
+одолжить нам пальмовый веер ненадолго.
+
+198
+00:38:30,880 --> 00:38:33,510
+Абсолютно нет! Танский монах Сенг и Сунь Укун -
+
+199
+00:38:33,510 --> 00:38:35,179
+враги моего сына. 
+
+200
+00:38:35,230 --> 00:38:38,739
+Я жажду им отомстить.
+
+201
+00:38:38,789 --> 00:38:44,969
+Ваш сын теперь служит Богини Милосердия, пожалуйста, успокойся.  
+
+202
+00:38:45,030 --> 00:38:48,940
+Хорошо, так как мы старые друзья, я не буду драться с тобой. 
+
+203
+00:38:49,000 --> 00:38:51,710
+А теперь уходи!
+
+204
+00:39:38,389 --> 00:39:44,179
+Крошка, тот монах с мордой свиньи мой друг. 
+
+205
+00:39:44,230 --> 00:39:46,500
+Его вообще не посылали из Пещеры Листа Пальмы. 
+
+206
+00:39:46,550 --> 00:39:47,739
+Я не верю вам. 
+
+207
+00:39:47,789 --> 00:39:50,940
+Я тебя не обманываю!
+
+208
+00:39:50,989 --> 00:39:54,019
+Где же он теперь?
+
+209
+00:39:54,110 --> 00:39:57,780
+Я уже прогнал его.
+
+
+
+210
+00:43:34,814 --> 00:43:40,987
+Пещера Листа Пальмы
+
+211
+00:43:58,630 --> 00:44:01,340
+Повелитель вернулся!
+
+212
+00:44:01,389 --> 00:44:02,369
+Где госпожа?
+
+213
+00:44:02,429 --> 00:44:04,780
+Она там.
+
+214
+00:44:42,989 --> 00:44:48,219
+Почему повелитель оказал такую честь и пришел сегодня?
+
+215
+00:44:48,269 --> 00:44:52,260
+Я услышал, что Сунь Укун и танский монах Сэнг идут сюда.
+
+216
+00:44:52,320 --> 00:44:56,909
+Я боюсь, что они хотят добыть веер пальмового листа, чтобы перейти Огненную Гору.
+
+217
+00:44:56,949 --> 00:45:00,860
+Та обезьяна  - именно тот, кто вредил нашему сыну.
+
+218
+00:45:00,909 --> 00:45:08,489
+Рано или поздно я поймаю его, и мы отомстим.
+
+219
+00:45:08,550 --> 00:45:12,699
+Дорогая, почему ты плачешь?
+
+220
+00:45:12,750 --> 00:45:15,699
+Эта обезьяна уже была здесь.
+
+221
+00:45:15,750 --> 00:45:18,860
+Я отказалась дать ему веер.
+
+222
+00:45:18,909 --> 00:45:22,260
+Я не знаю как, но он проник ко мне в живот. 
+
+223
+00:45:22,309 --> 00:45:25,500
+Мне было так плохо, я думала, что умру.
+
+224
+00:45:25,550 --> 00:45:30,589
+В итоге, мне пришлось отдать веер.
+
+225
+00:45:30,789 --> 00:45:35,260
+Какой ужас, как ты могла отдать ему веер?
+
+226
+00:45:38,320 --> 00:45:40,469
+Я дала ему поддельный.
+
+227
+00:45:40,720 --> 00:45:43,019
+Поддельный?
+
+
+228
+00:46:14,190 --> 00:46:19,860
+Пир в честь повелителя  
+
+229
+00:46:19,909 --> 00:46:25,619
+Пожалуйста выпей прекрасное вино. 
+
+230
+00:46:25,670 --> 00:46:34,179
+Цыпленок ароматен, утка красива, и свинья жирна. 
+
+231
+00:46:34,239 --> 00:46:45,670
+Я изо всех сил пытаюсь петь и танцевать. 
+
+232
+00:46:45,710 --> 00:46:54,500
+Ты должна также изо всех сил пить.
+
+233
+00:47:03,590 --> 00:47:16,389
+Мой повелитель! Ты оставил прошлое. 
+
+234
+00:47:16,429 --> 00:47:22,610
+Ты любишь другую женщину. 
+
+235
+00:47:22,670 --> 00:47:34,659
+Бесчисленные слезы были пролиты ради тебя.
+
+236
+00:47:46,710 --> 00:47:55,699
+Когда свет погаснет и опустят занавески, 
+
+237
+00:47:55,750 --> 00:48:00,869
+ты будешь спать один.
+
+238
+00:48:00,869 --> 00:48:05,510
+Ты также почувствуешь одинокость. 
+
+239
+00:48:05,510 --> 00:48:13,420
+Извини, что не могу составить тебе компанию. 
+
+240
+00:48:18,550 --> 00:48:24,619
+Даже если мы будем на той же кровати,
+
+241
+00:48:24,670 --> 00:48:34,340
+мы будем спать под отдельными листами. 
+
+242
+00:48:38,389 --> 00:48:42,380
+Король, я пьяна. 
+
+243
+00:48:55,070 --> 00:48:58,139
+Супруженька, куда же ты спрятала настоящий веер?
+
+244
+00:48:58,190 --> 00:49:05,460
+Эта обезьяна очень коварна, а кабан еще хитрее.
+
+245
+00:49:05,510 --> 00:49:09,780
+Если не будешь осторожной, они тебя могут обмануть.
+
+246
+00:49:18,360 --> 00:49:21,980
+Наше драгоценность прямо здесь. 
+
+247
+00:49:31,429 --> 00:49:39,309
+Повелитель, о чем ты задумался? Почему не берешь ее?
+
+248
+00:49:39,309 --> 00:49:40,847
+Моя драгоценность.
+
+249
+00:49:41,514 --> 00:49:44,150
+Пещера Изумрудных Облаков
+
+250
+00:49:44,250 --> 00:49:49,019
+Крошка, бери другую чашку. Пей.
+
+251
+00:49:53,909 --> 00:49:59,510
+Золотой царь драконов попросил, чтобы я выпил с ним сегодня вечером. 
+
+252
+00:49:59,510 --> 00:50:01,420
+Тогда вы должны пойти. 
+
+253
+00:50:01,469 --> 00:50:02,860
+Правильно. 
+
+254
+00:50:02,909 --> 00:50:06,610
+Подготовь золотое животное к дедушке.
+
+255
+00:50:06,670 --> 00:50:08,260
+Я мигом. 
+
+256
+00:50:08,320 --> 00:50:12,590
+Вы должны выпить поменьше сегодня вечером. 
+
+257
+00:50:12,630 --> 00:50:15,739
+Иначе я не смогу разбудить вас. 
+
+258
+00:50:15,800 --> 00:50:19,110
+Какой ужас, золотое глазастое животное дедушки исчезло!
+
+259
+00:50:19,150 --> 00:50:20,900
+Действительно ли вы - все тугоухие и слепые? 
+
+260
+00:50:20,949 --> 00:50:24,030
+Как оно могло просто исчезнуть? 
+
+261
+00:50:24,030 --> 00:50:27,900
+Крошка, не спорь. 
+
+262
+00:50:27,960 --> 00:50:31,710
+Я боюсь, что Джу Бацзе, возможно, украл его. 
+
+263
+00:50:31,750 --> 00:50:35,260
+Может мне лучше пойти к Пещере Листа Пальмы. 
+
+264
+00:50:35,320 --> 00:50:39,309
+Что? Все это заранее планировалось вами. 
+
+265
+00:50:42,280 --> 00:50:48,150
+Вы все еще хотите вернуться к той бессовестной женщине? 
+
+266
+00:50:48,190 --> 00:50:50,699
+Пожалуйста, крошка, не плачь.
+
+267
+00:50:50,750 --> 00:50:54,059
+Я скоро вернусь.
+
+
+268
+00:50:57,624 --> 00:51:01,194
+Пещера Листа Пальмы
+
+269
+00:51:02,670 --> 00:51:07,300
+Иди сюда, выпей немного! 
+
+270
+00:51:10,349 --> 00:51:12,460
+Теперь я могу быть спокоен. 
+
+271
+00:51:12,510 --> 00:51:16,699
+Мы можем не волноваться по поводу нашей драгоценности. 
+
+272
+00:51:16,750 --> 00:51:21,300
+Даже если бы они похитили веер, они бы все-равно не знали что надо тянуть шелковую нить. 
+
+273
+00:51:21,360 --> 00:51:26,269
+Одна жемчужина ни на что не способна.
+
+274
+00:51:26,309 --> 00:51:31,780
+Натягивание нити превращает ее в веер, правильно? 
+
+275
+00:51:35,119 --> 00:51:38,070
+Повелитель, ты пьян. 
+
+276
+00:51:38,110 --> 00:51:44,019
+Ты забыл как пользоваться собственной драгоценностью и спрашиваешь у меня. 
+
+277
+00:51:49,989 --> 00:51:53,690
+Женщина, посмотри, кто перед тобой.
+
+278
+00:52:00,320 --> 00:52:03,750
+Кто вы? 
+
+279
+00:52:03,789 --> 00:52:09,889
+Я - второй ученик танского монаха, Джу Бацзе.
+
+280
+00:52:09,949 --> 00:52:14,780
+Извини за беспокойство, и спасибо!
+
+281
+00:52:19,079 --> 00:52:21,710
+Пока!
+
+
+282
+00:53:06,829 --> 00:53:10,699
+Жена быка слишком кокетливая.
+
+283
+00:53:10,760 --> 00:53:14,710
+Все ее служанки красивы.
+
+284
+00:53:14,750 --> 00:53:24,809
+Старый Кабан почти не справился.
+
+285
+00:53:24,869 --> 00:53:28,860
+Используя умные уловки и тактику, 
+
+286
+00:53:28,909 --> 00:53:32,820
+я украл их драгоценность.
+
+287
+00:53:32,880 --> 00:53:36,789
+Это большой подвиг.
+
+288
+00:53:36,829 --> 00:53:38,300
+Монах Песков должен мне поклониться.
+
+289
+00:53:38,349 --> 00:53:40,730
+Обезьяне следует у меня поучиться.
+
+290
+00:53:40,789 --> 00:53:45,219
+Даже наставник будет удивлен.
+
+291
+00:53:45,280 --> 00:53:49,190
+Старый Кабан действительно лучше всех.
+
+292
+00:53:49,230 --> 00:53:54,349
+Старый Кабан действительно лучше всех.
+
+
+293
+00:54:36,719 --> 00:54:40,469
+Дурень, как идут дела?
+
+294
+00:54:40,510 --> 00:54:42,809
+Мало того, что я получил веер, 
+
+295
+00:54:42,880 --> 00:54:48,789
+Еще и принцесса Железный Веер полдня была моей женой. 
+
+296
+00:54:48,829 --> 00:54:51,699
+Тебе повезло.
+
+297
+00:54:58,150 --> 00:55:01,579
+Эй, покажи мне веер.
+
+298
+00:55:16,030 --> 00:55:20,219
+Почему ты уменьшил его?
+
+299
+00:55:40,550 --> 00:55:45,340
+Старая Свинья, ты узнаешь меня, верно? 
+
+300
+00:55:45,389 --> 00:55:49,170
+Прекрати шутить со мной.
+
+301
+00:55:49,230 --> 00:55:52,139
+А разве с тобой кто-нибудь шутит?
+
+
+302
+00:56:42,869 --> 00:56:45,380
+Дурень, как прошло?  
+
+303
+00:56:45,429 --> 00:56:47,099
+Ничего не вышло.
+
+304
+00:56:47,150 --> 00:56:49,980
+Унэн, ты достал веер? 
+
+305
+00:56:50,030 --> 00:56:53,340
+Я нашел Князя демонов, но он отказался. 
+
+306
+00:56:53,400 --> 00:56:59,190
+Тогда я превратился в него.
+
+307
+00:56:59,230 --> 00:57:03,539
+Хитростью я выманил веер у Принцессы. 
+
+308
+00:57:03,590 --> 00:57:10,590
+Но тогда Старый Бык превратился в тебя и тоже меня обманул. 
+
+309
+00:57:10,590 --> 00:57:12,739
+Старый Бык обладает большой волшебной силой. 
+
+310
+00:57:12,800 --> 00:57:16,150
+Он еще и меня побил.
+
+311
+00:57:16,190 --> 00:57:21,380
+Как же ты мог получить веер и оказаться таким дурнем? 
+
+312
+00:57:21,429 --> 00:57:25,659
+Не воображай! 
+
+313
+00:57:30,750 --> 00:57:34,369
+Не ссорьтесь, мы должны срочно что-то придумать. 
+
+314
+00:57:34,429 --> 00:57:40,260
+Найти какой... какой-нибудь обход, где нет огня? 
+
+315
+00:57:40,320 --> 00:57:47,070
+Из востока, юга, запада, севера, огонь распространяется только на Запад.  
+
+316
+00:57:47,119 --> 00:57:50,739
+Поэтому мы можем только повернуть.
+
+317
+00:57:50,789 --> 00:57:52,940
+Эта дорога закрыта для нас, что еще можно делать? 
+
+318
+00:57:52,989 --> 00:57:55,219
+Бадзе, не говори так. 
+
+319
+00:57:55,269 --> 00:57:59,139
+На нашей дороге всегда будут преграды. 
+
+320
+00:57:59,190 --> 00:58:04,539
+Чтобы завершить нашу священную задачу, мы должны быть сильными в нашей вере. 
+
+321
+00:58:04,590 --> 00:58:09,219
+Мы не можем повернуть на полпути, если мы столкнулись с препятствиями.
+
+322
+00:58:09,280 --> 00:58:14,590
+Причина нашего поражения в том, что мы не боремся вместе.
+
+323
+00:58:14,630 --> 00:58:17,139
+Если вы, трое, объединитесь, 
+
+324
+00:58:17,190 --> 00:58:20,500
+и общими усилиями будете сражаться с Князем Демонов, 
+
+325
+00:58:20,550 --> 00:58:22,849
+вы обязательно победите. 
+
+326
+00:58:22,909 --> 00:58:26,030
+Мы услышали наказ наставника 
+
+327
+00:58:26,030 --> 00:58:30,139
+и будем сражаться с Князем Демонов до конца. 
+
+328
+00:58:30,190 --> 00:58:34,260
+до...  до конца
+
+329
+00:58:34,320 --> 00:58:37,710
+Замечательно! 
+
+330
+00:58:37,750 --> 00:58:40,980
+Мы все справились с трудностями. 
+
+331
+00:58:41,039 --> 00:58:43,869
+Я надеюсь, каждый будет стараться 
+
+332
+00:58:43,869 --> 00:58:49,579
+вместе с моими учениками победить Князя Демонов и потушить пламя Огненной Горы. 
+
+333
+00:58:49,630 --> 00:58:52,820
+Иначе страдание никогда не кончится. 
+
+334
+00:58:53,869 --> 00:58:57,489
+Мы услышали наказ наставника, искать счастье для всех.  
+
+335
+00:58:57,550 --> 00:58:58,860
+Все объединяйтесь!
+
+336
+00:58:58,909 --> 00:59:00,519
+Хорошо!
+
+337
+01:08:23,229 --> 01:08:25,609
+Госпожа, какой ужас!
+
+338
+01:08:25,670 --> 01:08:30,789
+Господин пойман в ловушку, идите скорее! 
+
+339
+01:08:54,470 --> 01:08:56,699
+Борьба еще не решена, не решена.
+
+340
+01:08:56,760 --> 01:08:58,710
+Осторожно, осторожно.
+
+341
+01:08:59,760 --> 01:09:05,789
+Животное, все что ты должен - это отдать нам веер, и мы сохраним тебе жизнь.
+
+342
+01:09:05,840 --> 01:09:12,750
+Старый Бык, где веер? Отдай его!
+
+343
+01:09:12,789 --> 01:09:19,340
+Он... у моей жены.
+
+344
+01:09:25,239 --> 01:09:27,989
+Дорогая, милая.
+
+345
+01:09:28,029 --> 01:09:32,260
+Спаси меня скорее.
+
+346
+01:09:32,319 --> 01:09:35,109
+Отдай им веер.
+
+347
+01:09:35,149 --> 01:09:39,619
+Мой повелитель! Хорошо, хорошо!
+
+348
+01:09:43,399 --> 01:09:47,229
+Укун, иди еще раз!
+
+349
+01:12:30,850 --> 01:12:46,599
+Конец
+
diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt
new file mode 100644 (file)
index 0000000..3afc899
--- /dev/null
@@ -0,0 +1,1392 @@
+1\r
+00:00:01,080 --> 00:00:09,078\r
+片名:鐵扇公主\r
+\r
+2\r
+00:02:03,119 --> 00:02:09,280\r
+西遊記,本為一部絕妙之童話\r
+\r
+3\r
+00:02:09,280 --> 00:02:15,280\r
+特以世多誤解,致被目為神怪小說\r
+\r
+4\r
+00:02:15,280 --> 00:02:19,240\r
+本片取材於是\r
+\r
+5\r
+00:02:19,240 --> 00:02:24,240\r
+實為培育兒童心理而作\r
+\r
+6\r
+00:02:24,240 --> 00:02:29,280\r
+故內容刪蕪存精,不涉神怪\r
+\r
+7\r
+00:02:29,280 --> 00:02:32,560\r
+僅以唐僧等四人路阻火焰山\r
+\r
+8\r
+00:02:32,560 --> 00:02:41,040\r
+以示人生途徑中之磨難\r
+\r
+9\r
+00:02:41,040 --> 00:02:46,440\r
+欲求經此磨難,則必須堅持信念\r
+大眾一心\r
+\r
+10\r
+00:02:46,440 --> 00:02:52,436\r
+始能獲得此撲滅凶焰之芭蕉扇\r
+\r
+11\r
+00:03:34,480 --> 00:03:37,790\r
+現在已經秋天了,怎麼還這麼熱\r
+\r
+12\r
+00:03:37,840 --> 00:03:42,356\r
+呆子,不要說廢話,趕路要緊\r
+\r
+13\r
+00:04:06,920 --> 00:04:09,354\r
+悟空,這是到了什麼地方\r
+\r
+14\r
+00:04:09,400 --> 00:04:13,678\r
+反正是我們上西天必定要經過的地方\r
+\r
+15\r
+00:04:13,720 --> 00:04:18,111\r
+我們沒有走錯路線吧\r
+\r
+16\r
+00:04:18,159 --> 00:04:22,311\r
+為什麼這個地方這麼樣的熱呢\r
+\r
+17\r
+00:04:30,039 --> 00:04:31,711\r
+師傅,你看\r
+\r
+18\r
+00:04:31,759 --> 00:04:33,795\r
+前面那兒,不是有一座房子了嗎\r
+\r
+19\r
+00:04:33,839 --> 00:04:38,117\r
+我們大家進去歇息一會兒好吧\r
+\r
+20\r
+00:04:59,399 --> 00:05:02,914\r
+這個地方名叫火焰山\r
+\r
+21\r
+00:05:02,959 --> 00:05:06,031\r
+周圍有幾百里的火焰\r
+\r
+22\r
+00:05:06,079 --> 00:05:08,752\r
+一根草都不生\r
+\r
+23\r
+00:05:08,799 --> 00:05:11,632\r
+一年四季都是熱的\r
+\r
+24\r
+00:05:11,680 --> 00:05:19,633\r
+就是銅頭鐵臂要經過那個山\r
+也得融化成水\r
+\r
+25\r
+00:05:19,679 --> 00:05:23,592\r
+哪有這種事,師傅,你請放心\r
+\r
+26\r
+00:05:23,639 --> 00:05:27,154\r
+我們三個人都有法子可以過去\r
+\r
+27\r
+00:05:27,199 --> 00:05:30,714\r
+師傅,我去看看好吧\r
+\r
+28\r
+00:08:06,319 --> 00:08:09,595\r
+悟空,你去看了怎麼樣\r
+\r
+29\r
+00:08:09,639 --> 00:08:11,834\r
+厲害,厲害,真厲言\r
+\r
+30\r
+00:08:11,880 --> 00:08:15,919\r
+要不是我跑得快,尾巴都燒光了\r
+\r
+31\r
+00:08:42,720 --> 00:08:47,600\r
+老施主,這裡的火這樣大\r
+\r
+32\r
+00:08:47,600 --> 00:08:49,670\r
+這五穀從哪兒來的\r
+\r
+33\r
+00:08:49,719 --> 00:08:53,997\r
+你看這兒有一千多里的路\r
+有一位鐵扇公主\r
+\r
+34\r
+00:08:54,040 --> 00:08:56,508\r
+她有一把芭蕉扇\r
+\r
+35\r
+00:08:56,560 --> 00:08:59,074\r
+一扇呢,火就熄了\r
+\r
+36\r
+00:08:59,120 --> 00:09:01,634\r
+兩扇呢,風就來了\r
+\r
+37\r
+00:09:01,680 --> 00:09:03,989\r
+三扇呢,就下雨了\r
+\r
+38\r
+00:09:04,040 --> 00:09:07,510\r
+我們就從這個時候播種收割\r
+\r
+39\r
+00:09:07,560 --> 00:09:11,348\r
+不過,要請那位公主來\r
+\r
+40\r
+00:09:11,400 --> 00:09:14,870\r
+可不是一件容易的事\r
+\r
+41\r
+00:09:14,919 --> 00:09:16,830\r
+她住在什麼地方\r
+\r
+42\r
+00:09:16,880 --> 00:09:20,190\r
+她住在翠雲山芭蕉洞\r
+\r
+43\r
+00:09:20,240 --> 00:09:23,676\r
+是她一個人住在那兒嗎\r
+\r
+44\r
+00:09:23,720 --> 00:09:25,756\r
+她有沒有丈夫啊\r
+\r
+45\r
+00:09:25,800 --> 00:09:29,588\r
+她的丈夫是牛魔王\r
+\r
+46\r
+00:09:29,640 --> 00:09:32,200\r
+原來是老牛\r
+\r
+47\r
+00:09:32,240 --> 00:09:36,791\r
+呆子,你竟然認識他嗎?\r
+跟我一塊兒借扇子去\r
+\r
+48\r
+00:09:36,840 --> 00:09:41,755\r
+我…我知道老牛不住在那兒的\r
+\r
+49\r
+00:09:41,800 --> 00:09:46,351\r
+在他男人不在家的時候\r
+我們去找他的女人\r
+\r
+50\r
+00:09:46,400 --> 00:09:51,520\r
+這…這有點不大方便吧\r
+\r
+51\r
+00:09:51,560 --> 00:09:58,318\r
+你們…兩個人…去吧\r
+\r
+52\r
+00:09:58,360 --> 00:10:05,198\r
+我…我在…這兒…伺候師父\r
+\r
+53\r
+00:10:05,240 --> 00:10:11,270\r
+悟淨,你也跟你兩個師兄一同去吧\r
+\r
+54\r
+00:10:47,200 --> 00:10:51,557\r
+呆子,每次都是我去打頭陣的\r
+\r
+55\r
+00:10:51,600 --> 00:10:54,353\r
+這次該你去了\r
+\r
+56\r
+00:10:58,520 --> 00:11:04,914\r
+三弟,每次都是我去打頭陣\r
+這次該你去了\r
+\r
+57\r
+00:11:04,960 --> 00:11:06,837\r
+大師兄\r
+\r
+58\r
+00:11:06,880 --> 00:11:10,998\r
+我叫你去給師父出一點力\r
+你都不肯嗎\r
+\r
+59\r
+00:11:11,040 --> 00:11:14,316\r
+快去…\r
+\r
+60\r
+00:11:39,640 --> 00:11:43,040\r
+你是哪兒跑來的野和尚\r
+\r
+61\r
+00:11:43,040 --> 00:11:49,878\r
+大唐…聖僧…要你家…大公主…\r
+\r
+62\r
+00:11:49,920 --> 00:11:52,480\r
+胡說\r
+\r
+63\r
+00:12:47,559 --> 00:12:52,075\r
+大…大師兄,還是你去吧\r
+\r
+64\r
+00:12:52,120 --> 00:12:56,955\r
+呆子,你去\r
+\r
+65\r
+00:12:57,000 --> 00:13:00,709\r
+大師兄,還是你去吧\r
+\r
+66\r
+00:13:04,039 --> 00:13:07,475\r
+偷懶的東西\r
+\r
+67\r
+00:13:54,280 --> 00:13:57,909\r
+好雷公菩薩,你饒了我放了我吧\r
+\r
+68\r
+00:13:57,960 --> 00:13:59,951\r
+你跟你們公主說\r
+\r
+69\r
+00:14:00,000 --> 00:14:03,280\r
+我孫悟空要來借芭蕉扇\r
+\r
+70\r
+00:14:03,280 --> 00:14:08,400\r
+好,好,你放了我,我就去\r
+\r
+71\r
+00:14:29,560 --> 00:14:37,069\r
+奶奶,外面有一個孫悟空\r
+要來借芭蕉扇\r
+\r
+72\r
+00:14:41,520 --> 00:14:44,159\r
+快拿我的劍來\r
+\r
+73\r
+00:15:01,640 --> 00:15:04,154\r
+孫悟空,害我兒子的仇人\r
+\r
+74\r
+00:15:04,200 --> 00:15:08,557\r
+你今天也敢自己來送死嗎\r
+\r
+75\r
+00:15:08,600 --> 00:15:12,040\r
+我是從來沒見過你,怎麼會害你的兒子\r
+\r
+76\r
+00:15:12,040 --> 00:15:15,794\r
+我的孩子紅孩兒不是你害死的嗎\r
+\r
+77\r
+00:15:15,840 --> 00:15:20,391\r
+令郎已成正果,怎麼說老孫害他呢\r
+\r
+78\r
+00:15:20,440 --> 00:15:23,750\r
+少說廢話,伸過頭來讓我砍幾劍\r
+\r
+79\r
+00:15:23,800 --> 00:15:26,155\r
+受得住我就把芭蕉扇借給你\r
+\r
+80\r
+00:15:26,200 --> 00:15:28,555\r
+真的嗎\r
+\r
+81\r
+00:15:56,800 --> 00:16:00,634\r
+慢著,快把扇子借給我\r
+\r
+82\r
+00:17:53,639 --> 00:18:00,112\r
+大聖不保唐僧到西天去\r
+來到這兒做什麼\r
+\r
+83\r
+00:18:11,159 --> 00:18:17,155\r
+我被鐵扇公主一扇扇到這兒來的\r
+\r
+84\r
+00:18:17,199 --> 00:18:23,877\r
+大聖你來得巧極了\r
+我有一樣東西送給你\r
+\r
+85\r
+00:18:28,519 --> 00:18:33,468\r
+這裡是一粒定風珠,大聖你有了這珠子\r
+\r
+86\r
+00:18:33,519 --> 00:18:36,158\r
+可以使你的心堅定了\r
+\r
+87\r
+00:18:36,199 --> 00:18:39,191\r
+保那鐵扇公主扇不動你了\r
+\r
+88\r
+00:18:39,239 --> 00:18:42,868\r
+大聖你來看\r
+\r
+89\r
+00:19:00,439 --> 00:19:02,555\r
+謝謝\r
+\r
+90\r
+00:19:06,079 --> 00:19:12,314\r
+大…大師兄…不知給…\r
+\r
+91\r
+00:19:12,359 --> 00:19:18,707\r
+吹到什麼…地方去了\r
+\r
+92\r
+00:19:18,759 --> 00:19:26,109\r
+管他呢,讓猴子也吃點舌頭,我們走\r
+\r
+93\r
+00:19:35,199 --> 00:19:37,269\r
+大…大…師兄\r
+\r
+94\r
+00:19:37,319 --> 00:19:43,479\r
+你…被…被…那…\r
+\r
+95\r
+00:19:43,479 --> 00:19:50,237\r
+大師兄,你被那個婆娘扇到\r
+什麼地方去了\r
+\r
+96\r
+00:19:50,279 --> 00:19:57,196\r
+呆子,現在總該你去了\r
+\r
+97\r
+00:19:57,239 --> 00:20:00,948\r
+我不去,我要是被她一扇\r
+\r
+98\r
+00:20:00,999 --> 00:20:03,467\r
+簡直就認不得回來了\r
+\r
+99\r
+00:20:03,519 --> 00:20:09,719\r
+還是…你再去一趟吧\r
+\r
+100\r
+00:20:09,719 --> 00:20:12,233\r
+不去,不去\r
+\r
+101\r
+00:20:17,799 --> 00:20:22,793\r
+下次輪到你,可不准再偷懶了\r
+\r
+102\r
+00:20:56,159 --> 00:21:00,152\r
+這次你儘管扇,扇得我動一動\r
+\r
+103\r
+00:21:00,199 --> 00:21:05,227\r
+我不算男子漢大丈夫\r
+\r
+104\r
+00:21:33,679 --> 00:21:38,594\r
+大師兄,怎麼這回\r
+她的扇子沒有用啊\r
+\r
+105\r
+00:21:46,839 --> 00:21:50,115\r
+我們來打進去\r
+\r
+106\r
+00:23:59,639 --> 00:24:04,190\r
+快把芭蕉拿出來,給我孫悟空用一用\r
+\r
+107\r
+00:24:14,879 --> 00:24:16,915\r
+孫悟空,你在什麼地方\r
+\r
+108\r
+00:24:16,959 --> 00:24:19,996\r
+我在你肚子裡呢\r
+\r
+109\r
+00:24:45,759 --> 00:24:48,557\r
+孫悟空,你饒了我的命吧\r
+\r
+110\r
+00:24:48,599 --> 00:24:51,193\r
+你把扇子拿出來就是了\r
+\r
+111\r
+00:24:51,239 --> 00:24:56,552\r
+我答應你就是了,請你快點出來吧\r
+\r
+112\r
+00:25:00,239 --> 00:25:02,833\r
+快把扇子拿來\r
+\r
+113\r
+00:25:07,439 --> 00:25:09,236\r
+扇子已經來了\r
+\r
+114\r
+00:25:09,280 --> 00:25:12,078\r
+孫悟空你怎麼還不出來呢\r
+\r
+115\r
+00:25:12,119 --> 00:25:16,635\r
+你把嘴張開來,我就出來了\r
+\r
+116\r
+00:25:25,359 --> 00:25:29,432\r
+孫祖宗,你怎麼還不出來呢\r
+\r
+117\r
+00:25:50,359 --> 00:25:55,592\r
+我在這兒呢,借給我用用就還你的\r
+\r
+118\r
+00:26:32,559 --> 00:26:36,598\r
+師父等了好久了,我們快去吧\r
+\r
+119\r
+00:27:01,879 --> 00:27:04,916\r
+經,經是什麼\r
+\r
+120\r
+00:27:04,959 --> 00:27:10,039\r
+經是天地之間不能辨易的道理\r
+\r
+121\r
+00:27:10,039 --> 00:27:14,191\r
+這個道理也就是做人的道理\r
+\r
+122\r
+00:27:14,239 --> 00:27:18,710\r
+任何一個人有了這個道理\r
+\r
+123\r
+00:27:18,759 --> 00:27:25,358\r
+才可以免去諸般痛苦\r
+好好的安居樂業\r
+\r
+124\r
+00:27:25,399 --> 00:27:29,950\r
+實實在在的過日子\r
+\r
+125\r
+00:27:34,680 --> 00:27:36,352\r
+反過來說\r
+\r
+126\r
+00:27:36,399 --> 00:27:40,108\r
+要是做人不曉得這個道理\r
+\r
+127\r
+00:27:40,159 --> 00:27:46,394\r
+就跟沉陷在苦海裡頭一樣\r
+一生一世\r
+\r
+128\r
+00:27:46,439 --> 00:27:52,628\r
+甚至於子孫孫,都得不到幸福\r
+\r
+129\r
+00:27:52,679 --> 00:27:55,671\r
+我為什麼要去取經\r
+\r
+130\r
+00:27:55,719 --> 00:28:01,316\r
+就是因為現在的人都陷在苦海裡了\r
+\r
+131\r
+00:28:01,359 --> 00:28:04,192\r
+要想成就這此些人\r
+\r
+132\r
+00:28:04,239 --> 00:28:12,510\r
+所以在大唐皇帝面前討下這\r
+重大繁難的差事\r
+\r
+133\r
+00:28:15,679 --> 00:28:17,829\r
+芭蕉扇借到了沒有\r
+\r
+134\r
+00:28:17,879 --> 00:28:19,517\r
+借來了\r
+\r
+135\r
+00:28:19,559 --> 00:28:22,790\r
+是不是這個\r
+\r
+136\r
+00:28:22,839 --> 00:28:27,993\r
+諸位施主,現在扇子既然借到了\r
+\r
+137\r
+00:28:28,039 --> 00:28:32,157\r
+貧僧師徒就要告辭了\r
+\r
+138\r
+00:28:32,199 --> 00:28:34,040\r
+慢一點\r
+\r
+139\r
+00:28:34,040 --> 00:28:39,797\r
+諸位,我想留聖僧在這兒多住幾天\r
+\r
+140\r
+00:28:39,839 --> 00:28:41,352\r
+好不好啊\r
+\r
+141\r
+00:28:41,399 --> 00:28:43,469\r
+好的,好的\r
+\r
+142\r
+00:28:43,519 --> 00:28:45,908\r
+謝謝諸位的好意\r
+\r
+143\r
+00:28:45,959 --> 00:28:51,795\r
+我早走一步就是早一步完成\r
+我們的任務\r
+\r
+144\r
+00:28:51,839 --> 00:28:56,196\r
+那麼就請令高徒先到火焰山\r
+\r
+145\r
+00:28:56,239 --> 00:29:02,155\r
+扇滅了火之後,再陪聖僧同行\r
+\r
+146\r
+00:29:02,199 --> 00:29:05,475\r
+好,你就去吧\r
+\r
+147\r
+00:30:24,479 --> 00:30:30,039\r
+鐵扇公主真可惡,拿假的芭蕉扇\r
+來騙我\r
+\r
+148\r
+00:30:30,039 --> 00:30:32,792\r
+我非殺了她不可\r
+\r
+149\r
+00:30:32,839 --> 00:30:36,309\r
+不,殺了她也是枉然\r
+\r
+150\r
+00:30:36,359 --> 00:30:39,590\r
+我素來不願意你多殺人\r
+\r
+151\r
+00:30:39,639 --> 00:30:42,995\r
+我們再想辦法\r
+\r
+152\r
+00:30:52,159 --> 00:30:56,232\r
+師兄,怎麼你也會上她的當\r
+\r
+153\r
+00:30:56,279 --> 00:30:58,554\r
+費了這麼許多的力氣\r
+\r
+154\r
+00:30:58,599 --> 00:31:02,114\r
+卻弄了一把假的扇子來\r
+\r
+155\r
+00:31:02,159 --> 00:31:06,516\r
+笑話,笑話\r
+\r
+156\r
+00:31:08,919 --> 00:31:10,432\r
+那麼你去\r
+\r
+157\r
+00:31:10,479 --> 00:31:14,392\r
+好好,我去我去,我就去\r
+\r
+158\r
+00:31:14,439 --> 00:31:17,033\r
+我去找牛魔王\r
+\r
+159\r
+00:31:17,119 --> 00:31:19,952\r
+這倒是一個好辦法\r
+\r
+160\r
+00:31:21,399 --> 00:31:24,550\r
+師兄,你看好不好\r
+\r
+161\r
+00:31:24,599 --> 00:31:27,397\r
+好,看你的了\r
+\r
+162\r
+00:33:07,199 --> 00:33:11,159\r
+你看我今天化妝得好嗎\r
+\r
+163\r
+00:33:11,159 --> 00:33:13,798\r
+好極了,我的小寶貝\r
+\r
+164\r
+00:33:13,839 --> 00:33:17,070\r
+你陪我到洞外頭去走走,好不好\r
+\r
+165\r
+00:33:17,119 --> 00:33:21,556\r
+我的寶貝,還是你一個人去吧\r
+\r
+166\r
+00:33:21,599 --> 00:33:24,830\r
+本來嘛,我們這種草婆子\r
+\r
+167\r
+00:33:24,879 --> 00:33:28,030\r
+跟你出去了會使你丟臉的\r
+\r
+168\r
+00:33:28,079 --> 00:33:32,039\r
+小寶貝,這是什麼話呢\r
+\r
+169\r
+00:33:32,039 --> 00:33:37,511\r
+你先去,我隨後就來好不好\r
+\r
+170\r
+00:35:28,039 --> 00:35:35,673\r
+女菩薩,你真是天仙下凡\r
+\r
+171\r
+00:35:35,719 --> 00:35:37,914\r
+你…你是什麼人\r
+\r
+172\r
+00:35:37,959 --> 00:35:41,474\r
+我是從芭蕉洞來找牛魔王的\r
+\r
+173\r
+00:35:41,520 --> 00:35:43,988\r
+快放手\r
+\r
+174\r
+00:35:49,559 --> 00:35:52,949\r
+女菩薩,你慢點走\r
+\r
+175\r
+00:36:44,239 --> 00:36:49,233\r
+小寶貝,誰來欺負你\r
+\r
+176\r
+00:36:49,279 --> 00:36:50,837\r
+是你\r
+\r
+177\r
+00:36:50,879 --> 00:36:54,349\r
+我哪裡捨得欺負你呢\r
+\r
+178\r
+00:36:56,919 --> 00:36:59,274\r
+你還是回芭蕉洞去吧\r
+\r
+179\r
+00:36:59,320 --> 00:37:01,709\r
+省得那個不要臉的東西\r
+\r
+180\r
+00:37:01,759 --> 00:37:07,675\r
+時常派人來請你,欺負我\r
+\r
+181\r
+00:37:07,719 --> 00:37:11,075\r
+你說有人來找我\r
+\r
+182\r
+00:37:11,119 --> 00:37:15,078\r
+外邊有一個豬臉的和尚來請你\r
+\r
+183\r
+00:37:15,120 --> 00:37:18,510\r
+差一點把我嚇死了\r
+\r
+184\r
+00:37:18,559 --> 00:37:22,757\r
+真有這回事嗎?待我出去看一看\r
+\r
+185\r
+00:37:50,679 --> 00:37:53,796\r
+牛大哥\r
+\r
+186\r
+00:37:53,839 --> 00:37:58,151\r
+這裡頭有個頂漂亮的小娘們\r
+\r
+187\r
+00:37:58,200 --> 00:38:03,991\r
+呸,那是我的女人,你為什麼要欺負她\r
+\r
+188\r
+00:38:04,039 --> 00:38:08,559\r
+大哥,我不知那就是二嫂,請原瓊\r
+\r
+189\r
+00:38:08,559 --> 00:38:11,949\r
+不知道不見罪,好啊,你走啊\r
+\r
+190\r
+00:38:11,999 --> 00:38:16,117\r
+不不不,我還有事情請大哥幫忙\r
+\r
+191\r
+00:38:18,479 --> 00:38:24,719\r
+小弟保唐僧取經,路過火焰山\r
+\r
+192\r
+00:38:24,719 --> 00:38:27,313\r
+請大哥跟嫂子說一聲\r
+\r
+193\r
+00:38:27,359 --> 00:38:30,829\r
+把這個芭蕉扇借來用一用\r
+\r
+194\r
+00:38:30,880 --> 00:38:33,519\r
+不成,那唐僧和孫悟空\r
+\r
+195\r
+00:38:33,519 --> 00:38:35,191\r
+是我孩子的仇人\r
+\r
+196\r
+00:38:35,239 --> 00:38:38,754\r
+我正要抓他們報仇\r
+\r
+197\r
+00:38:38,799 --> 00:38:44,988\r
+令郎已成正果,請大哥不必再計較吧\r
+\r
+198\r
+00:38:45,039 --> 00:38:48,952\r
+好,看在我們從前的交情\r
+我不跟你計較\r
+\r
+199\r
+00:38:49,000 --> 00:38:51,719\r
+那麼去吧\r
+\r
+200\r
+00:39:38,399 --> 00:39:44,190\r
+寶貝,那個豬臉和尚\r
+是我從前一個朋友\r
+\r
+201\r
+00:39:44,239 --> 00:39:46,514\r
+並不是芭蕉洞派來的\r
+\r
+202\r
+00:39:46,559 --> 00:39:47,753\r
+我不相信\r
+\r
+203\r
+00:39:47,799 --> 00:39:50,950\r
+我不騙你\r
+\r
+204\r
+00:39:50,999 --> 00:39:54,036\r
+現在那個和尚到哪兒去了呢\r
+\r
+205\r
+00:39:54,119 --> 00:39:57,794\r
+已經被我打走了\r
+\r
+206\r
+00:43:58,639 --> 00:44:01,358\r
+大王回來了\r
+\r
+207\r
+00:44:01,399 --> 00:44:02,388\r
+奶奶呢\r
+\r
+208\r
+00:44:02,439 --> 00:44:04,794\r
+在裡邊\r
+\r
+209\r
+00:44:42,999 --> 00:44:48,232\r
+今天是什麼風會把大王吹到這兒來的\r
+\r
+210\r
+00:44:48,279 --> 00:44:52,272\r
+聽到孫悟空保唐僧快到這兒\r
+\r
+211\r
+00:44:52,320 --> 00:44:56,916\r
+恐怕他要來借芭蕉扇過火焰山\r
+\r
+212\r
+00:44:56,959 --> 00:45:00,872\r
+那猴子是害我們兒子的仇人\r
+\r
+213\r
+00:45:00,919 --> 00:45:08,507\r
+早晚來了抓著他,讓我們夫妻出出恨\r
+\r
+214\r
+00:45:08,559 --> 00:45:12,711\r
+夫人,你為什麼哭\r
+\r
+215\r
+00:45:12,759 --> 00:45:15,717\r
+那猴子已經來過了\r
+\r
+216\r
+00:45:15,759 --> 00:45:18,876\r
+是我不肯把扇子借給他\r
+\r
+217\r
+00:45:18,919 --> 00:45:22,275\r
+不知道怎麼會跑到我的肚子裡來\r
+\r
+218\r
+00:45:22,319 --> 00:45:25,516\r
+弄得我肚子痛得要命\r
+\r
+219\r
+00:45:25,559 --> 00:45:31,399\r
+後來我沒有法子,只好把扇子借給他\r
+\r
+220\r
+00:45:31,399 --> 00:45:38,271\r
+可惜可惜,你怎麼把扇子借給他\r
+\r
+221\r
+00:45:38,320 --> 00:45:40,470\r
+拿去的是假的\r
+\r
+222\r
+00:45:40,519 --> 00:45:43,033\r
+假的\r
+\r
+223\r
+00:46:14,199 --> 00:46:19,876\r
+開筵慶祝大王歸\r
+\r
+224\r
+00:46:19,919 --> 00:46:25,630\r
+好酒殷勤勸幾杯\r
+\r
+225\r
+00:46:25,679 --> 00:46:34,189\r
+雞又香,鴨又美,豬又肥\r
+\r
+226\r
+00:46:34,240 --> 00:46:45,674\r
+我盡量的歌,我盡量的舞\r
+\r
+227\r
+00:46:45,719 --> 00:46:54,514\r
+你也要盡量的醉\r
+\r
+228\r
+00:47:03,599 --> 00:47:16,399\r
+大王啊,你把舊人丟\r
+\r
+229\r
+00:47:16,439 --> 00:47:22,628\r
+你愛新人媚\r
+\r
+230\r
+00:47:22,679 --> 00:47:36,673\r
+為你淌了多少相思淚\r
+\r
+231\r
+00:47:46,719 --> 00:47:55,718\r
+等一會燈兒吹帳兒垂\r
+\r
+232\r
+00:47:55,759 --> 00:48:00,879\r
+你獨自兒睡\r
+\r
+233\r
+00:48:00,879 --> 00:48:05,519\r
+也嘗嘗這個淒涼味\r
+\r
+234\r
+00:48:05,519 --> 00:48:13,437\r
+恕我不奉陪\r
+\r
+235\r
+00:48:18,559 --> 00:48:24,634\r
+就是同床\r
+\r
+236\r
+00:48:24,679 --> 00:48:34,350\r
+我們各人蓋著各人的被\r
+\r
+237\r
+00:48:38,399 --> 00:48:42,392\r
+大王,我醉了\r
+\r
+238\r
+00:48:55,079 --> 00:48:58,151\r
+夫人,那真扇子你放在什麼地方\r
+\r
+239\r
+00:48:58,199 --> 00:49:05,469\r
+那猴子花樣很多,而且那豬八戒\r
+本事更大\r
+\r
+240\r
+00:49:05,519 --> 00:49:09,797\r
+當心給他們騙了去\r
+\r
+241\r
+00:49:18,360 --> 00:49:21,989\r
+寶貝不是在這兒嗎\r
+\r
+242\r
+00:49:31,439 --> 00:49:39,319\r
+大王,你出神想什麼呢?\r
+還是收了吧\r
+\r
+243\r
+00:49:39,319 --> 00:49:43,551\r
+小寶貝\r
+\r
+244\r
+00:49:43,599 --> 00:49:49,037\r
+寶貝,你多喝一杯,你喝啊\r
+\r
+245\r
+00:49:53,919 --> 00:49:59,519\r
+今兒晚上,金龍大王\r
+還要請我去喝酒呢\r
+\r
+246\r
+00:49:59,519 --> 00:50:01,430\r
+那你就該去了\r
+\r
+247\r
+00:50:01,479 --> 00:50:02,878\r
+是的\r
+\r
+248\r
+00:50:02,919 --> 00:50:06,628\r
+你去替爺爺把金睛獸牽出去預備好\r
+\r
+249\r
+00:50:06,679 --> 00:50:08,271\r
+是\r
+\r
+250\r
+00:50:08,320 --> 00:50:12,598\r
+可是,你今兒個晚上去要少喝一點兒\r
+\r
+251\r
+00:50:12,639 --> 00:50:15,756\r
+免得回來睡著叫不醒你\r
+\r
+252\r
+00:50:15,800 --> 00:50:19,110\r
+不好了,爺爺那個金隋獸不見了\r
+\r
+253\r
+00:50:19,159 --> 00:50:20,911\r
+你們全都是死人嗎\r
+\r
+254\r
+00:50:20,959 --> 00:50:24,039\r
+家裡頭的東西怎麼會不見了呢\r
+\r
+255\r
+00:50:24,039 --> 00:50:27,918\r
+寶貝,不要管他們吧\r
+\r
+256\r
+00:50:27,960 --> 00:50:31,714\r
+恐怕是那豬八戒偷了去了\r
+\r
+257\r
+00:50:31,759 --> 00:50:35,274\r
+說不定我要到芭蕉洞去一趟\r
+\r
+258\r
+00:50:35,320 --> 00:50:39,313\r
+原來是你們做好了的圈套\r
+\r
+259\r
+00:50:42,280 --> 00:50:48,150\r
+你還是要到那個不要臉的女人那兒去\r
+\r
+260\r
+00:50:48,199 --> 00:50:50,713\r
+好寶貝,你不要哭了\r
+\r
+261\r
+00:50:50,759 --> 00:50:54,069\r
+我去去就來的\r
+\r
+262\r
+00:51:02,679 --> 00:51:07,309\r
+來來,喝喝\r
+\r
+263\r
+00:51:10,359 --> 00:51:12,475\r
+我現在放心了\r
+\r
+264\r
+00:51:12,519 --> 00:51:16,717\r
+不怕他們偷我們的寶貝\r
+\r
+265\r
+00:51:16,759 --> 00:51:21,310\r
+他們就是偷了去\r
+不知道把那絲線一拉\r
+\r
+266\r
+00:51:21,360 --> 00:51:26,275\r
+單是一顆珠子也沒有用處啊\r
+\r
+267\r
+00:51:26,319 --> 00:51:31,791\r
+是不是那麼一拉就變成扇子\r
+\r
+268\r
+00:51:35,120 --> 00:51:38,078\r
+大王,你今天喝醉了\r
+\r
+269\r
+00:51:38,119 --> 00:51:44,035\r
+自己的寶貝都忘了,還來問我\r
+\r
+270\r
+00:51:49,999 --> 00:51:53,708\r
+娘子,你看看我是誰\r
+\r
+271\r
+00:52:00,320 --> 00:52:03,756\r
+你是什麼人\r
+\r
+272\r
+00:52:03,799 --> 00:52:09,908\r
+我是唐僧的二徒弟,豬八戒\r
+\r
+273\r
+00:52:09,959 --> 00:52:14,794\r
+對不住,謝謝你,打擾了\r
+\r
+274\r
+00:52:19,080 --> 00:52:21,719\r
+再見\r
+\r
+275\r
+00:53:06,839 --> 00:53:10,718\r
+牛大嫂太風騷\r
+\r
+276\r
+00:53:10,760 --> 00:53:14,719\r
+眾小妖都俊俏\r
+\r
+277\r
+00:53:14,759 --> 00:53:24,828\r
+老豬真有點受不了\r
+\r
+278\r
+00:53:24,879 --> 00:53:28,872\r
+心機巧,手段妙\r
+\r
+279\r
+00:53:28,919 --> 00:53:32,832\r
+居然騙得了無價寶\r
+\r
+280\r
+00:53:32,880 --> 00:53:36,793\r
+這一番勞苦功高\r
+\r
+281\r
+00:53:36,839 --> 00:53:38,318\r
+沙僧該拜倒\r
+\r
+282\r
+00:53:38,359 --> 00:53:40,748\r
+猴兒該領教\r
+\r
+283\r
+00:53:40,799 --> 00:53:45,236\r
+師父也要嚇一跳\r
+\r
+284\r
+00:53:45,280 --> 00:53:49,193\r
+我老豬也有今朝\r
+\r
+285\r
+00:53:49,239 --> 00:53:54,359\r
+我老豬也有今朝\r
+\r
+286\r
+00:54:36,720 --> 00:54:40,474\r
+呆子,事情辦得怎麼樣了\r
+\r
+287\r
+00:54:40,519 --> 00:54:42,828\r
+不僅扇子到手\r
+\r
+288\r
+00:54:42,880 --> 00:54:48,796\r
+鐵扇公主並且還做了我\r
+半天的老婆\r
+\r
+289\r
+00:54:48,839 --> 00:54:51,717\r
+這倒便宜了你了\r
+\r
+290\r
+00:54:58,159 --> 00:55:01,595\r
+扇子拿來給我看看\r
+\r
+291\r
+00:55:16,039 --> 00:55:20,237\r
+你怎麼會把它縮小了的呀\r
+\r
+292\r
+00:55:40,559 --> 00:55:45,349\r
+老豬,你可認識我嗎\r
+\r
+293\r
+00:55:45,399 --> 00:55:49,187\r
+你不要跟我開玩笑了\r
+\r
+294\r
+00:55:49,239 --> 00:55:52,151\r
+誰跟你開玩笑\r
+\r
+295\r
+00:56:42,879 --> 00:56:45,393\r
+呆子,你去了怎麼樣\r
+\r
+296\r
+00:56:45,439 --> 00:56:47,111\r
+白跑了一趟\r
+\r
+297\r
+00:56:47,159 --> 00:56:49,992\r
+悟能,扇子借來沒有\r
+\r
+298\r
+00:56:50,039 --> 00:56:53,349\r
+我去找牛魔王,他不肯借\r
+\r
+299\r
+00:56:53,400 --> 00:56:59,191\r
+後來,我又變成老牛的樣子\r
+\r
+300\r
+00:56:59,239 --> 00:57:03,551\r
+在鐵扇公主那兒把扇子已經騙過來了\r
+\r
+301\r
+00:57:03,599 --> 00:57:10,599\r
+誰知道他又變成你的樣子又給他騙回去了\r
+\r
+302\r
+00:57:10,599 --> 00:57:12,749\r
+老牛的本領大\r
+\r
+303\r
+00:57:12,800 --> 00:57:16,156\r
+我還被他揍了一頓呢\r
+\r
+304\r
+00:57:16,199 --> 00:57:21,398\r
+呆子,你能辦這樣大的事那\r
+還算是呆子嗎\r
+\r
+305\r
+00:57:21,439 --> 00:57:25,671\r
+事情不都環在你頭上\r
+\r
+306\r
+00:57:30,759 --> 00:57:34,388\r
+你們不要吵了,趕緊再想辦法\r
+\r
+307\r
+00:57:34,439 --> 00:57:40,275\r
+哪一方…沒…沒有火啊\r
+\r
+308\r
+00:57:40,320 --> 00:57:47,078\r
+東南西北,只有西方有火\r
+\r
+309\r
+00:57:47,120 --> 00:57:50,749\r
+那我們不是要走回去了嗎\r
+\r
+310\r
+00:57:50,799 --> 00:57:52,949\r
+這路不通,不回去怎麼樣呢\r
+\r
+311\r
+00:57:52,999 --> 00:57:55,229\r
+八戒,你不要這樣說\r
+\r
+312\r
+00:57:55,279 --> 00:57:59,158\r
+要成功一件事情總是有阻礙的\r
+\r
+313\r
+00:57:59,199 --> 00:58:04,557\r
+我們要做這樣神聖的事情\r
+就要堅定我們的信念\r
+\r
+314\r
+00:58:04,599 --> 00:58:09,229\r
+不能因為有一點兒困難\r
+就中適改變我們的宗旨\r
+\r
+315\r
+00:58:09,280 --> 00:58:14,593\r
+你們這次失敗的原因是由於\r
+既不同心又不合力\r
+\r
+316\r
+00:58:14,639 --> 00:58:17,153\r
+假使你們三個人一條心\r
+\r
+317\r
+00:58:17,199 --> 00:58:20,509\r
+合起力量,共同跟牛魔王決鬥\r
+\r
+318\r
+00:58:20,559 --> 00:58:22,868\r
+事情一定可以成功的\r
+\r
+319\r
+00:58:22,919 --> 00:58:26,039\r
+我們謹遵師父的命令\r
+\r
+320\r
+00:58:26,039 --> 00:58:30,157\r
+去跟牛魔王爭一個誰勝誰敗\r
+\r
+321\r
+00:58:30,199 --> 00:58:34,272\r
+誰…誰…誰勝誰敗\r
+\r
+322\r
+00:58:34,320 --> 00:58:37,710\r
+那就好極了\r
+\r
+323\r
+00:58:37,759 --> 00:58:40,990\r
+各位受他的害處也不小了\r
+\r
+324\r
+00:58:41,040 --> 00:58:43,879\r
+希望各位也出此些力量\r
+\r
+325\r
+00:58:43,879 --> 00:58:49,590\r
+跟小徒們共同征服牛魔王,消滅火焰山\r
+\r
+326\r
+00:58:49,639 --> 00:58:53,837\r
+免除永遠的禍害\r
+\r
+327\r
+00:58:53,879 --> 00:58:57,508\r
+我們聽從師父的命令,為大家謀幸福\r
+\r
+328\r
+00:58:57,559 --> 00:58:58,878\r
+大家一起出力去\r
+\r
+329\r
+00:58:58,919 --> 00:59:01,035\r
+好\r
+\r
+330\r
+01:08:23,239 --> 01:08:25,628\r
+奶奶,不好了\r
+\r
+331\r
+01:08:25,679 --> 01:08:30,799\r
+爺爺給人家抓住了,你快點去看看吧\r
+\r
+332\r
+01:08:54,479 --> 01:08:56,709\r
+還不過來打,過來打\r
+\r
+333\r
+01:08:56,760 --> 01:08:59,718\r
+慢一點,慢一點\r
+\r
+334\r
+01:08:59,760 --> 01:09:05,790\r
+孽畜,只要你把扇子交出來,饒你不死\r
+\r
+335\r
+01:09:05,840 --> 01:09:12,757\r
+老牛,扇子在什麼地方?快拿出來啊\r
+\r
+336\r
+01:09:12,799 --> 01:09:19,352\r
+在我老…老婆那兒\r
+\r
+337\r
+01:09:25,240 --> 01:09:27,993\r
+夫人,夫人,夫人\r
+\r
+338\r
+01:09:28,039 --> 01:09:32,271\r
+你快點來救救我\r
+\r
+339\r
+01:09:32,320 --> 01:09:35,118\r
+把扇子拿出來吧\r
+\r
+340\r
+01:09:35,159 --> 01:09:39,630\r
+大王,好,好的\r
+\r
+341\r
+01:09:43,400 --> 01:09:47,234\r
+悟空,你再去一趟吧\r
+\r
diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt
new file mode 100644 (file)
index 0000000..04168a6
--- /dev/null
@@ -0,0 +1,1396 @@
+1\r
+00:00:01,080 --> 00:00:09,070\r
+Princess Iron Fan\r
+\r
+2\r
+00:02:03,109 --> 00:02:09,280\r
+Journey to the West is a wonderful children's story,\r
+\r
+3\r
+00:02:09,280 --> 00:02:15,280\r
+but the world often misunderstands it as a fantasy novel.\r
+\r
+4\r
+00:02:15,280 --> 00:02:19,240\r
+This film was made for the purpose of\r
+\r
+5\r
+00:02:19,240 --> 00:02:24,240\r
+training the hearts and minds of children.\r
+\r
+6\r
+00:02:24,240 --> 00:02:29,280\r
+The story is pure, untainted by fantasy.\r
+\r
+7\r
+00:02:29,280 --> 00:02:32,560\r
+Fiery Mountain blocking the path of Tang Seng's company\r
+\r
+8\r
+00:02:32,560 --> 00:02:41,039\r
+is a metaphor for the difficulties in life.\r
+\r
+9\r
+00:02:41,039 --> 00:02:46,439\r
+In order to overcome them, one must keep faith.\r
+Everybody must work together\r
+\r
+10\r
+00:02:46,439 --> 00:02:52,430\r
+in order to obtain the palm leaf fan and put out the flames.\r
+\r
+11\r
+00:02:52,839 --> 00:02:58,178\r
+Tripikata True Sutra\r
+\r
+12\r
+00:03:34,479 --> 00:03:37,789\r
+It's already autumn, how can it still be so warm?\r
+\r
+13\r
+00:03:37,840 --> 00:03:42,349\r
+Fool, don't talk rubbish. We should hurry and get on our way.\r
+\r
+14\r
+00:04:06,919 --> 00:04:09,349\r
+Wukong, where is this place?\r
+\r
+15\r
+00:04:09,400 --> 00:04:13,669\r
+We must pass through here to continue westwards, that much is certain.\r
+\r
+16\r
+00:04:13,719 --> 00:04:18,110\r
+Might we have taken the wrong path?\r
+\r
+17\r
+00:04:18,149 --> 00:04:21,700\r
+Why is it so hot here?\r
+\r
+18\r
+00:04:30,029 --> 00:04:31,649\r
+Master, look!\r
+\r
+19\r
+00:04:31,650 --> 00:04:33,779\r
+Isn't that a house up ahead?\r
+\r
+20\r
+00:04:33,829 --> 00:04:38,100\r
+Let's go in and rest for a while, OK?\r
+\r
+21\r
+00:04:59,389 --> 00:05:02,899\r
+This place is called Fiery Mountain.\r
+\r
+22\r
+00:05:02,949 --> 00:05:06,019\r
+The fire stretches for hundreds of miles.\r
+\r
+23\r
+00:05:06,069 --> 00:05:08,740\r
+Not single straw of grass can grow here.\r
+\r
+24\r
+00:05:08,790 --> 00:05:11,620\r
+The four seasons of the year are all warm.\r
+\r
+25\r
+00:05:11,680 --> 00:05:19,629\r
+You couldn't pass through the mountain even with a head of copper and arms of iron.\r
+\r
+26\r
+00:05:19,670 --> 00:05:23,579\r
+What kind of place is this? Master, don't worry!\r
+\r
+27\r
+00:05:23,629 --> 00:05:27,139\r
+The three of us are all strong enough to pass!\r
+\r
+28\r
+00:05:27,189 --> 00:05:30,699\r
+Master, I'll go and have a look!\r
+\r
+29\r
+00:08:06,310 --> 00:08:09,579\r
+Wukong, what was it like?\r
+\r
+30\r
+00:08:09,629 --> 00:08:11,819\r
+Bad, bad, very bad.\r
+\r
+31\r
+00:08:11,879 --> 00:08:15,910\r
+If I were any slower the fur on my tail would have been burned off.\r
+\r
+32\r
+00:08:42,720 --> 00:08:47,600\r
+Noble host, the fires here are so big.\r
+\r
+33\r
+00:08:47,600 --> 00:08:49,669\r
+How can you grow any crops?\r
+\r
+34\r
+00:08:49,710 --> 00:08:53,980\r
+A thousand miles from here lives Princess Iron Fan.\r
+\r
+35\r
+00:08:54,039 --> 00:08:56,500\r
+She has a palm leaf fan.\r
+\r
+36\r
+00:08:56,559 --> 00:08:59,070\r
+Wave the fan once and the fire goes out.\r
+\r
+37\r
+00:08:59,120 --> 00:09:01,629\r
+Twice and the wind starts blowing.\r
+\r
+38\r
+00:09:01,679 --> 00:09:03,980\r
+Three times and the rain starts coming down.\r
+\r
+39\r
+00:09:04,039 --> 00:09:07,509\r
+In the following period we plant and harvest.\r
+\r
+40\r
+00:09:07,559 --> 00:09:11,340\r
+However, asking that princess to come\r
+\r
+41\r
+00:09:11,399 --> 00:09:14,870\r
+is certainly no simple matter.\r
+\r
+42\r
+00:09:14,909 --> 00:09:16,820\r
+Where does she live?\r
+\r
+43\r
+00:09:16,879 --> 00:09:20,190\r
+She lives in Palm Leaf Cave at Emerald Cloud Mountain.\r
+\r
+44\r
+00:09:20,240 --> 00:09:23,669\r
+Does she live there alone?\r
+\r
+45\r
+00:09:23,720 --> 00:09:25,750\r
+Doesn't she have a husband?\r
+\r
+46\r
+00:09:25,799 --> 00:09:29,580\r
+Her husband is Bull Demon King.\r
+\r
+47\r
+00:09:29,639 --> 00:09:32,200\r
+What, her husband is Old Bull?\r
+\r
+48\r
+00:09:32,240 --> 00:09:36,789\r
+Fool, you know him? Come with me to borrow the fan!\r
+\r
+49\r
+00:09:36,840 --> 00:09:41,750\r
+Actually... Old Bull doesn't live there.\r
+\r
+50\r
+00:09:41,799 --> 00:09:46,350\r
+Looking for his woman when he isn't home\r
+\r
+51\r
+00:09:46,399 --> 00:09:51,519\r
+isn't very... appropriate.\r
+\r
+52\r
+00:09:51,559 --> 00:09:58,309\r
+You... you... the two of you go.\r
+\r
+53\r
+00:09:58,360 --> 00:10:04,290\r
+I... I'll stay here and serve Master.\r
+\r
+54\r
+00:10:04,440 --> 00:10:11,269\r
+Sha Wujing, go with your two fellow apprentices.\r
+\r
+55\r
+00:10:38,571 --> 00:10:44,978\r
+Palm Leaf Cave\r
+\r
+56\r
+00:10:47,200 --> 00:10:51,549\r
+Fool, I always go first.\r
+\r
+57\r
+00:10:51,600 --> 00:10:54,350\r
+This time it's your turn!\r
+\r
+58\r
+00:10:58,519 --> 00:11:04,909\r
+Junior! I always go first, this time it's your turn!\r
+\r
+59\r
+00:11:04,960 --> 00:11:06,830\r
+Senior...\r
+\r
+60\r
+00:11:06,879 --> 00:11:10,990\r
+I'm asking you to make a small effort for Master. Can't you do that?\r
+\r
+61\r
+00:11:11,039 --> 00:11:14,309\r
+Hurry up!\r
+\r
+62\r
+00:11:39,639 --> 00:11:43,039\r
+Simple monk, where did you come from?\r
+\r
+63\r
+00:11:43,039 --> 00:11:49,870\r
+The Great Sage... Tang Seng... wants your princess...\r
+\r
+64\r
+00:11:49,919 --> 00:11:52,480\r
+Nonsense!\r
+\r
+65\r
+00:12:47,549 --> 00:12:52,059\r
+Senior... why don't you go instead?\r
+\r
+66\r
+00:12:52,120 --> 00:12:56,950\r
+Fool, you go!\r
+\r
+67\r
+00:12:57,000 --> 00:13:00,700\r
+Senior, why don't you go?\r
+\r
+68\r
+00:13:04,029 --> 00:13:07,460\r
+Lazy fool!\r
+\r
+69\r
+00:13:54,279 --> 00:13:57,899\r
+Great God of Thunder! Don't kill me, let me go!\r
+\r
+70\r
+00:13:57,960 --> 00:13:59,950\r
+Go tell your princess\r
+\r
+71\r
+00:14:00,000 --> 00:14:03,279\r
+that Sun Wukong has come to borrow the fan.\r
+\r
+72\r
+00:14:03,279 --> 00:14:08,399\r
+Yes, yes! Let me loose, I'll go at once.\r
+\r
+73\r
+00:14:29,559 --> 00:14:37,059\r
+Grandma, there's a Sun Wukong outside asking to borrow the fan.\r
+\r
+74\r
+00:14:41,519 --> 00:14:44,149\r
+Quickly fetch my sword.\r
+\r
+75\r
+00:15:01,639 --> 00:15:04,149\r
+Sun Wukong, you hurt my son!\r
+\r
+76\r
+00:15:04,200 --> 00:15:08,549\r
+You dare come here to meet your death?\r
+\r
+77\r
+00:15:08,600 --> 00:15:12,039\r
+I've never met you before, how could I have harmed your son?\r
+\r
+78\r
+00:15:12,039 --> 00:15:15,789\r
+My son Red Child's life was ruined, wasn't that your doing?\r
+\r
+79\r
+00:15:15,840 --> 00:15:20,389\r
+Your son is with the Goddess of Mercy now, how can you say that I hurt him?\r
+\r
+80\r
+00:15:20,440 --> 00:15:23,750\r
+Enough rubbish! Come here and let me chop you with my sword.\r
+\r
+81\r
+00:15:23,799 --> 00:15:26,149\r
+If you can take it I'll lend you the fan.\r
+\r
+82\r
+00:15:26,200 --> 00:15:28,549\r
+Really?\r
+\r
+83\r
+00:15:56,799 --> 00:16:00,629\r
+Stop! Quickly give me the fan!\r
+\r
+84\r
+00:17:53,630 --> 00:18:00,099\r
+Great Sage, weren't you going west? Why have you come back here?\r
+\r
+85\r
+00:18:11,150 --> 00:18:17,140\r
+Princess Iron Fan blew me here with a single wave of her fan.\r
+\r
+86\r
+00:18:17,190 --> 00:18:23,859\r
+That's truly amazing, Great Sage. I have something for you.\r
+\r
+87\r
+00:18:28,509 --> 00:18:33,450\r
+This is a wind pearl. When you use it,\r
+\r
+88\r
+00:18:33,509 --> 00:18:36,140\r
+your heart will become steady as a rock.\r
+\r
+89\r
+00:18:36,190 --> 00:18:39,180\r
+Princess Iron Fan won't be able to move you.\r
+\r
+90\r
+00:18:39,230 --> 00:18:42,849\r
+Great Sage, come and have a look.\r
+\r
+91\r
+00:19:00,430 --> 00:19:02,539\r
+Thank you.\r
+\r
+92\r
+00:19:06,069 --> 00:19:12,299\r
+Senior... where...\r
+\r
+93\r
+00:19:12,349 --> 00:19:18,690\r
+where has he... been blown to?\r
+\r
+94\r
+00:19:18,750 --> 00:19:26,099\r
+Who cares about him? Let the monkey handle himself. Let's go.\r
+\r
+95\r
+00:19:35,190 --> 00:19:37,259\r
+Senior... senior...\r
+\r
+96\r
+00:19:37,309 --> 00:19:43,470\r
+You... you...\r
+\r
+97\r
+00:19:43,470 --> 00:19:50,220\r
+Where were you blown to by that old lady?\r
+\r
+98\r
+00:19:50,269 --> 00:19:57,180\r
+Fool, now it's definitely your turn to go.\r
+\r
+99\r
+00:19:57,230 --> 00:20:00,930\r
+I'm not going, a single wave of her fan\r
+\r
+100\r
+00:20:00,990 --> 00:20:03,450\r
+could blow me to some faraway land.\r
+\r
+101\r
+00:20:03,509 --> 00:20:09,710\r
+Maybe it's better if you go again.\r
+\r
+102\r
+00:20:09,710 --> 00:20:12,220\r
+I won't go.\r
+\r
+103\r
+00:20:17,789 --> 00:20:22,779\r
+Next time I won't let you off!\r
+\r
+104\r
+00:20:56,150 --> 00:21:00,140\r
+This time I won't move no matter how much you wave,\r
+\r
+105\r
+00:21:00,190 --> 00:21:05,210\r
+as sure as I call myself am a man!\r
+\r
+106\r
+00:21:33,670 --> 00:21:38,579\r
+Senior, how come this time her fan couldn't move you?\r
+\r
+107\r
+00:21:46,829 --> 00:21:50,099\r
+Let's break our way in.\r
+\r
+108\r
+00:23:59,630 --> 00:24:04,180\r
+Quickly bring out the fan for Sun Wukong!\r
+\r
+109\r
+00:24:14,869 --> 00:24:16,900\r
+Sun Wukong, where are you?\r
+\r
+110\r
+00:24:16,950 --> 00:24:19,980\r
+I'm in your stomach!\r
+\r
+111\r
+00:24:45,750 --> 00:24:48,539\r
+Sun Wukong, spare me!\r
+\r
+112\r
+00:24:48,589 --> 00:24:51,180\r
+Only if you give me the fan!\r
+\r
+113\r
+00:24:51,230 --> 00:24:56,539\r
+I promise, I'll give it to you. Please come out!\r
+\r
+114\r
+00:25:00,230 --> 00:25:02,819\r
+Hurry up and bring the fan.\r
+\r
+115\r
+00:25:07,430 --> 00:25:09,220\r
+We've brought out the fan.\r
+\r
+116\r
+00:25:09,279 --> 00:25:12,069\r
+Why haven't you come out?\r
+\r
+117\r
+00:25:12,109 --> 00:25:16,619\r
+Open your mouth and I'll come out.\r
+\r
+118\r
+00:25:25,349 --> 00:25:29,420\r
+Sun Wukong, why haven't you come out?\r
+\r
+119\r
+00:25:50,349 --> 00:25:55,579\r
+Here I am. Lend me the fan for a while, I'll return it.\r
+\r
+120\r
+00:26:32,549 --> 00:26:36,579\r
+Master has been waiting long enough, let's get going!\r
+\r
+121\r
+00:27:01,869 --> 00:27:04,900\r
+Scripture, what is scripture?\r
+\r
+122\r
+00:27:04,950 --> 00:27:10,029\r
+Scriptures are the principles that link heaven and earth.\r
+\r
+123\r
+00:27:10,029 --> 00:27:14,180\r
+They are the principles of man.\r
+\r
+124\r
+00:27:14,230 --> 00:27:18,700\r
+Only he who holds these principles\r
+\r
+125\r
+00:27:18,750 --> 00:27:25,339\r
+can rid himself of pain and live a good life,\r
+\r
+126\r
+00:27:25,390 --> 00:27:29,940\r
+live a true and honest life.\r
+\r
+127\r
+00:27:34,680 --> 00:27:36,349\r
+Conversely,\r
+\r
+128\r
+00:27:36,390 --> 00:27:40,089\r
+he who does not know these principles,\r
+\r
+129\r
+00:27:40,150 --> 00:27:46,380\r
+will live a life full of misery.\r
+\r
+130\r
+00:27:46,430 --> 00:27:52,609\r
+Even his son or grandson will not achieve happiness.\r
+\r
+131\r
+00:27:52,670 --> 00:27:55,660\r
+Why am I going to get the scripture?\r
+\r
+132\r
+00:27:55,710 --> 00:28:01,299\r
+Because men nowadays are trapped in misery.\r
+\r
+133\r
+00:28:01,349 --> 00:28:04,180\r
+In order to achieve this goal, we are going to\r
+\r
+134\r
+00:28:04,230 --> 00:28:12,500\r
+appear before the Tang emperor and discuss this very complicated matter.\r
+\r
+135\r
+00:28:15,670 --> 00:28:17,819\r
+Did you get the palm leaf fan?\r
+\r
+136\r
+00:28:17,869 --> 00:28:19,400\r
+We have it.\r
+\r
+137\r
+00:28:19,401 --> 00:28:20,779\r
+Is this it?\r
+\r
+138\r
+00:28:22,829 --> 00:28:27,980\r
+Noble hosts, now that we have the fan,\r
+\r
+139\r
+00:28:28,029 --> 00:28:32,140\r
+we will take our leave.\r
+\r
+140\r
+00:28:32,190 --> 00:28:34,039\r
+Hold on.\r
+\r
+141\r
+00:28:34,039 --> 00:28:39,789\r
+Everyone, I would like to ask Sage Seng to stay here for a few more days.\r
+\r
+142\r
+00:28:39,829 --> 00:28:41,339\r
+Do you agree?\r
+\r
+143\r
+00:28:41,390 --> 00:28:43,460\r
+Agreed!\r
+\r
+144\r
+00:28:43,509 --> 00:28:45,890\r
+Thank you for your kindness.\r
+\r
+145\r
+00:28:45,950 --> 00:28:51,779\r
+But the sooner I leave the sooner we can complete our task.\r
+\r
+146\r
+00:28:51,829 --> 00:28:56,180\r
+Very well, will the honorable apprentice first go to Fiery Mountain.\r
+\r
+147\r
+00:28:56,230 --> 00:29:02,140\r
+After extinguishing the flames, continue to follow Sage Seng.\r
+\r
+148\r
+00:29:02,190 --> 00:29:05,460\r
+All right, go ahead!\r
+\r
+149\r
+00:30:24,470 --> 00:30:30,029\r
+Princess Iron Fan is really despicable, she gave us a fake fan!\r
+\r
+150\r
+00:30:30,029 --> 00:30:32,779\r
+I'll kill her for sure!\r
+\r
+151\r
+00:30:32,829 --> 00:30:36,299\r
+No, killing her is the wrong thing to do.\r
+\r
+152\r
+00:30:36,349 --> 00:30:39,579\r
+I won't let you kill anyone.\r
+\r
+153\r
+00:30:39,630 --> 00:30:42,980\r
+Let's think of something else.\r
+\r
+154\r
+00:30:52,150 --> 00:30:56,220\r
+Senior, how could you be fooled by her?\r
+\r
+155\r
+00:30:56,269 --> 00:30:58,539\r
+After making such an effort\r
+\r
+156\r
+00:30:58,589 --> 00:31:02,099\r
+all we got was a fake fan.\r
+\r
+157\r
+00:31:02,150 --> 00:31:06,500\r
+Ridiculous, ridiculous.\r
+\r
+158\r
+00:31:08,910 --> 00:31:10,420\r
+Then you go!\r
+\r
+159\r
+00:31:10,470 --> 00:31:14,380\r
+OK, I'll go, I'll go, I'm going!\r
+\r
+160\r
+00:31:14,430 --> 00:31:16,908\r
+I'll go find Bull Demon King.\r
+\r
+161\r
+00:31:16,909 --> 00:31:19,940\r
+This is a good solution.\r
+\r
+162\r
+00:31:21,390 --> 00:31:24,439\r
+Partner, what do you think?\r
+\r
+163\r
+00:31:24,440 --> 00:31:27,380\r
+We'll see how you do.\r
+\r
+164\r
+00:33:07,190 --> 00:33:11,150\r
+What do you think, am I pretty today?\r
+\r
+165\r
+00:33:11,150 --> 00:33:13,779\r
+Beautiful, my baby.\r
+\r
+166\r
+00:33:13,829 --> 00:33:17,059\r
+Accompany me for a walk outside the cave, all right?\r
+\r
+167\r
+00:33:17,109 --> 00:33:21,539\r
+My baby, why don't you go by yourself.\r
+\r
+168\r
+00:33:21,589 --> 00:33:24,819\r
+Why of course, I'm just a plain country girl.\r
+\r
+169\r
+00:33:24,869 --> 00:33:28,019\r
+Taking me outside might cause you to lose face.\r
+\r
+170\r
+00:33:28,069 --> 00:33:32,029\r
+Baby, what are you saying?\r
+\r
+171\r
+00:33:32,029 --> 00:33:37,500\r
+You go ahead, I'll come out in a while, all right?\r
+\r
+172\r
+00:33:39,852 --> 00:33:44,557\r
+Emerald Cloud Cave\r
+\r
+173\r
+00:35:28,030 --> 00:35:35,659\r
+Goddess, you're truly an angel come down from heaven.\r
+\r
+174\r
+00:35:35,710 --> 00:35:37,900\r
+Who... who are you?\r
+\r
+175\r
+00:35:37,949 --> 00:35:41,460\r
+I've come from Palm Leaf Cave to look for Bull Demon King.\r
+\r
+176\r
+00:35:41,519 --> 00:35:43,980\r
+Let go of me!\r
+\r
+177\r
+00:35:49,550 --> 00:35:52,940\r
+Goddess, slow down!\r
+\r
+178\r
+00:36:38,768 --> 00:36:40,133\r
+Emerald Cloud Cave\r
+\r
+179\r
+00:36:44,230 --> 00:36:49,219\r
+Baby, who has bullied you?\r
+\r
+180\r
+00:36:49,269 --> 00:36:50,820\r
+You!\r
+\r
+181\r
+00:36:50,869 --> 00:36:54,340\r
+How could I bully you?\r
+\r
+182\r
+00:36:56,909 --> 00:36:59,260\r
+Why don't you go back to Palm Leaf Cave?\r
+\r
+183\r
+00:36:59,320 --> 00:37:01,699\r
+It would spare you some embarrassment.\r
+\r
+184\r
+00:37:01,750 --> 00:37:07,659\r
+They often send people to look for you, and bully me.\r
+\r
+185\r
+00:37:07,710 --> 00:37:11,059\r
+Has there been someone here to look for me?\r
+\r
+186\r
+00:37:11,110 --> 00:37:15,059\r
+There's a pig monk outside looking for you.\r
+\r
+187\r
+00:37:15,119 --> 00:37:18,510\r
+He almost scared me to death.\r
+\r
+188\r
+00:37:18,550 --> 00:37:22,739\r
+How can this be? Wait while I go out to have a look.\r
+\r
+189\r
+00:37:50,670 --> 00:37:53,780\r
+Bull, old friend!\r
+\r
+190\r
+00:37:53,829 --> 00:37:58,139\r
+There's a very beautiful young lady in here.\r
+\r
+191\r
+00:37:58,199 --> 00:38:03,889\r
+Hey, that's my woman! Why have you come to bother her?\r
+\r
+192\r
+00:38:03,930 --> 00:38:08,550\r
+Oh, I didn't know, please forgive me!\r
+\r
+193\r
+00:38:08,550 --> 00:38:11,940\r
+You didn't know, so I can't blame you. Off you go!\r
+\r
+194\r
+00:38:11,989 --> 00:38:16,099\r
+No, no. I still have something I need you to help me with.\r
+\r
+195\r
+00:38:18,469 --> 00:38:24,710\r
+We were on our way to retrieve the scriptures when we arrived at Fiery Mountain.\r
+\r
+196\r
+00:38:24,710 --> 00:38:27,300\r
+Please ask your wife\r
+\r
+197\r
+00:38:27,349 --> 00:38:30,820\r
+to lend us the palm leaf fan for a while.\r
+\r
+198\r
+00:38:30,880 --> 00:38:33,510\r
+Absolutely not! Tang Seng and Sun Wukong\r
+\r
+199\r
+00:38:33,510 --> 00:38:35,179\r
+are my son's enemies.\r
+\r
+200\r
+00:38:35,230 --> 00:38:38,739\r
+I'd love to take my revenge on them.\r
+\r
+201\r
+00:38:38,789 --> 00:38:44,969\r
+Your son is with the Goddess of Mercy now, please don't fight.\r
+\r
+202\r
+00:38:45,030 --> 00:38:48,940\r
+All right, since we are old friends, I won't fight you.\r
+\r
+203\r
+00:38:49,000 --> 00:38:51,710\r
+Now go away!\r
+\r
+204\r
+00:39:38,389 --> 00:39:44,179\r
+Baby, that pig monk is a friend of mine.\r
+\r
+205\r
+00:39:44,230 --> 00:39:46,500\r
+He wasn't sent from Palm Leaf Cave at all.\r
+\r
+206\r
+00:39:46,550 --> 00:39:47,739\r
+I don't believe you.\r
+\r
+207\r
+00:39:47,789 --> 00:39:50,940\r
+I'm not lying to you!\r
+\r
+208\r
+00:39:50,989 --> 00:39:54,019\r
+Where is that monk now?\r
+\r
+209\r
+00:39:54,110 --> 00:39:57,780\r
+I've already scared him away.\r
+\r
+210\r
+00:43:34,814 --> 00:43:40,987\r
+Palm Leaf Cave\r
+\r
+211\r
+00:43:58,630 --> 00:44:01,340\r
+The king has returned!\r
+\r
+212\r
+00:44:01,389 --> 00:44:02,369\r
+Where's grandma?\r
+\r
+213\r
+00:44:02,429 --> 00:44:04,780\r
+She's inside.\r
+\r
+214\r
+00:44:42,989 --> 00:44:48,219\r
+By what honor has the king come to visit today?\r
+\r
+215\r
+00:44:48,269 --> 00:44:52,260\r
+I heard that Sun Wukong and Tang Seng are coming here.\r
+\r
+216\r
+00:44:52,320 --> 00:44:56,909\r
+I'm afraid they want to use the palm leaf fan to pass Fiery Mountain.\r
+\r
+217\r
+00:44:56,949 --> 00:45:00,860\r
+That monkey is the one who harmed our son.\r
+\r
+218\r
+00:45:00,909 --> 00:45:08,489\r
+I'll get him sooner or later, we will have our revenge.\r
+\r
+219\r
+00:45:08,550 --> 00:45:12,699\r
+Darling, why are you crying?\r
+\r
+220\r
+00:45:12,750 --> 00:45:15,699\r
+That monkey has already been here.\r
+\r
+221\r
+00:45:15,750 --> 00:45:18,860\r
+I refused to give him the fan.\r
+\r
+222\r
+00:45:18,909 --> 00:45:22,260\r
+I don't know how, but he got inside my stomach.\r
+\r
+223\r
+00:45:22,309 --> 00:45:25,500\r
+It hurt so bad I thought I would die.\r
+\r
+224\r
+00:45:25,550 --> 00:45:30,589\r
+At last I had no choice but to give him the fan.\r
+\r
+225\r
+00:45:30,789 --> 00:45:35,260\r
+That's terrible, how could you give him the fan?\r
+\r
+226\r
+00:45:38,320 --> 00:45:40,469\r
+I gave him a false one.\r
+\r
+227\r
+00:45:40,720 --> 00:45:43,019\r
+A false one?\r
+\r
+228\r
+00:46:14,190 --> 00:46:19,860\r
+A banquet to celebrate the king's return\r
+\r
+229\r
+00:46:19,909 --> 00:46:25,619\r
+Please drink the fine wine.\r
+\r
+230\r
+00:46:25,670 --> 00:46:34,179\r
+The chicken is fragrant, the duck is beautiful, and the pig is fat.\r
+\r
+231\r
+00:46:34,239 --> 00:46:45,670\r
+I try my best to sing, I try my best to dance.\r
+\r
+232\r
+00:46:45,710 --> 00:46:54,500\r
+You must also try your best to drink.\r
+\r
+233\r
+00:47:03,590 --> 00:47:16,389\r
+My king! You dumped the old one.\r
+\r
+234\r
+00:47:16,429 --> 00:47:22,610\r
+You love another woman.\r
+\r
+235\r
+00:47:22,670 --> 00:47:34,659\r
+Countless tears were spilled for you.\r
+\r
+236\r
+00:47:46,710 --> 00:47:55,699\r
+When the light is out and the curtain is dropped,\r
+\r
+237\r
+00:47:55,750 --> 00:48:00,869\r
+you will sleep alone.\r
+\r
+238\r
+00:48:00,869 --> 00:48:05,510\r
+You too will taste loneliness.\r
+\r
+239\r
+00:48:05,510 --> 00:48:13,420\r
+Pardon me for not making you company.\r
+\r
+240\r
+00:48:18,550 --> 00:48:24,619\r
+Even if we are on the same bed,\r
+\r
+241\r
+00:48:24,670 --> 00:48:34,340\r
+we will sleep under separate sheets.\r
+\r
+242\r
+00:48:38,389 --> 00:48:42,380\r
+King, I'm drunk.\r
+\r
+243\r
+00:48:55,070 --> 00:48:58,139\r
+Darling, where did you put the real fan?\r
+\r
+244\r
+00:48:58,190 --> 00:49:05,460\r
+That monkey is very deceitful, and the pig has even greater skill.\r
+\r
+245\r
+00:49:05,510 --> 00:49:09,780\r
+If you're not careful they might trick you.\r
+\r
+246\r
+00:49:18,360 --> 00:49:21,980\r
+Our treasure is right here.\r
+\r
+247\r
+00:49:31,429 --> 00:49:39,309\r
+King, what are you thinking about? Why don't you take it?\r
+\r
+248\r
+00:49:39,309 --> 00:49:40,847\r
+My treasure.\r
+\r
+249\r
+00:49:41,514 --> 00:49:44,150\r
+Emerald Cloud Cave\r
+\r
+250\r
+00:49:44,250 --> 00:49:49,019\r
+Baby, have another cup. Drink.\r
+\r
+251\r
+00:49:53,909 --> 00:49:59,510\r
+Gold Dragon King has asked me to drink with him tonight\r
+\r
+252\r
+00:49:59,510 --> 00:50:01,420\r
+Then you should go.\r
+\r
+253\r
+00:50:01,469 --> 00:50:02,860\r
+That's right.\r
+\r
+254\r
+00:50:02,909 --> 00:50:06,610\r
+You should prepare the golden eyed beast for grandpa.\r
+\r
+255\r
+00:50:06,670 --> 00:50:08,260\r
+I will.\r
+\r
+256\r
+00:50:08,320 --> 00:50:12,590\r
+You should drink a little less tonight.\r
+\r
+257\r
+00:50:12,630 --> 00:50:15,739\r
+Otherwise I won't be able to wake you up.\r
+\r
+258\r
+00:50:15,800 --> 00:50:19,110\r
+It's terrible, grandpa's golden eyed beast has disappeared!\r
+\r
+259\r
+00:50:19,150 --> 00:50:20,900\r
+Are you all deaf and blind?\r
+\r
+260\r
+00:50:20,949 --> 00:50:24,030\r
+How could it just disappear?\r
+\r
+261\r
+00:50:24,030 --> 00:50:27,900\r
+Baby, don't mind them.\r
+\r
+262\r
+00:50:27,960 --> 00:50:31,710\r
+I'm afraid Zhu Bajie might have stolen it.\r
+\r
+263\r
+00:50:31,750 --> 00:50:35,260\r
+Maybe I should go over to Palm Leaf Cave.\r
+\r
+264\r
+00:50:35,320 --> 00:50:39,309\r
+What? You've had this planned all along.\r
+\r
+265\r
+00:50:42,280 --> 00:50:48,150\r
+You still want to go over to that shameless woman?\r
+\r
+266\r
+00:50:48,190 --> 00:50:50,699\r
+Please baby, don't cry.\r
+\r
+267\r
+00:50:50,750 --> 00:50:54,059\r
+I'll be back soon.\r
+\r
+268\r
+00:50:57,624 --> 00:51:01,194\r
+Palm Leaf Cave\r
+\r
+269\r
+00:51:02,670 --> 00:51:07,300\r
+Come over here, drink a little!\r
+\r
+270\r
+00:51:10,349 --> 00:51:12,460\r
+Now I can relax.\r
+\r
+271\r
+00:51:12,510 --> 00:51:16,699\r
+We don't have to worry about our treasure being stolen.\r
+\r
+272\r
+00:51:16,750 --> 00:51:21,300\r
+Even if they stole it, they wouldn't know to pull the silk thread.\r
+\r
+273\r
+00:51:21,360 --> 00:51:26,269\r
+Having just a pearl won't be of any use.\r
+\r
+274\r
+00:51:26,309 --> 00:51:31,780\r
+Pulling the thread will turn it into a fan, right?\r
+\r
+275\r
+00:51:35,119 --> 00:51:38,070\r
+King, you're drunk.\r
+\r
+276\r
+00:51:38,110 --> 00:51:44,019\r
+You forgot about your own treasure, and are asking me.\r
+\r
+277\r
+00:51:49,989 --> 00:51:53,690\r
+Lady, look at who I am.\r
+\r
+278\r
+00:52:00,320 --> 00:52:03,750\r
+Who are you?\r
+\r
+279\r
+00:52:03,789 --> 00:52:09,889\r
+I am Tang Seng's second apprentice, Zhu Bajie.\r
+\r
+280\r
+00:52:09,949 --> 00:52:14,780\r
+Sorry about bothering you, and thanks!\r
+\r
+281\r
+00:52:19,079 --> 00:52:21,710\r
+Bye!\r
+\r
+282\r
+00:53:06,829 --> 00:53:10,699\r
+Bull's wife is too flirtatious.\r
+\r
+283\r
+00:53:10,760 --> 00:53:14,710\r
+All her underlings are handsome.\r
+\r
+284\r
+00:53:14,750 --> 00:53:24,809\r
+Old Pig almost couldn't take it.\r
+\r
+285\r
+00:53:24,869 --> 00:53:28,860\r
+Using clever tricks and tactics,\r
+\r
+286\r
+00:53:28,909 --> 00:53:32,820\r
+I stole their treasure away.\r
+\r
+287\r
+00:53:32,880 --> 00:53:36,789\r
+This is a great accomplishment.\r
+\r
+288\r
+00:53:36,829 --> 00:53:38,300\r
+Sandy should be on his knees.\r
+\r
+289\r
+00:53:38,349 --> 00:53:40,730\r
+Monkey should learn from me.\r
+\r
+290\r
+00:53:40,789 --> 00:53:45,219\r
+Even Master will be astonished.\r
+\r
+291\r
+00:53:45,280 --> 00:53:49,190\r
+Old Pig is truly masterful.\r
+\r
+292\r
+00:53:49,230 --> 00:53:54,349\r
+Old Pig is truly masterful.\r
+\r
+293\r
+00:54:36,719 --> 00:54:40,469\r
+Fool, how are things going?\r
+\r
+294\r
+00:54:40,510 --> 00:54:42,809\r
+Not only did I get the fan,\r
+\r
+295\r
+00:54:42,880 --> 00:54:48,789\r
+Princess Iron Fan was my wife for half a day, too.\r
+\r
+296\r
+00:54:48,829 --> 00:54:51,699\r
+You got a good deal.\r
+\r
+297\r
+00:54:58,150 --> 00:55:01,579\r
+Hey, let me see the fan.\r
+\r
+298\r
+00:55:16,030 --> 00:55:20,219\r
+Why did you shrink it?\r
+\r
+299\r
+00:55:40,550 --> 00:55:45,340\r
+Old Pig, you do recognize me, right?\r
+\r
+300\r
+00:55:45,389 --> 00:55:49,170\r
+Stop joking around with me.\r
+\r
+301\r
+00:55:49,230 --> 00:55:52,139\r
+Who's joking around with you?\r
+\r
+302\r
+00:56:42,869 --> 00:56:45,380\r
+Fool, how did it go?\r
+\r
+303\r
+00:56:45,429 --> 00:56:47,099\r
+It was all for nothing.\r
+\r
+304\r
+00:56:47,150 --> 00:56:49,980\r
+Wuneng, did you borrow the fan?\r
+\r
+305\r
+00:56:50,030 --> 00:56:53,340\r
+I found Bull Demon King, but he refused.\r
+\r
+306\r
+00:56:53,400 --> 00:56:59,190\r
+Then, I turned into his look-alike.\r
+\r
+307\r
+00:56:59,230 --> 00:57:03,539\r
+I tricked Princess Iron Fan into giving me the fan.\r
+\r
+308\r
+00:57:03,590 --> 00:57:10,590\r
+But then Old Bull turned into your look-alike and tricked me into giving it back.\r
+\r
+309\r
+00:57:10,590 --> 00:57:12,739\r
+Old Bull's skills are great.\r
+\r
+310\r
+00:57:12,800 --> 00:57:16,150\r
+I got beaten up by him, too.\r
+\r
+311\r
+00:57:16,190 --> 00:57:21,380\r
+How could you get the fan and still be such a fool?\r
+\r
+312\r
+00:57:21,429 --> 00:57:25,659\r
+Not everything revolves around you!\r
+\r
+313\r
+00:57:30,750 --> 00:57:34,369\r
+Don't fight, we should quickly think of a solution.\r
+\r
+314\r
+00:57:34,429 --> 00:57:40,260\r
+In which... which direction is there no fire?\r
+\r
+315\r
+00:57:40,320 --> 00:57:47,070\r
+Of east, south, west, north, there's fire only to the west.\r
+\r
+316\r
+00:57:47,119 --> 00:57:50,739\r
+So we have no option but to go back.\r
+\r
+317\r
+00:57:50,789 --> 00:57:52,940\r
+This path is blocked, what other options do we have?\r
+\r
+318\r
+00:57:52,989 --> 00:57:55,219\r
+Bajie, don't talk like that.\r
+\r
+319\r
+00:57:55,269 --> 00:57:59,139\r
+There will always be obstacles in our path.\r
+\r
+320\r
+00:57:59,190 --> 00:58:04,539\r
+To complete our sacred task we must be strong in our faith.\r
+\r
+321\r
+00:58:04,590 --> 00:58:09,219\r
+We can't change our goal half way just because we encounter some obstacles.\r
+\r
+322\r
+00:58:09,280 --> 00:58:14,590\r
+The reason that we've been defeated is that we haven't worked together.\r
+\r
+323\r
+00:58:14,630 --> 00:58:17,139\r
+If the three of you work as one,\r
+\r
+324\r
+00:58:17,190 --> 00:58:20,500\r
+put your strength together to fight Bull Demon King,\r
+\r
+325\r
+00:58:20,550 --> 00:58:22,849\r
+then you will certainly be victorious.\r
+\r
+326\r
+00:58:22,909 --> 00:58:26,030\r
+We have heard the order of Master\r
+\r
+327\r
+00:58:26,030 --> 00:58:30,139\r
+and will fight Bull Demon King to the end.\r
+\r
+328\r
+00:58:30,190 --> 00:58:34,260\r
+to... to the end.\r
+\r
+329\r
+00:58:34,320 --> 00:58:37,710\r
+That's excellent!\r
+\r
+330\r
+00:58:37,750 --> 00:58:40,980\r
+We have all been through hardships.\r
+\r
+331\r
+00:58:41,039 --> 00:58:43,869\r
+I hope everyone will make an effort\r
+\r
+332\r
+00:58:43,869 --> 00:58:49,579\r
+together with my disciples to defeat Bull Demon King and put out the flames of Fiery Mountain.\r
+\r
+333\r
+00:58:49,630 --> 00:58:52,820\r
+Otherwise this misery will never end.\r
+\r
+334\r
+00:58:53,869 --> 00:58:57,489\r
+We have heard the order of Master, to seek happiness for all.\r
+\r
+335\r
+00:58:57,550 --> 00:58:58,860\r
+Everyone work together!\r
+\r
+336\r
+00:58:58,909 --> 00:59:00,519\r
+All right!\r
+\r
+337\r
+01:08:23,229 --> 01:08:25,609\r
+Grandma, it's terrible!\r
+\r
+338\r
+01:08:25,670 --> 01:08:30,789\r
+Grandpa has been trapped, come quickly and look!\r
+\r
+339\r
+01:08:54,470 --> 01:08:56,699\r
+The fight's not over yet, not over.\r
+\r
+340\r
+01:08:56,760 --> 01:08:58,710\r
+Careful, careful.\r
+\r
+341\r
+01:08:59,760 --> 01:09:05,789\r
+Beast, all you have to is give us the fan and we'll spare your life.\r
+\r
+342\r
+01:09:05,840 --> 01:09:12,750\r
+Old Bull, where is the fan? Hand it over!\r
+\r
+343\r
+01:09:12,789 --> 01:09:19,340\r
+My... my wife... has it.\r
+\r
+344\r
+01:09:25,239 --> 01:09:27,989\r
+Darling, darling!\r
+\r
+345\r
+01:09:28,029 --> 01:09:32,260\r
+Save me, hurry!\r
+\r
+346\r
+01:09:32,319 --> 01:09:35,109\r
+Give them the fan.\r
+\r
+347\r
+01:09:35,149 --> 01:09:39,619\r
+King! All right, all right!\r
+\r
+348\r
+01:09:43,399 --> 01:09:47,229\r
+Wukong, you go one more time!\r
+\r
+349\r
+01:12:30,850 --> 01:12:46,599\r
+The End\r
diff --git a/js2/mwEmbed/example_usage/media/princess_iron_fan-cs.srt b/js2/mwEmbed/example_usage/media/princess_iron_fan-cs.srt
new file mode 100644 (file)
index 0000000..6cc0494
--- /dev/null
@@ -0,0 +1,1397 @@
+1
+00:00:01,080 --> 00:00:09,070
+Princezna Železný Vějíř
+
+2
+00:02:03,109 --> 00:02:09,280
+Cesta na Východ je báječný dětský příběh,
+
+3
+00:02:09,280 --> 00:02:15,280
+ale svět ho často chybně označuje jako fantasy román.
+
+4
+00:02:15,280 --> 00:02:19,240
+Tento film byl vyroben za účelem
+
+5
+00:02:19,240 --> 00:02:24,240
+tréninku dětských srdcí a myslí.
+
+6
+00:02:24,240 --> 00:02:29,280
+Příběh je pravý, nezkažený fantazií.
+
+7
+00:02:29,280 --> 00:02:32,560
+Ohnivá hora, která brání v cestě skupině Tanga Senga
+
+8
+00:02:32,560 --> 00:02:41,039
+je metafora pro obtíže v životě.
+
+9
+00:02:41,039 --> 00:02:46,439
+Abychom je překonali, musíme si uchovat víru.
+Musíme spolupracovat
+
+10
+00:02:46,439 --> 00:02:52,430
+abychom získali vějíř z palmových listů a udusili plameny.
+
+11
+00:02:52,839 --> 00:02:58,178
+Tripikata True Sutra
+
+12
+00:03:34,479 --> 00:03:37,789
+Už je přece podzim. Jakto, že je pořád takové vedro?
+
+13
+00:03:37,840 --> 00:03:42,349
+Hlupáku, neplácej nesmysly. Musíme si pospíšit a postupovat dál.
+
+14
+00:04:06,919 --> 00:04:09,349
+Wukongu, kde je to místo?
+
+15
+00:04:09,400 --> 00:04:13,669
+Musíme přejít tudy a dál na západ. Zaručeně.
+
+16
+00:04:13,719 --> 00:04:18,110
+A nemohli jsme zabloudit? 
+
+17
+00:04:18,149 --> 00:04:21,700
+Proč je tu takové horko?
+
+18
+00:04:30,029 --> 00:04:31,649
+Mistře, podívejte!
+
+19
+00:04:31,650 --> 00:04:33,779
+Není to domek? Tam nahoře...
+
+20
+00:04:33,829 --> 00:04:38,100
+Pojďme si dovnitř na chvilku odpočinout. Souhlasíte?
+
+21
+00:04:59,389 --> 00:05:02,899
+Tohle místo se nazývá Ohnivá hora.
+
+22
+00:05:02,949 --> 00:05:06,019
+Oheň dosahuje stovky mil daleko.
+
+23
+00:05:06,069 --> 00:05:08,740
+Ani jediné stéblo trávy zde nemůže vyrůst.
+
+24
+00:05:08,790 --> 00:05:11,620
+Všechny čtyři roční období je tu horko.
+
+25
+00:05:11,680 --> 00:05:19,629
+Přes horu by nešlo projít ani s měděnou hlavou ani s železnýma rukama.
+
+26
+00:05:19,670 --> 00:05:23,579
+Co je tohle jenom za místo? Mistře, nebojte.
+
+27
+00:05:23,629 --> 00:05:27,139
+My tři jsme dost silní abychom dokázali projít.
+
+28
+00:05:27,189 --> 00:05:30,699
+Mistře, půjdu a podívám se na to.
+
+29
+00:08:06,310 --> 00:08:09,579
+Wukongu, jaké to bylo?
+
+30
+00:08:09,629 --> 00:08:11,819
+Špatné, špatné, moc špatné.
+
+31
+00:08:11,879 --> 00:08:15,910
+Kdybych byl jenom trochu pomalejší, měl bych kůži na ocase spálenou.
+
+32
+00:08:42,720 --> 00:08:47,600
+Urozený hostiteli, ohně jsou zde tak velké.
+
+33
+00:08:47,600 --> 00:08:49,669
+Jak zde mohou vyrůst nějaké plodiny?
+
+34
+00:08:49,710 --> 00:08:53,980
+Tisíc mil odsud žije princezna Železný Vějíř.
+
+35
+00:08:54,039 --> 00:08:56,500
+Ona má vějíř z palmových listů.
+
+36
+00:08:56,559 --> 00:08:59,070
+Zamávej s ním jednou a oheň ustane.
+
+37
+00:08:59,120 --> 00:09:01,629
+Dvakrát a začne foukat vítr.
+
+38
+00:09:01,679 --> 00:09:03,980
+Třikrát a spustí se déšť.
+
+39
+00:09:04,039 --> 00:09:07,509
+V nadcházejícím období pak pěstujeme a sklízíme.
+
+40
+00:09:07,559 --> 00:09:11,340
+Nicméně... požádat, aby princezna přišla
+
+41
+00:09:11,399 --> 00:09:14,870
+není tak úplně jednoduché.
+
+42
+00:09:14,909 --> 00:09:16,820
+Kde ona žije?
+
+43
+00:09:16,879 --> 00:09:20,190
+Žije v jeskyni Palmových Listů v hoře Smaragdových Mračen.
+
+44
+00:09:20,240 --> 00:09:23,669
+Žije tam sama?
+
+45
+00:09:23,720 --> 00:09:25,750
+Ona nemá manžela?
+
+46
+00:09:25,799 --> 00:09:29,580
+Její manžel je Král, Býčí Démon.
+
+47
+00:09:29,639 --> 00:09:32,200
+Cože? Její manžel je Starý Býk?
+
+48
+00:09:32,240 --> 00:09:36,789
+Hlupáku, ty ho znáš? Pojď si se mnou vypůjčit ten vějíř!
+
+49
+00:09:36,840 --> 00:09:41,750
+Vlastně... Starý Býk tam nežije.
+
+50
+00:09:41,799 --> 00:09:46,350
+Vyhledávat jeho ženu, když on není doma
+
+51
+00:09:46,399 --> 00:09:51,519
+není moc ... vhodné.
+
+52
+00:09:51,559 --> 00:09:58,309
+Ty... ty... Vy dva, jděte už.
+
+53
+00:09:58,360 --> 00:10:04,290
+Já... Já zůstanu a postarám se o mistra.
+
+54
+00:10:04,440 --> 00:10:11,269
+Sha Wujingu, jdi se svými dvěma učedníky.
+
+55
+00:10:38,571 --> 00:10:44,978
+jeskyně Palmových Listů
+
+56
+00:10:47,200 --> 00:10:51,549
+Hlupáku. První jdu vždy já.
+
+57
+00:10:51,600 --> 00:10:54,350
+Tentokrát jsi na řadě ty.
+
+58
+00:10:58,519 --> 00:11:04,909
+Juniore. Vždycky jdu první já, tak teď jsi na řadě ty.
+
+59
+00:11:04,960 --> 00:11:06,830
+Seniore...
+
+60
+00:11:06,879 --> 00:11:10,990
+Žádám tě, abys pro mistra udělal malou službu. Nemůžeš to udělat?
+
+61
+00:11:11,039 --> 00:11:14,309
+Dělej!
+
+62
+00:11:39,639 --> 00:11:43,039
+Prostý mnichu, odkud jsi přišel?
+
+63
+00:11:43,039 --> 00:11:49,870
+Velký Mudrc... Tang Seng... si žádá vaši princeznu...
+
+64
+00:11:49,919 --> 00:11:52,480
+Nesmysl!
+
+65
+00:12:47,549 --> 00:12:52,059
+Seniore... proč raději nejde vy?
+
+66
+00:12:52,120 --> 00:12:56,950
+Hlupáku, jdi ty!
+
+67
+00:12:57,000 --> 00:13:00,700
+Seiore, proč vy ne?
+
+68
+00:13:04,029 --> 00:13:07,460
+Líný hlupáku!
+
+69
+00:13:54,279 --> 00:13:57,899
+Velká Matko Hromů! Nezabíjejte mě, nechte mě jít!
+
+70
+00:13:57,960 --> 00:13:59,950
+Jdi a řekni tvé princezně, 
+
+71
+00:14:00,000 --> 00:14:03,279
+že Sun Wukong si přišel půjčit její vějíř.
+
+72
+00:14:03,279 --> 00:14:08,399
+Ano, ano! Nech mě zmizet. Já hned půjdu.
+
+73
+00:14:29,559 --> 00:14:37,059
+Babičko, venku je Sun Wukong a ptá se na půjčení vějíře.
+
+74
+00:14:41,519 --> 00:14:44,149
+Rychle, přines mi můj meč.
+
+75
+00:15:01,639 --> 00:15:04,149
+Sune Wukongu, ty jsi zranil mého syna!
+
+76
+00:15:04,200 --> 00:15:08,549
+Ty se odvažuješ přijít si sem pro svou smrt?
+
+77
+00:15:08,600 --> 00:15:12,039
+Nikdy jsem tě nepotkal. Jak bych mohl ublížit tvému synovi?
+
+78
+00:15:12,039 --> 00:15:15,789
+Život mého syna Červeného Dítěte byl zničen. Není to to co děláš? 
+
+79
+00:15:15,840 --> 00:15:20,389
+Tvůj syn je nyní s Bohyní Milosrdenství. Jak můžeš říci, že jsem ho zranil?
+
+80
+00:15:20,440 --> 00:15:23,750
+Dost řečí! Pojď sem ať tě můžu seknout svým mečem.
+
+81
+00:15:23,799 --> 00:15:26,149
+Pokud to podstoupíš tak ti půjčím svůj vějíř.
+
+82
+00:15:26,200 --> 00:15:28,549
+Opravdu?
+
+83
+00:15:56,799 --> 00:16:00,629
+Zastav! Rychle, dej mi vějíř.
+
+84
+00:17:53,630 --> 00:18:00,099
+Velký mudrci, nešli jste na západ? Proč jste se vrátili?
+
+85
+00:18:11,150 --> 00:18:17,140
+Princezna Železný Vějíř mě sem odfoukla jedním mávnutím svého vějíře.
+
+86
+00:18:17,190 --> 00:18:23,859
+To je skutečně úžasné, velký mudrci. Něco pro Vás mám.
+
+87
+00:18:28,509 --> 00:18:33,450
+Tohle je větrná perla. Když ji použijete
+
+88
+00:18:33,509 --> 00:18:36,140
+vaše srdce se zastaví jako kámen.
+
+89
+00:18:36,190 --> 00:18:39,180
+Princezna Železný Vějíř nebude schopná s Vámi vůbec pohnout.
+
+90
+00:18:39,230 --> 00:18:42,849
+Velký mudrci, podívejte se.
+
+91
+00:19:00,430 --> 00:19:02,539
+Děkuji.
+
+92
+00:19:06,069 --> 00:19:12,299
+Seniore... kde...
+
+93
+00:19:12,349 --> 00:19:18,690
+Kam ho to odfouklo?
+
+94
+00:19:18,750 --> 00:19:26,099
+Kdo by se o něj staral. Ať se opičák postará sám o sebe. Pojďme.
+
+95
+00:19:35,190 --> 00:19:37,259
+Seniore... seniore...
+
+96
+00:19:37,309 --> 00:19:43,470
+Vy... vy...
+
+97
+00:19:43,470 --> 00:19:50,220
+Kam vás ta stará paní odfoukla?
+
+98
+00:19:50,269 --> 00:19:57,180
+Hlupáku, teď je rozhodně řada na tobě abys šel.
+
+99
+00:19:57,230 --> 00:20:00,930
+Já nejdu. Jediné mávnutí vějíře
+
+100
+00:20:00,990 --> 00:20:03,450
+by mě mohlo odfouknout do nějaké daleké země.
+
+101
+00:20:03,509 --> 00:20:09,710
+Možná by bylo lepší, kdyby jste šel znovu.
+
+102
+00:20:09,710 --> 00:20:12,220
+Já nepůjdu.
+
+103
+00:20:17,789 --> 00:20:22,779
+Příště už tě nenechám odpálit.
+
+104
+00:20:56,150 --> 00:21:00,140
+Tentokrát se nepohnu a nezáleží na tom jak moc máchneš.
+
+105
+00:21:00,190 --> 00:21:05,210
+Buď si jistá mým slovem, slovem muže.
+
+106
+00:21:33,670 --> 00:21:38,579
+Seniore, jakto že její vějíř vás neodfouknul?
+
+107
+00:21:46,829 --> 00:21:50,099
+Dostaňme se dovnitř.
+
+108
+00:23:59,630 --> 00:24:04,180
+Rychle, dones vějíř Sunu Wukongovi.
+
+109
+00:24:14,869 --> 00:24:16,900
+Sune Wukongu, kde jsi?
+
+110
+00:24:16,950 --> 00:24:19,980
+Jsem ve tvém žaludku!
+
+111
+00:24:45,750 --> 00:24:48,539
+Sune Wukongu, ušetři mě!
+
+112
+00:24:48,589 --> 00:24:51,180
+Jenom tehdy, když mi dáš ten vějíř.
+
+113
+00:24:51,230 --> 00:24:56,539
+Slibuji. Dám ti to. Prosím, jdi ven!
+
+114
+00:25:00,230 --> 00:25:02,819
+Honem a přines vějíř.
+
+115
+00:25:07,430 --> 00:25:09,220
+Přinesli jsme vějíř.
+
+116
+00:25:09,279 --> 00:25:12,069
+Porč jsi ještě nevylezl?
+
+117
+00:25:12,109 --> 00:25:16,619
+Otevři ústa a já vylezu.
+
+118
+00:25:25,349 --> 00:25:29,420
+Sune Wukongu, proč jsi dosud nevylezl?
+
+119
+00:25:50,349 --> 00:25:55,579
+Já jsem zde. Půjč mi na chvíli ten vějíř a já ti ho vrátím.
+
+120
+00:26:32,549 --> 00:26:36,579
+Mistr už čekal dost dlouho. Pojďme už.
+
+121
+00:27:01,869 --> 00:27:04,900
+Posvátná kniha... Co je to posvátná kniha?
+
+122
+00:27:04,950 --> 00:27:10,029
+Posvátná kniha je zásadní pro spojení mezi nebem a zemí.
+
+123
+00:27:10,029 --> 00:27:14,180
+To je princip lidí.
+
+124
+00:27:14,230 --> 00:27:18,700
+Jenom ten, kdo se těch principů drží,
+
+125
+00:27:18,750 --> 00:27:25,339
+se může zbavit bolesti a žije dobrý život.
+
+126
+00:27:25,390 --> 00:27:29,940
+Žije správný a čestný život.
+
+127
+00:27:34,680 --> 00:27:36,349
+Naproti tomu...
+
+128
+00:27:36,390 --> 00:27:40,089
+ten, kdo tyto zásady nezná,
+
+129
+00:27:40,150 --> 00:27:46,380
+bude žít život plný utrpení.
+
+130
+00:27:46,430 --> 00:27:52,609
+A dokonce ani jeho syn a vnuk nedosáhnou štěstí.
+
+131
+00:27:52,670 --> 00:27:55,660
+Proč já chci dosáhnout posvátné knihy?
+
+132
+00:27:55,710 --> 00:28:01,299
+Protože lidé jsou nyní chyceni v utrpení.
+
+133
+00:28:01,349 --> 00:28:04,180
+Abychom dosáhni tohoto cíle, jdeme...
+
+134
+00:28:04,230 --> 00:28:12,500
+navštívit císaře Tangu a povíme mu o této komplikované záležitosti.
+
+135
+00:28:15,670 --> 00:28:17,819
+Dostali jste vějíř z palmových listů?
+
+136
+00:28:17,869 --> 00:28:19,400
+Máme ho.
+
+137
+00:28:19,401 --> 00:28:20,779
+To je ono?
+
+138
+00:28:22,829 --> 00:28:27,980
+Vznešený hostiteli, teď, když máme vějíř,
+
+139
+00:28:28,029 --> 00:28:32,140
+můžeme již jít.
+
+140
+00:28:32,190 --> 00:28:34,039
+Počkejte.
+
+141
+00:28:34,039 --> 00:28:39,789
+Všichni. Rád bych požádal Sage Senga, aby jste na pár dní zůstali.
+
+142
+00:28:39,829 --> 00:28:41,339
+Souhlasíte?
+
+143
+00:28:41,390 --> 00:28:43,460
+Ujednáno!
+
+144
+00:28:43,509 --> 00:28:45,890
+Děkuji Vám za Vaši laskavost.
+
+145
+00:28:45,950 --> 00:28:51,779
+Ale odejdeme dříve abychom dokončili náš úkol.
+
+146
+00:28:51,829 --> 00:28:56,180
+Dobrá tedy. Čestný učeň půjde nejprve k Ohnivé hoře. 
+
+147
+00:28:56,230 --> 00:29:02,140
+Až uhasíš plameny, následuj Sage Senga.
+
+148
+00:29:02,190 --> 00:29:05,460
+V pořádku. Pokračujte.
+
+149
+00:30:24,470 --> 00:30:30,029
+Princezna Železný Vějíř je opravdu opovrženíhodná. Dala nám falešný vějíř!
+
+150
+00:30:30,029 --> 00:30:32,779
+Já ji zabiju! To je jisté.
+
+151
+00:30:32,829 --> 00:30:36,299
+Ne, zabíjení je špatná věc.
+
+152
+00:30:36,349 --> 00:30:39,579
+Nedovolím ti nikoho zabít.
+
+153
+00:30:39,630 --> 00:30:42,980
+Vymysleme něco jiného.
+
+154
+00:30:52,150 --> 00:30:56,220
+Seniore, jakto že Vás oklamala?
+
+155
+00:30:56,269 --> 00:30:58,539
+Po vší té námaze
+
+156
+00:30:58,589 --> 00:31:02,099
+jediné co jsme získali je falešný vějíř.
+
+157
+00:31:02,150 --> 00:31:06,500
+Směšné, směšné.
+
+158
+00:31:08,910 --> 00:31:10,420
+Pak tedy jděte!
+
+159
+00:31:10,470 --> 00:31:14,380
+Ano, půjdu, jdu, odcházím!
+
+160
+00:31:14,430 --> 00:31:16,908
+Jdu najít Krále Býčího Démona.
+
+161
+00:31:16,909 --> 00:31:19,940
+To je dobré řešení.
+
+162
+00:31:21,390 --> 00:31:24,439
+Parťáku, co si o tom myslíš?
+
+163
+00:31:24,440 --> 00:31:27,380
+Uvidíme jak to půjde.
+
+164
+00:33:07,190 --> 00:33:11,150
+Co myslíš, jsem dnes půvabná?
+
+165
+00:33:11,150 --> 00:33:13,779
+Nádherná, má drahá.
+
+166
+00:33:13,829 --> 00:33:17,059
+Doprovoď mě na procházku mimo jeskyni, ano?
+
+167
+00:33:17,109 --> 00:33:21,539
+Má drahá, proč nejdeš sama?
+
+168
+00:33:21,589 --> 00:33:24,819
+To je jasné proč. Jsem obyčejná venkovská holka.
+
+169
+00:33:24,869 --> 00:33:28,019
+Když půjdu ven tak to může způsobit, že ztratíš tvář.
+
+170
+00:33:28,069 --> 00:33:32,029
+Miláčku, proč to říkáš?
+
+171
+00:33:32,029 --> 00:33:37,500
+Pokračuj a já přijdu ven za chvilku, ano?
+
+172
+00:33:39,852 --> 00:33:44,557
+Jeskyně Smaragdových Mračen
+
+173
+00:35:28,030 --> 00:35:35,659
+Bohyně, ty jsi skutečný anděl co slétl dolů z nebes.
+
+174
+00:35:35,710 --> 00:35:37,900
+Kdo... kdo jsi?
+
+175
+00:35:37,949 --> 00:35:41,460
+Přišel jsem z jeskyně Palmových Listů abych našel krále Býčího Démona.
+
+176
+00:35:41,519 --> 00:35:43,980
+Jdi ode mě!
+
+177
+00:35:49,550 --> 00:35:52,940
+Bohyně, zpomal!
+
+178
+00:36:38,768 --> 00:36:40,133
+Jeskyně Smaragdových Mračen
+
+179
+00:36:44,230 --> 00:36:49,219
+Miláčku, kdo tě vystrašil?
+
+180
+00:36:49,269 --> 00:36:50,820
+Ty!
+
+181
+00:36:50,869 --> 00:36:54,340
+Jak bych tě mohl vystrašit?
+
+182
+00:36:56,909 --> 00:36:59,260
+Proč nejdeš zpátky do jeskyně Palmových Listů?
+
+183
+00:36:59,320 --> 00:37:01,699
+To by ti ušetřilo rozpaky.
+
+184
+00:37:01,750 --> 00:37:07,659
+Oni často posílají lidi aby tě našli a vystrašili mě.
+
+185
+00:37:07,710 --> 00:37:11,059
+Tady byl někdo kdo mě hledal?
+
+186
+00:37:11,110 --> 00:37:15,059
+Venku je prasečí mnich, který tě hledá.
+
+187
+00:37:15,119 --> 00:37:18,510
+On mě k smrti vyděsil.
+
+188
+00:37:18,550 --> 00:37:22,739
+Jak je tohle možné? Počkej chvíli. Půjdu se podívat ven.
+
+189
+00:37:50,670 --> 00:37:53,780
+Býku, starý příteli.
+
+190
+00:37:53,829 --> 00:37:58,139
+Tady vevnitř je nějaká moc krásná mladá dáma.
+
+191
+00:37:58,199 --> 00:38:03,889
+Hej, to je moje paní. Neopovažuj se ji obtěžovat.
+
+192
+00:38:03,930 --> 00:38:08,550
+Oh, to jsem nevěděl, prosím promiň mi!
+
+193
+00:38:08,550 --> 00:38:11,940
+Ty's to nevěděl, tak tě nemůžu obviňovat. A teď už jdi.
+
+194
+00:38:11,989 --> 00:38:16,099
+Ne, ne. Stále mám něco s čím potřebuji tvou pomoc.
+
+195
+00:38:18,469 --> 00:38:24,710
+Byli jsme na cestě získat posvátnou knihu když v tom jsme dorazili k Ohnivé hoře.
+
+196
+00:38:24,710 --> 00:38:27,300
+Prosím, požádej svou choť,
+
+197
+00:38:27,349 --> 00:38:30,820
+aby nám na chvíli půjčila vějíř z palmových listů.
+
+198
+00:38:30,880 --> 00:38:33,510
+V žádném případě! Tang Seng a Sun Wukong
+
+199
+00:38:33,510 --> 00:38:35,179
+jsou nepřátelé mého syna.
+
+200
+00:38:35,230 --> 00:38:38,739
+Moc rád bych na nich vykonal svou pomstu.
+
+201
+00:38:38,789 --> 00:38:44,969
+Tvůj syn je nyní s Bohyní Milosrdenství. Prosím, nebojuj.
+
+202
+00:38:45,030 --> 00:38:48,940
+Dobrá. Jsme staří přátelé tak s tebou nebudu bojovat.
+
+203
+00:38:49,000 --> 00:38:51,710
+Nyní jdi pryč!
+
+204
+00:39:38,389 --> 00:39:44,179
+Miláčku, ten prasečí mnich je můj přítel.
+
+205
+00:39:44,230 --> 00:39:46,500
+On vůbec nebyl poslán z jeskyně Palmových Listů.
+
+206
+00:39:46,550 --> 00:39:47,739
+Nevěřím ti.
+
+207
+00:39:47,789 --> 00:39:50,940
+Já ti nelžu!
+
+208
+00:39:50,989 --> 00:39:54,019
+Kde je ten mnich teď?
+
+209
+00:39:54,110 --> 00:39:57,780
+Už jsem ho zastrašil.
+
+210
+00:43:34,814 --> 00:43:40,987
+Jeskyně Palmových Listů
+
+211
+00:43:58,630 --> 00:44:01,340
+Král se vrátil.
+
+212
+00:44:01,389 --> 00:44:02,369
+Kde je babička?
+
+213
+00:44:02,429 --> 00:44:04,780
+Je uvnitř.
+
+214
+00:44:42,989 --> 00:44:48,219
+Jaká čest, že nás dnes navštívil král.
+
+215
+00:44:48,269 --> 00:44:52,260
+Slyšel jsem, že sem jsou Sun Wukong a Tang Seng.
+
+216
+00:44:52,320 --> 00:44:56,909
+Obávám se, že chtějí použít vějíř z palmových listů a přejít Ohnivou horu.
+
+217
+00:44:56,949 --> 00:45:00,860
+Ten opičák je jeden z těch co zranil našeho syna.
+
+218
+00:45:00,909 --> 00:45:08,489
+Dostanu ho dříve či později. Dosáhnu naší msty.
+
+219
+00:45:08,550 --> 00:45:12,699
+Miláčku, proč pláčeš?
+
+220
+00:45:12,750 --> 00:45:15,699
+Ten opičák už tady byl.
+
+221
+00:45:15,750 --> 00:45:18,860
+Odmítla jsem mu vějíř dát.
+
+222
+00:45:18,909 --> 00:45:22,260
+Nevím jak, ale dostal se mi do žaludku.
+
+223
+00:45:22,309 --> 00:45:25,500
+Bolelo to tak strašně, že jsem myslela že umřu.
+
+224
+00:45:25,550 --> 00:45:30,589
+Nakonec jsem neměla na výběr a dala jsem mu vějíř.
+
+225
+00:45:30,789 --> 00:45:35,260
+To je strašné. Jak's mu mohla dát vějíř?
+
+226
+00:45:38,320 --> 00:45:40,469
+Dala jsem mu falešný.
+
+227
+00:45:40,720 --> 00:45:43,019
+Falešný?
+
+228
+00:46:14,190 --> 00:46:19,860
+Večírek na oslavu návratu krále
+
+229
+00:46:19,909 --> 00:46:25,619
+Prosím, napijte se dobrého vína. 
+
+230
+00:46:25,670 --> 00:46:34,179
+Kuřecí je voňavé, kachna je skvostná a vepřové je tučné. 
+
+231
+00:46:34,239 --> 00:46:45,670
+Zkusím si zazpívat. Zkusím si dobře zatančit.
+
+232
+00:46:45,710 --> 00:46:54,500
+Musíš také ochutnat náš nejlepší nápoj.
+
+233
+00:47:03,590 --> 00:47:16,389
+Můj králi. Ty's pustil k vodě tu starou.
+
+234
+00:47:16,429 --> 00:47:22,610
+Ty miluješ jinou ženu.
+
+235
+00:47:22,670 --> 00:47:34,659
+Nespočet slz jsem pro tebe naplakala.
+
+236
+00:47:46,710 --> 00:47:55,699
+Když světlo zhasne a spustí se závěs,
+
+237
+00:47:55,750 --> 00:48:00,869
+budeš spát sám.
+
+238
+00:48:00,869 --> 00:48:05,510
+Ty také okusíš samotu.
+
+239
+00:48:05,510 --> 00:48:13,420
+Omluv mě, že ti nedělám společnost.
+
+240
+00:48:18,550 --> 00:48:24,619
+Dokonce i když jsme ve stejné posteli,
+
+241
+00:48:24,670 --> 00:48:34,340
+budeme spát pod oddělenými přikrývkami.
+
+242
+00:48:38,389 --> 00:48:42,380
+Králi. Jsem opilá.
+
+243
+00:48:55,070 --> 00:48:58,139
+Miláčku, kam jsi dala skutečný vějíř?
+
+244
+00:48:58,190 --> 00:49:05,460
+Ten opičák je velmi podvodný a prase je dokonce mnohem nadanější.
+
+245
+00:49:05,510 --> 00:49:09,780
+Když si nebudeš dávat pozor tak tě mohou obelstít.
+
+246
+00:49:18,360 --> 00:49:21,980
+Náš poklad je přímo tady.
+
+247
+00:49:31,429 --> 00:49:39,309
+Králi, na co myslíš? Proč si jej nevezmeš?
+
+248
+00:49:39,309 --> 00:49:40,847
+Můj poklade.
+
+249
+00:49:41,514 --> 00:49:44,150
+Jeskyně Smaragdových Mračen
+
+250
+00:49:44,250 --> 00:49:49,019
+Miláčku, dej si další pohár. Pij.
+
+251
+00:49:53,909 --> 00:49:59,510
+Zlatý drak mě požádal abych s ním dnes večer pil.
+
+252
+00:49:59,510 --> 00:50:01,420
+Potom bys měl jít.
+
+253
+00:50:01,469 --> 00:50:02,860
+Dobrá.
+
+254
+00:50:02,909 --> 00:50:06,610
+Měl bys pro dědečka připravit zlatooké zvíře.
+
+255
+00:50:06,670 --> 00:50:08,260
+Připravím.
+
+256
+00:50:08,320 --> 00:50:12,590
+Měl bys dnes večer pít trochu méně.
+
+257
+00:50:12,630 --> 00:50:15,739
+Jinak tě nebudu moci probudit.
+
+258
+00:50:15,800 --> 00:50:19,110
+To je strašné. Dědečkova zlatooká nestvůra zmizela!
+
+259
+00:50:19,150 --> 00:50:20,900
+Jste všichni hluší a slepí?
+
+260
+00:50:20,949 --> 00:50:24,030
+Jak mohla zmizet?
+
+261
+00:50:24,030 --> 00:50:27,900
+Miláčku, nestrachuj se o ně.
+
+262
+00:50:27,960 --> 00:50:31,710
+Bojím se, že Zhu Bajie ho mohl ukrást.
+
+263
+00:50:31,750 --> 00:50:35,260
+Možná bych měl prohledat jeskyni Palmových Listů.
+
+264
+00:50:35,320 --> 00:50:39,309
+Cože? Ty's to plánoval celou dobu.
+
+265
+00:50:42,280 --> 00:50:48,150
+Stále to chceš prohledat u té nestoudné ženy?
+
+266
+00:50:48,190 --> 00:50:50,699
+Prosím miláčku, neplakej.
+
+267
+00:50:50,750 --> 00:50:54,059
+Vrátím se brzy.
+
+268
+00:50:57,624 --> 00:51:01,194
+Jeskyně Palmových Listů
+
+269
+00:51:02,670 --> 00:51:07,300
+Pojď sem, napij se trochu!
+
+270
+00:51:10,349 --> 00:51:12,460
+Teď si můžu odpočinout.
+
+271
+00:51:12,510 --> 00:51:16,699
+Nemusíme se obávat, že jsme byli oloupeni o náš poklad.
+
+272
+00:51:16,750 --> 00:51:21,300
+Dokonce i když ho ukradli, tak nebudou vědět, že mají zatáhnout za hedvábnou nit.
+
+273
+00:51:21,360 --> 00:51:26,269
+Mají perlu, ale nebudou ji moci použít.
+
+274
+00:51:26,309 --> 00:51:31,780
+Zatáhnutí za nit ji promění na vějíř, že?
+
+275
+00:51:35,119 --> 00:51:38,070
+Králi, jsi opilý.
+
+276
+00:51:38,110 --> 00:51:44,019
+Zapomněl jsi na svůj vlastní poklad a ptáš se mě...
+
+277
+00:51:49,989 --> 00:51:53,690
+Madam, podívej se kdo já jsem.
+
+278
+00:52:00,320 --> 00:52:03,750
+Kdo jsi?
+
+279
+00:52:03,789 --> 00:52:09,889
+Já jsem Zhu Bajie, druhý pomocník Tanga Senga.
+
+280
+00:52:09,949 --> 00:52:14,780
+Omlouvám se, že jsem Vás rušil a díky!
+
+281
+00:52:19,079 --> 00:52:21,710
+Na shledanou!
+
+282
+00:53:06,829 --> 00:53:10,699
+Býkova žena je příliš koketní.
+
+283
+00:53:10,760 --> 00:53:14,710
+Všichni její podřízení jsou krásní.
+
+284
+00:53:14,750 --> 00:53:24,809
+Starý Čuník to skoro nedokázal.
+
+285
+00:53:24,869 --> 00:53:28,860
+Použil jsem chytré triky a taktiky.
+
+286
+00:53:28,909 --> 00:53:32,820
+Uloupil jsem jejich poklad.
+
+287
+00:53:32,880 --> 00:53:36,789
+To je ohromný výkon.
+
+288
+00:53:36,829 --> 00:53:38,300
+Písečný by měl klečet.
+
+289
+00:53:38,349 --> 00:53:40,730
+Opice by se měla učit ode mě.
+
+290
+00:53:40,789 --> 00:53:45,219
+Dokonce i Mistr bude v úžasu.
+
+291
+00:53:45,280 --> 00:53:49,190
+Starý Čuník je skutečně mistrovský.
+
+292
+00:53:49,230 --> 00:53:54,349
+Starý Čuník je skutečně mistrovský.
+
+293
+00:54:36,719 --> 00:54:40,469
+Hlupáku, jak to jde?
+
+294
+00:54:40,510 --> 00:54:42,809
+Nejen že jsem získal vějíř,
+
+295
+00:54:42,880 --> 00:54:48,789
+ale princezna Železný Vějíř byla půl dne mou ženou.
+
+296
+00:54:48,829 --> 00:54:51,699
+Udělal jsi to dobře.
+
+297
+00:54:58,150 --> 00:55:01,579
+Hej, ukaž mi ten vějíř.
+
+298
+00:55:16,030 --> 00:55:20,219
+Proč jsi ho smrštil?
+
+299
+00:55:40,550 --> 00:55:45,340
+Starý Čuníku, ty mě nepoznáváš, že?
+
+300
+00:55:45,389 --> 00:55:49,170
+Nedělej si ze mě legraci.
+
+301
+00:55:49,230 --> 00:55:52,139
+A kdo si z tebe dělá legraci?
+
+302
+00:56:42,869 --> 00:56:45,380
+Hlupáku, jak se to stalo?
+
+303
+00:56:45,429 --> 00:56:47,099
+Všechno bylo k ničemu.
+
+304
+00:56:47,150 --> 00:56:49,980
+Wunengu, vypůjčil jsi ten vějíř?
+
+305
+00:56:50,030 --> 00:56:53,340
+Našel jsem krále Býčího démona, ale on odmítl.
+
+306
+00:56:53,400 --> 00:56:59,190
+Potom jsem na sebe vzal jeho podobu.
+
+307
+00:56:59,230 --> 00:57:03,539
+Oklamal jsem princeznu Železný Vějíř aby mi dala vějíř.
+
+308
+00:57:03,590 --> 00:57:10,590
+Ale potom si Starý Býk vzal tvou podobu a vylákal ho na mě zpátky.
+
+309
+00:57:10,590 --> 00:57:12,739
+Schopnosti Starého Býka jsou vynikající.
+
+310
+00:57:12,800 --> 00:57:16,150
+Potom mě ještě zbil.
+
+311
+00:57:16,190 --> 00:57:21,380
+Jak jsi mohl získat vějíř a přitom zůstat tak hloupý?
+
+312
+00:57:21,429 --> 00:57:25,659
+Všechno se neotáčí kolem tebe!
+
+313
+00:57:30,750 --> 00:57:34,369
+Nebojuj. Musíme rychle vymyslet nějaké řešení.
+
+314
+00:57:34,429 --> 00:57:40,260
+Ve kterém směru není oheň?
+
+315
+00:57:40,320 --> 00:57:47,070
+Východ, jih, západ, sever. Oheň není jenom na západě.
+
+316
+00:57:47,119 --> 00:57:50,739
+Tak to nemáme jinou možnost než se vrátit.
+
+317
+00:57:50,789 --> 00:57:52,940
+Tato stezka je zablokovaná. Jaké máme jiné možnosti?
+
+318
+00:57:52,989 --> 00:57:55,219
+Bajie, nemluv tak.
+
+319
+00:57:55,269 --> 00:57:59,139
+Na naší cestě budou vždy překážky.
+
+320
+00:57:59,190 --> 00:58:04,539
+Abychom dokončili náš posvátný úkol, musíme být silní v naší víře.
+
+321
+00:58:04,590 --> 00:58:09,219
+Nemůžeme změnit náš plán jenom kvůli tomu, že jsme narazili na pár překážek.
+
+322
+00:58:09,280 --> 00:58:14,590
+Důvod proč jsme byli poraženi je ten, že jsme nespolupracovali.
+
+323
+00:58:14,630 --> 00:58:17,139
+Pokud tři z nás budou jako jeden,
+
+324
+00:58:17,190 --> 00:58:20,500
+dáme síly dohromady a zdoláme krále Býčího Démona.
+
+325
+00:58:20,550 --> 00:58:22,849
+A vítězství bude naše.
+
+326
+00:58:22,909 --> 00:58:26,030
+Slyšeli jsme Mistrův rozkaz 
+
+327
+00:58:26,030 --> 00:58:30,139
+a budeme s králem Býčím Démonem bojovat až do konce.
+
+328
+00:58:30,190 --> 00:58:34,260
+až... až do konce.
+
+329
+00:58:34,320 --> 00:58:37,710
+To je skvělé!
+
+330
+00:58:37,750 --> 00:58:40,980
+Všichni jsme dokázali překonat nesnáze.
+
+331
+00:58:41,039 --> 00:58:43,869
+Doufám, že každý vynaloží veškeré úsilí
+
+332
+00:58:43,869 --> 00:58:49,579
+společně s mými učedníky k porážce krále Býčího Démona a uhasíme plameny Ohnivé hory.
+
+333
+00:58:49,630 --> 00:58:52,820
+Jinak toto neštěstí nikdy neskončí.
+
+334
+00:58:53,869 --> 00:58:57,489
+Slyšeli jsme Mistrovo nařízení na dosažení štěstí pro všechny.
+
+335
+00:58:57,550 --> 00:58:58,860
+Společně to dokážeme!
+
+336
+00:58:58,909 --> 00:59:00,519
+Hurá!
+
+337
+01:08:23,229 --> 01:08:25,609
+Babičko, to je strašné!
+
+338
+01:08:25,670 --> 01:08:30,789
+Dědeček je chycen. Pojď se rychle podívat.
+
+339
+01:08:54,470 --> 01:08:56,699
+Ještě není po boji. Ještě ne.
+
+340
+01:08:56,760 --> 01:08:58,710
+Pozor. Opatrně.
+
+341
+01:08:59,760 --> 01:09:05,789
+Nestvůro, jediné co musíš udělat je dát nám vějíř a ušetříme tvůj život.
+
+342
+01:09:05,840 --> 01:09:12,750
+Starý Býku, kde je vějíř? Odevzdej ho!
+
+343
+01:09:12,789 --> 01:09:19,340
+Moje ... moje choť... jej má.
+
+344
+01:09:25,239 --> 01:09:27,989
+Drahoušku, drahoušku!
+
+345
+01:09:28,029 --> 01:09:32,260
+Zachraň mě, rychle!
+
+346
+01:09:32,319 --> 01:09:35,109
+Dej jim vějíř.
+
+347
+01:09:35,149 --> 01:09:39,619
+Králi! Ano, ano.
+
+348
+01:09:43,399 --> 01:09:47,229
+Wukongu, jdi na to ještě jednou!
+
+349
+01:12:30,850 --> 01:12:46,599
+Konec
+
diff --git a/js2/mwEmbed/example_usage/media/sample_eclipse.jpg b/js2/mwEmbed/example_usage/media/sample_eclipse.jpg
new file mode 100644 (file)
index 0000000..1f237a9
Binary files /dev/null and b/js2/mwEmbed/example_usage/media/sample_eclipse.jpg differ
diff --git a/js2/mwEmbed/example_usage/media/sample_fish.jpg b/js2/mwEmbed/example_usage/media/sample_fish.jpg
new file mode 100644 (file)
index 0000000..8ee8910
Binary files /dev/null and b/js2/mwEmbed/example_usage/media/sample_fish.jpg differ
diff --git a/js2/mwEmbed/example_usage/media/sample_fish_text_en.srt b/js2/mwEmbed/example_usage/media/sample_fish_text_en.srt
new file mode 100644 (file)
index 0000000..e2a09e2
--- /dev/null
@@ -0,0 +1,28 @@
+0
+00:00:01,120 --> 00:00:04,520
+blue fish, yellow fish
+
+1
+00:00:05,000 --> 00:00:06,000
+just yellow fish now
+
+2
+00:00:06,100 --> 00:00:8,500
+look a crab! 
+
+3
+00:00:8,500 --> 00:00:11,000
+Fish in some under-water plant
+
+4
+00:00:11,000 --> 00:00:14,480
+another yellow fish!
+
+5
+00:00:14,000 --> 00:00:16,000
+another crab!
+
+6
+00:00:20,680 --> 00:00:32,160
+oky I think you get the idea now
+multiple lines are fine too. 
\ No newline at end of file
diff --git a/js2/mwEmbed/example_usage/media/sample_fish_text_es.srt b/js2/mwEmbed/example_usage/media/sample_fish_text_es.srt
new file mode 100644 (file)
index 0000000..3b68ad1
--- /dev/null
@@ -0,0 +1,28 @@
+0
+00:00:01,120 --> 00:00:04,520
+pescado azul, amarillo de pescado
+
+1
+00:00:05,000 --> 00:00:06,000
+sólo ahora los peces de color amarillo
+
+2
+00:00:06,100 --> 00:00:8,500
+buscar un cangrejo!
+
+3
+00:00:8,500 --> 00:00:11,000
+En algunos peces bajo el agua-planta
+
+4
+00:00:11,000 --> 00:00:14,480
+otro amarillo de pescado!
+
+5
+00:00:14,000 --> 00:00:16,000
+otro cangrejo!
+
+6
+00:00:20,680 --> 00:00:32,160
+oky Creo que tienes la idea
+múltiples líneas
\ No newline at end of file
diff --git a/js2/mwEmbed/example_usage/media/sample_jellyfish.jpg b/js2/mwEmbed/example_usage/media/sample_jellyfish.jpg
new file mode 100644 (file)
index 0000000..65dfab4
Binary files /dev/null and b/js2/mwEmbed/example_usage/media/sample_jellyfish.jpg differ
diff --git a/js2/mwEmbed/example_usage/media/sample_smil.xml b/js2/mwEmbed/example_usage/media/sample_smil.xml
new file mode 100644 (file)
index 0000000..02f9225
--- /dev/null
@@ -0,0 +1,44 @@
+<smil xmlns="http://www.w3.org/2001/SMIL20/Language">
+  <head>
+    <meta name="title" content="Simple Crossfading Example"/>
+    
+    <transition id="fromGreen"
+       type="fade" 
+       subtype="fadeFromColor" 
+       fadeColor="#87CF87" 
+       dur="4s"/>
+       
+    <transition id="toGreen"
+       type="fade"
+       subtype="fadeToColor"
+       fadeColor="#87CF87" 
+       dur="4s"/>
+       
+    <transition id="xFade" 
+       type="fade" 
+       subtype="crossfade" 
+       dur="4s"/>
+       
+  </head>
+  <body>
+    <seq>
+
+       <video src="media/sample_fish.ogg" 
+               region="video_region" 
+               transIn="fromGreen"     
+               transOut="xFade"        
+               type="video/ogg"        
+               fill="transition"
+               dur="7s"
+               poster="media/sample_fish.jpg"/>        
+       
+    <video src="media/sample_jellyfish.ogg" 
+               region="video_region"                           
+               fill="transition" 
+               dur="10s"
+               type="video/ogg" 
+               poster="media/sample_jellyfish.jpg"/>     
+    </seq>
+  </body>
+</smil>
+
diff --git a/js2/mwEmbed/example_usage/media/simple_smil_example_script_loader.html b/js2/mwEmbed/example_usage/media/simple_smil_example_script_loader.html
new file mode 100644 (file)
index 0000000..0b8f83a
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+       <title>Simple SMIL example via Script Loader</title>
+       <script type="text/javascript" src="../jsScriptLoader.php?class=mv_embed"></script>
+</head>
+<body>
+<h3> Simple SMIL example via Script Loader</h3>
+
+<span id="default_attr">
+</span> <br />
+<br />
+  <table border="1" cellpadding="6" width="600">
+                   <tr>
+             <td valign="top"><playlist id="smil_pl" src="sample_smil.xml"></td>
+
+             <td valign="top"><b>Sample Embed 8</b><br />
+              <br><b>Crossfading Videos</b><br/>
+                       The first video fades up from green when it starts to play, 
+                       and the second video fades down to green when it ends. 
+                       When the first video stops and the second video starts, 
+                       though, the two videos crossfade into each other<br><iframe width="500" height="200" src="media/sample_smil.xml">sample smil here</iframe><br />
+             &lt;-- code used: <br />
+            <pre> &lt;playlist id=&quot;smil_pl&quot; src=&quot;media/sample_smil.smil.xml&quot;&gt;</pre>
+
+             </td>
+           </tr>
+
+             </table>
+       <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />&nbsp;
+  </body>
+</html>
+
diff --git a/js2/mwEmbed/jquery/jquery-1.3.2.js b/js2/mwEmbed/jquery/jquery-1.3.2.js
new file mode 100644 (file)
index 0000000..d2548a5
--- /dev/null
@@ -0,0 +1,3657 @@
+/*!
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){
+var
+       // Will speed up references to window, and allows munging its name.
+       window = this,
+       // Will speed up references to undefined, and allows munging its name.
+       undefined,
+       // Map over jQuery in case of overwrite
+       _jQuery = window.jQuery,
+       // Map over the $ in case of overwrite
+       _$ = window.$,
+       jQuery = window.jQuery = window.$ = function( selector, context ) {
+               // The jQuery object is actually just the init constructor 'enhanced'
+               return new jQuery.fn.init( selector, context );
+       },
+       // A simple way to check for HTML strings or ID strings
+       // (both of which we optimize for)
+       quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
+       // Is it a simple selector
+       isSimple = /^.[^:#\[\.,]*$/;
+jQuery.fn = jQuery.prototype = {
+       init: function( selector, context ) {
+               // Make sure that a selection was provided
+               selector = selector || document;
+               // Handle $(DOMElement)
+               if ( selector.nodeType ) {
+                       this[0] = selector;
+                       this.length = 1;
+                       this.context = selector;
+                       return this;
+               }
+               // Handle HTML strings
+               if ( typeof selector === "string" ) {
+                       // Are we dealing with HTML string or an ID?
+                       var 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] )
+                                       selector = jQuery.clean( [ match[1] ], context );
+                               // HANDLE: $("#id")
+                               else {
+                                       var elem = document.getElementById( match[3] );
+                                       // Handle the case where IE and Opera return items
+                                       // by name instead of ID
+                                       if ( elem && elem.id != match[3] )
+                                               return jQuery().find( selector );
+                                       // Otherwise, we inject the element directly into the jQuery object
+                                       var ret = jQuery( elem || [] );
+                                       ret.context = document;
+                                       ret.selector = selector;
+                                       return ret;
+                               }
+                       // HANDLE: $(expr, [context])
+                       // (which is just equivalent to: $(content).find(expr)
+                       } else
+                               return jQuery( context ).find( selector );
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( jQuery.isFunction( selector ) )
+                       return jQuery( document ).ready( selector );
+               // Make sure that old selector state is passed along
+               if ( selector.selector && selector.context ) {
+                       this.selector = selector.selector;
+                       this.context = selector.context;
+               }
+               return this.setArray(jQuery.isArray( selector ) ?
+                       selector :
+                       jQuery.makeArray(selector));
+       },
+       // Start with an empty selector
+       selector: "",
+       // The current version of jQuery being used
+       jquery: "1.3.2",
+       // The number of elements contained in the matched element set
+       size: function() {
+               return this.length;
+       },
+       // 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 === undefined ?
+                       // Return a 'clean' array
+                       Array.prototype.slice.call( this ) :
+                       // Return just the object
+                       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 = jQuery( 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;
+       },
+       // Force the current matched set of elements to become
+       // the specified array of elements (destroying the stack in the process)
+       // You should use pushStack() in order to do this, but maintain the stack
+       setArray: function( elems ) {
+               // Resetting the length to 0, then using the native Array push
+               // is a super-fast way to populate an object with array-like properties
+               this.length = 0;
+               Array.prototype.push.apply( this, elems );
+               return this;
+       },
+       // 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 );
+       },
+       // Determine the position of an element within
+       // the matched set of elements
+       index: function( elem ) {
+               // Locate the position of the desired element
+               return jQuery.inArray(
+                       // If it receives a jQuery object, the first element is used
+                       elem && elem.jquery ? elem[0] : elem
+               , this );
+       },
+       attr: function( name, value, type ) {
+               var options = name;
+               // Look for the case where we're accessing a style value
+               if ( typeof name === "string" )
+                       if ( value === undefined )
+                               return this[0] && jQuery[ type || "attr" ]( this[0], name );
+                       else {
+                               options = {};
+                               options[ name ] = value;
+                       }
+               // Check to see if we're setting style values
+               return this.each(function(i){
+                       // Set all the styles
+                       for ( name in options )
+                               jQuery.attr(
+                                       type ?
+                                               this.style :
+                                               this,
+                                       name, jQuery.prop( this, options[ name ], type, i, name )
+                               );
+               });
+       },
+       css: function( key, value ) {
+               // ignore negative width and height values
+               if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
+                       value = undefined;
+               return this.attr( key, value, "curCSS" );
+       },
+       text: function( text ) {
+               if ( typeof text !== "object" && text != null )
+                       return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+               var ret = "";
+               jQuery.each( text || this, function(){
+                       jQuery.each( this.childNodes, function(){
+                               if ( this.nodeType != 8 )
+                                       ret += this.nodeType != 1 ?
+                                               this.nodeValue :
+                                               jQuery.fn.text( [ this ] );
+                       });
+               });
+               return ret;
+       },
+       wrapAll: function( html ) {
+               if ( this[0] ) {
+                       // The elements to wrap the target around
+                       var wrap = jQuery( html, this[0].ownerDocument ).clone();
+                       if ( this[0].parentNode )
+                               wrap.insertBefore( this[0] );
+                       wrap.map(function(){
+                               var elem = this;
+                               while ( elem.firstChild )
+                                       elem = elem.firstChild;
+                               return elem;
+                       }).append(this);
+               }
+               return this;
+       },
+       wrapInner: function( html ) {
+               return this.each(function(){
+                       jQuery( this ).contents().wrapAll( html );
+               });
+       },
+       wrap: function( html ) {
+               return this.each(function(){
+                       jQuery( this ).wrapAll( html );
+               });
+       },
+       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() {
+               return this.domManip(arguments, false, function(elem){
+                       this.parentNode.insertBefore( elem, this );
+               });
+       },
+       after: function() {
+               return this.domManip(arguments, false, function(elem){
+                       this.parentNode.insertBefore( elem, this.nextSibling );
+               });
+       },
+       end: function() {
+               return this.prevObject || jQuery( [] );
+       },
+       // For internal use only.
+       // Behaves like an Array's method, not like a jQuery method.
+       push: [].push,
+       sort: [].sort,
+       splice: [].splice,
+       find: function( selector ) {
+               if ( this.length === 1 ) {
+                       var ret = this.pushStack( [], "find", selector );
+                       ret.length = 0;
+                       jQuery.find( selector, this[0], ret );
+                       return ret;
+               } else {
+                       return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
+                               return jQuery.find( selector, elem );
+                       })), "find", selector );
+               }
+       },
+       clone: function( events ) {
+               // Do the clone
+               var ret = this.map(function(){
+                       if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
+                               // IE copies events bound via attachEvent when
+                               // using cloneNode. Calling detachEvent on the
+                               // clone will also remove the events from the orignal
+                               // In order to get around this, we use innerHTML.
+                               // Unfortunately, this means some modifications to
+                               // attributes in IE that are actually only stored
+                               // as properties will not be copied (such as the
+                               // the name attribute on an input).
+                               var html = this.outerHTML;
+                               if ( !html ) {
+                                       var div = this.ownerDocument.createElement("div");
+                                       div.appendChild( this.cloneNode(true) );
+                                       html = div.innerHTML;
+                               }
+                               return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
+                       } else
+                               return this.cloneNode(true);
+               });
+               // Copy the events from the original to the clone
+               if ( events === true ) {
+                       var orig = this.find("*").andSelf(), i = 0;
+                       ret.find("*").andSelf().each(function(){
+                               if ( this.nodeName !== orig[i].nodeName )
+                                       return;
+                               var events = jQuery.data( orig[i], "events" );
+                               for ( var type in events ) {
+                                       for ( var handler in events[ type ] ) {
+                                               jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
+                                       }
+                               }
+                               i++;
+                       });
+               }
+               // Return the cloned set
+               return ret;
+       },
+       filter: function( selector ) {
+               return this.pushStack(
+                       jQuery.isFunction( selector ) &&
+                       jQuery.grep(this, function(elem, i){
+                               return selector.call( elem, i );
+                       }) ||
+                       jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
+                               return elem.nodeType === 1;
+                       }) ), "filter", selector );
+       },
+       closest: function( selector ) {
+               var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
+                       closer = 0;
+               return this.map(function(){
+                       var cur = this;
+                       while ( cur && cur.ownerDocument ) {
+                               if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
+                                       jQuery.data(cur, "closest", closer);
+                                       return cur;
+                               }
+                               cur = cur.parentNode;
+                               closer++;
+                       }
+               });
+       },
+       not: function( selector ) {
+               if ( typeof selector === "string" )
+                       // test special case where just one selector is passed in
+                       if ( isSimple.test( selector ) )
+                               return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
+                       else
+                               selector = jQuery.multiFilter( selector, this );
+               var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
+               return this.filter(function() {
+                       return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
+               });
+       },
+       add: function( selector ) {
+               return this.pushStack( jQuery.unique( jQuery.merge(
+                       this.get(),
+                       typeof selector === "string" ?
+                               jQuery( selector ) :
+                               jQuery.makeArray( selector )
+               )));
+       },
+       is: function( selector ) {
+               return !!selector && jQuery.multiFilter( selector, this ).length > 0;
+       },
+       hasClass: function( selector ) {
+               return !!selector && this.is( "." + selector );
+       },
+       val: function( value ) {
+               if ( value === undefined ) {            
+                       var elem = this[0];
+                       if ( elem ) {
+                               if( jQuery.nodeName( elem, 'option' ) )
+                                       return (elem.attributes.value || {}).specified ? elem.value : elem.text;
+                       
+                               // We need to handle select boxes special
+                               if ( jQuery.nodeName( elem, "select" ) ) {
+                                       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 ];
+                                               if ( option.selected ) {
+                                                       // Get the specifc 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 );
+                                               }
+                                       }
+                                       return values;                  
+                               }
+                               // Everything else, we just grab the value
+                               return (elem.value || "").replace(/\r/g, "");
+                       }
+                       return undefined;
+               }
+               if ( typeof value === "number" )
+                       value += '';
+               return this.each(function(){
+                       if ( this.nodeType != 1 )
+                               return;
+                       if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
+                               this.checked = (jQuery.inArray(this.value, value) >= 0 ||
+                                       jQuery.inArray(this.name, value) >= 0);
+                       else if ( jQuery.nodeName( this, "select" ) ) {
+                               var values = jQuery.makeArray(value);
+                               jQuery( "option", this ).each(function(){
+                                       this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
+                                               jQuery.inArray( this.text, values ) >= 0);
+                               });
+                               if ( !values.length )
+                                       this.selectedIndex = -1;
+                       } else
+                               this.value = value;
+               });
+       },
+       html: function( value ) {
+               return value === undefined ?
+                       (this[0] ?
+                               this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
+                               null) :
+                       this.empty().append( value );
+       },
+       replaceWith: function( value ) {
+               return this.after( value ).remove();
+       },
+       eq: function( i ) {
+               return this.slice( i, +i + 1 );
+       },
+       slice: function() {
+               return this.pushStack( Array.prototype.slice.apply( this, arguments ),
+                       "slice", Array.prototype.slice.call(arguments).join(",") );
+       },
+       map: function( callback ) {
+               return this.pushStack( jQuery.map(this, function(elem, i){
+                       return callback.call( elem, i, elem );
+               }));
+       },
+       andSelf: function() {
+               return this.add( this.prevObject );
+       },
+       domManip: function( args, table, callback ) {
+               if ( this[0] ) {
+                       var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
+                               scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
+                               first = fragment.firstChild;
+                       if ( first )
+                               for ( var i = 0, l = this.length; i < l; i++ )
+                                       callback.call( root(this[i], first), this.length > 1 || i > 0 ?
+                                                       fragment.cloneNode(true) : fragment );
+       
+                       if ( scripts )
+                               jQuery.each( scripts, evalScript );
+               }
+               return this;
+       
+               function root( elem, cur ) {
+                       return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
+                               (elem.getElementsByTagName("tbody")[0] ||
+                               elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+                               elem;
+               }
+       }
+};
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+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 );
+}
+function now(){
+       return +new Date;
+}
+jQuery.extend = jQuery.fn.extend = function() {
+       // copy reference to target object
+       var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+       // 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 ( var name in options ) {
+                               var src = target[ name ], copy = options[ name ];
+                               // Prevent never-ending loop
+                               if ( target === copy )
+                                       continue;
+                               // Recurse if we're merging object values
+                               if ( deep && copy && typeof copy === "object" && !copy.nodeType )
+                                       target[ name ] = jQuery.extend( deep,
+                                               // Never move original objects, clone them
+                                               src || ( copy.length != null ? [ ] : { } )
+                                       , copy );
+                               // Don't bring in undefined values
+                               else if ( copy !== undefined )
+                                       target[ name ] = copy;
+                       }
+       // Return the modified object
+       return target;
+};
+// exclude the following css properties to add px
+var    exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+       // cache defaultView
+       defaultView = document.defaultView || {},
+       toString = Object.prototype.toString;
+jQuery.extend({
+       noConflict: function( deep ) {
+               window.$ = _$;
+               if ( deep )
+                       window.jQuery = _jQuery;
+               return jQuery;
+       },
+       // 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 toString.call(obj) === "[object Function]";
+       },
+       isArray: function( obj ) {
+               return toString.call(obj) === "[object Array]";
+       },
+       // check if an element is in a (or is an) XML document
+       isXMLDoc: function( elem ) {
+               return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+                       !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
+       },
+       // Evalulates a script in a global context
+       globalEval: function( data ) {
+               if ( data && /\S/.test(data) ) {
+                       // Inspired by code by Andrea Giammarchi
+                       // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+                       var head = document.getElementsByTagName("head")[0] || document.documentElement,
+                               script = document.createElement("script");
+                       script.type = "text/javascript";
+                       if ( jQuery.support.scriptEval )
+                               script.appendChild( document.createTextNode( data ) );
+                       else
+                               script.text = data;
+                       // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+                       // This arises when a base node is used (#2709).
+                       head.insertBefore( script, head.firstChild );
+                       head.removeChild( script );
+               }
+       },
+       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;
+               if ( args ) {
+                       if ( length === undefined ) {
+                               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 ( length === undefined ) {
+                               for ( name in object )
+                                       if ( callback.call( object[ name ], name, object[ name ] ) === false )
+                                               break;
+                       } else
+                               for ( var value = object[0];
+                                       i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
+               }
+               return object;
+       },
+       prop: function( elem, value, type, i, name ) {
+               // Handle executable functions
+               if ( jQuery.isFunction( value ) )
+                       value = value.call( elem, i );
+               // Handle passing in a number to a CSS property
+               return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ?
+                       value + "px" :
+                       value;
+       },
+       className: {
+               // internal only, use addClass("class")
+               add: function( elem, classNames ) {
+                       jQuery.each((classNames || "").split(/\s+/), function(i, className){
+                               if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+                                       elem.className += (elem.className ? " " : "") + className;
+                       });
+               },
+               // internal only, use removeClass("class")
+               remove: function( elem, classNames ) {
+                       if (elem.nodeType == 1)
+                               elem.className = classNames !== undefined ?
+                                       jQuery.grep(elem.className.split(/\s+/), function(className){
+                                               return !jQuery.className.has( classNames, className );
+                                       }).join(" ") :
+                                       "";
+               },
+               // internal only, use hasClass("class")
+               has: function( elem, className ) {
+                       return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
+               }
+       },
+       // 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 ( var name in options )
+                       elem.style[ name ] = old[ name ];
+       },
+       css: function( elem, name, force, extra ) {
+               if ( name == "width" || name == "height" ) {
+                       var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
+                       function getWH() {
+                               val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
+                               if ( extra === "border" )
+                                       return;
+                               jQuery.each( which, function() {
+                                       if ( !extra )
+                                               val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+                                       if ( extra === "margin" )
+                                               val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
+                                       else
+                                               val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+                               });
+                       }
+                       if ( elem.offsetWidth !== 0 )
+                               getWH();
+                       else
+                               jQuery.swap( elem, props, getWH );
+                       return Math.max(0, Math.round(val));
+               }
+               return jQuery.curCSS( elem, name, force );
+       },
+       curCSS: function( elem, name, force ) {
+               var ret, style = elem.style;
+               // We need to handle opacity special in IE
+               if ( name == "opacity" && !jQuery.support.opacity ) {
+                       ret = jQuery.attr( style, "opacity" );
+                       return ret == "" ?
+                               "1" :
+                               ret;
+               }
+               // Make sure we're using the right name for getting the float value
+               if ( name.match( /float/i ) )
+                       name = styleFloat;
+               if ( !force && style && style[ name ] )
+                       ret = style[ name ];
+               else if ( defaultView.getComputedStyle ) {
+                       // Only "float" is needed here
+                       if ( name.match( /float/i ) )
+                               name = "float";
+                       name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+                       var computedStyle = defaultView.getComputedStyle( elem, null );
+                       if ( computedStyle )
+                               ret = computedStyle.getPropertyValue( name );
+                       // We should always get a number back from opacity
+                       if ( name == "opacity" && ret == "" )
+                               ret = "1";
+               } else if ( elem.currentStyle ) {
+                       var camelCase = name.replace(/\-(\w)/g, function(all, letter){
+                               return letter.toUpperCase();
+                       });
+                       ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+                       // 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 ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+                               // Remember the original values
+                               var left = style.left, rsLeft = elem.runtimeStyle.left;
+                               // Put in the new values to get a computed value out
+                               elem.runtimeStyle.left = elem.currentStyle.left;
+                               style.left = ret || 0;
+                               ret = style.pixelLeft + "px";
+                               // Revert the changed values
+                               style.left = left;
+                               elem.runtimeStyle.left = rsLeft;
+                       }
+               }
+               return ret;
+       },
+       clean: function( elems, context, fragment ) {
+               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;
+               // If a single string is passed in and it's a single tag
+               // just do a createElement and skip the rest
+               if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
+                       var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
+                       if ( match )
+                               return [ context.createElement( match[1] ) ];
+               }
+               var ret = [], scripts = [], div = context.createElement("div");
+               jQuery.each(elems, function(i, elem){
+                       if ( typeof elem === "number" )
+                               elem += '';
+                       if ( !elem )
+                               return;
+                       // Convert html string into DOM nodes
+                       if ( typeof elem === "string" ) {
+                               // Fix "XHTML"-style tags in all browsers
+                               elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
+                                       return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
+                                               all :
+                                               front + "></" + tag + ">";
+                               });
+                               // Trim whitespace, otherwise indexOf won't work as expected
+                               var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
+                               var wrap =
+                                       // option or optgroup
+                                       !tags.indexOf("<opt") &&
+                                       [ 1, "<select multiple='multiple'>", "</select>" ] ||
+                                       !tags.indexOf("<leg") &&
+                                       [ 1, "<fieldset>", "</fieldset>" ] ||
+                                       tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
+                                       [ 1, "<table>", "</table>" ] ||
+                                       !tags.indexOf("<tr") &&
+                                       [ 2, "<table><tbody>", "</tbody></table>" ] ||
+                                       // <thead> matched above
+                                       (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
+                                       [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
+                                       !tags.indexOf("<col") &&
+                                       [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
+                                       // IE can't serialize <link> and <script> tags normally
+                                       !jQuery.support.htmlSerialize &&
+                                       [ 1, "div<div>", "</div>" ] ||
+                                       [ 0, "", "" ];
+                               // Go to html and back, then peel off extra wrappers
+                               div.innerHTML = wrap[1] + elem + wrap[2];
+                               // Move to the right depth
+                               while ( wrap[0]-- )
+                                       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 = /<tbody/i.test(elem),
+                                               tbody = !tags.indexOf("<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 && /^\s/.test( elem ) )
+                                       div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+                       
+                               elem = jQuery.makeArray( div.childNodes );
+                       }
+                       if ( elem.nodeType )
+                               ret.push( elem );
+                       else
+                               ret = jQuery.merge( ret, elem );
+               });
+               if ( fragment ) {
+                       for ( var i = 0; ret[i]; i++ ) {
+                               if ( 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 )
+                                               ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
+                                       fragment.appendChild( ret[i] );
+                               }
+                       }
+               
+                       return scripts;
+               }
+               return ret;
+       },
+       attr: function( elem, name, value ) {
+               // don't set attributes on text and comment nodes
+               if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
+                       return undefined;
+               var notxml = !jQuery.isXMLDoc( elem ),
+                       // Whether we are setting (or getting)
+                       set = value !== undefined;
+               // Try to normalize/fix the name
+               name = notxml && jQuery.props[ name ] || name;
+               // Only do all the following if this is a node (faster for style)
+               // IE elem.getAttribute passes even for style
+               if ( elem.tagName ) {
+                       // These attributes require special treatment
+                       var special = /href|src|style/.test( name );
+                       // Safari mis-reports the default selected property of a hidden option
+                       // Accessing the parent's selectedIndex property fixes it
+                       if ( name == "selected" && elem.parentNode )
+                               elem.parentNode.selectedIndex;
+                       // If applicable, access the attribute via the DOM 0 way
+                       if ( name in elem && notxml && !special ) {
+                               if ( set ){
+                                       // We can't allow the type property to be changed (since it causes problems in IE)
+                                       if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
+                                               throw "type property can't be changed";
+                                       elem[ name ] = value;
+                               }
+                               // browsers index elements by id/name on forms, give priority to attributes.
+                               if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
+                                       return elem.getAttributeNode( name ).nodeValue;
+                               // 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/
+                               if ( name == "tabIndex" ) {
+                                       var attributeNode = elem.getAttributeNode( "tabIndex" );
+                                       return attributeNode && attributeNode.specified
+                                               ? attributeNode.value
+                                               : elem.nodeName.match(/(button|input|object|select|textarea)/i)
+                                                       ? 0
+                                                       : elem.nodeName.match(/^(a|area)$/i) && elem.href
+                                                               ? 0
+                                                               : undefined;
+                               }
+                               return elem[ name ];
+                       }
+                       if ( !jQuery.support.style && notxml &&  name == "style" )
+                               return jQuery.attr( elem.style, "cssText", value );
+                       if ( set )
+                               // convert the value to a string (all browsers do this but IE) see #1070
+                               elem.setAttribute( name, "" + value );
+                       var attr = !jQuery.support.hrefNormalized && notxml && special
+                                       // Some attributes require a special call on IE
+                                       ? elem.getAttribute( name, 2 )
+                                       : elem.getAttribute( name );
+                       // Non-existent attributes return null, we normalize to undefined
+                       return attr === null ? undefined : attr;
+               }
+               // elem is actually elem.style ... set the style
+               // IE uses filters for opacity
+               if ( !jQuery.support.opacity && name == "opacity" ) {
+                       if ( set ) {
+                               // IE has trouble with opacity if it does not have layout
+                               // Force it by setting the zoom level
+                               elem.zoom = 1;
+                               // Set the alpha filter to set the opacity
+                               elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
+                                       (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+                       }
+                       return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+                               (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
+                               "";
+               }
+               name = name.replace(/-([a-z])/ig, function(all, letter){
+                       return letter.toUpperCase();
+               });
+               if ( set )
+                       elem[ name ] = value;
+               return elem[ name ];
+       },
+       trim: function( text ) {
+               return (text || "").replace( /^\s+|\s+$/g, "" );
+       },
+       makeArray: function( array ) {
+               var ret = [];
+               if( array != null ){
+                       var i = array.length;
+                       // The window, strings (and functions) also have 'length'
+                       if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
+                               ret[0] = array;
+                       else
+                               while( i )
+                                       ret[--i] = array[i];
+               }
+               return ret;
+       },
+       inArray: function( elem, array ) {
+               for ( var i = 0, length = array.length; i < length; i++ )
+               // Use === because on IE, window == document
+                       if ( array[ i ] === elem )
+                               return i;
+               return -1;
+       },
+       merge: function( first, second ) {
+               // We have to loop this way because IE & Opera overwrite the length
+               // expando of getElementsByTagName
+               var i = 0, elem, pos = first.length;
+               // Also, we need to make sure that the correct elements are being returned
+               // (IE returns comment nodes in a '*' query)
+               if ( !jQuery.support.getAll ) {
+                       while ( (elem = second[ i++ ]) != null )
+                               if ( elem.nodeType != 8 )
+                                       first[ pos++ ] = elem;
+               } else
+                       while ( (elem = second[ i++ ]) != null )
+                               first[ pos++ ] = elem;
+               return first;
+       },
+       unique: function( array ) {
+               var ret = [], done = {};
+               try {
+                       for ( var i = 0, length = array.length; i < length; i++ ) {
+                               var id = jQuery.data( array[ i ] );
+                               if ( !done[ id ] ) {
+                                       done[ id ] = true;
+                                       ret.push( array[ i ] );
+                               }
+                       }
+               } catch( e ) {
+                       ret = array;
+               }
+               return ret;
+       },
+       grep: function( elems, callback, inv ) {
+               var ret = [];
+               // Go through the array, only saving the items
+               // that pass the validator function
+               for ( var i = 0, length = elems.length; i < length; i++ )
+                       if ( !inv != !callback( elems[ i ], i ) )
+                               ret.push( elems[ i ] );
+               return ret;
+       },
+       map: function( elems, callback ) {
+               var ret = [];
+               // Go through the array, translating each of the items to their
+               // new value (or values).
+               for ( var i = 0, length = elems.length; i < length; i++ ) {
+                       var value = callback( elems[ i ], i );
+                       if ( value != null )
+                               ret[ ret.length ] = value;
+               }
+               return ret.concat.apply( [], ret );
+       }
+});
+// Use of jQuery.browser is deprecated.
+// It's included for backwards compatibility and plugins,
+// although they should work to migrate away.
+var userAgent = navigator.userAgent.toLowerCase();
+// Figure out what browser is being used
+jQuery.browser = {
+       version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
+       safari: /webkit/.test( userAgent ),
+       opera: /opera/.test( userAgent ),
+       msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+       mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+jQuery.each({
+       parent: function(elem){return elem.parentNode;},
+       parents: function(elem){return jQuery.dir(elem,"parentNode");},
+       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");},
+       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( selector ) {
+               var ret = jQuery.map( this, fn );
+               if ( selector && typeof selector == "string" )
+                       ret = jQuery.multiFilter( selector, ret );
+               return this.pushStack( jQuery.unique( ret ), name, selector );
+       };
+});
+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 );
+               for ( var i = 0, l = insert.length; i < l; i++ ) {
+                       var elems = (i > 0 ? this.clone(true) : this).get();
+                       jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
+                       ret = ret.concat( elems );
+               }
+               return this.pushStack( ret, name, selector );
+       };
+});
+jQuery.each({
+       removeAttr: function( name ) {
+               jQuery.attr( this, name, "" );
+               if (this.nodeType == 1)
+                       this.removeAttribute( name );
+       },
+       addClass: function( classNames ) {
+               jQuery.className.add( this, classNames );
+       },
+       removeClass: function( classNames ) {
+               jQuery.className.remove( this, classNames );
+       },
+       toggleClass: function( classNames, state ) {
+               if( typeof state !== "boolean" )
+                       state = !jQuery.className.has( this, classNames );
+               jQuery.className[ state ? "add" : "remove" ]( this, classNames );
+       },
+       remove: function( selector ) {
+               if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
+                       // Prevent memory leaks
+                       jQuery( "*", this ).add([this]).each(function(){
+                               jQuery.event.remove(this);
+                               jQuery.removeData(this);
+                       });
+                       if (this.parentNode)
+                               this.parentNode.removeChild( this );
+               }
+       },
+       empty: function() {
+               // Remove element nodes and prevent memory leaks
+               jQuery(this).children().remove();
+               // Remove any remaining nodes
+               while ( this.firstChild )
+                       this.removeChild( this.firstChild );
+       }
+}, function(name, fn){
+       jQuery.fn[ name ] = function(){
+               return this.each( fn, arguments );
+       };
+});
+// Helper function used by the dimensions and offset modules
+function num(elem, prop) {
+       return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
+}
+var expando = "jQuery" + now(), uuid = 0, windowData = {};
+jQuery.extend({
+       cache: {},
+       data: function( elem, name, data ) {
+               elem = elem == window ?
+                       windowData :
+                       elem;
+               var id = elem[ expando ];
+               // Compute a unique ID for the element
+               if ( !id )
+                       id = elem[ expando ] = ++uuid;
+               // Only generate the data cache if we're
+               // trying to access or manipulate it
+               if ( name && !jQuery.cache[ id ] )
+                       jQuery.cache[ id ] = {};
+               // Prevent overriding the named cache with undefined values
+               if ( data !== undefined )
+                       jQuery.cache[ id ][ name ] = data;
+               // Return the named cache data, or the ID for the element
+               return name ?
+                       jQuery.cache[ id ][ name ] :
+                       id;
+       },
+       removeData: function( elem, name ) {
+               elem = elem == window ?
+                       windowData :
+                       elem;
+               var id = elem[ expando ];
+               // If we want to remove a specific section of the element's data
+               if ( name ) {
+                       if ( jQuery.cache[ id ] ) {
+                               // Remove the section of cache data
+                               delete jQuery.cache[ id ][ name ];
+                               // If we've removed all the data, remove the element's cache
+                               name = "";
+                               for ( name in jQuery.cache[ id ] )
+                                       break;
+                               if ( !name )
+                                       jQuery.removeData( elem );
+                       }
+               // Otherwise, we want to remove all of the element's data
+               } else {
+                       // Clean up the element expando
+                       try {
+                               delete elem[ expando ];
+                       } catch(e){
+                               // IE has trouble directly removing the expando
+                               // but it's ok with using removeAttribute
+                               if ( elem.removeAttribute )
+                                       elem.removeAttribute( expando );
+                       }
+                       // Completely remove the data cache
+                       delete jQuery.cache[ id ];
+               }
+       },
+       queue: function( elem, type, data ) {
+               if ( elem ){
+
+                       type = (type || "fx") + "queue";
+
+                       var q = jQuery.data( elem, type );
+
+                       if ( !q || jQuery.isArray(data) )
+                               q = jQuery.data( elem, type, jQuery.makeArray(data) );
+                       else if( data )
+                               q.push( data );
+
+               }
+               return q;
+       },
+       dequeue: function( elem, type ){
+               var queue = jQuery.queue( elem, type ),
+                       fn = queue.shift();
+       
+               if( !type || type === "fx" )
+                       fn = queue[0];
+               
+               if( fn !== undefined )
+                       fn.call(elem);
+       }
+});
+jQuery.fn.extend({
+       data: function( key, value ){
+               var parts = key.split(".");
+               parts[1] = parts[1] ? "." + parts[1] : "";
+               if ( value === undefined ) {
+                       var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+                       if ( data === undefined && this.length )
+                               data = jQuery.data( this[0], key );
+                       return data === undefined && parts[1] ?
+                               this.data( parts[0] ) :
+                               data;
+               } else
+                       return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
+                               jQuery.data( this, key, value );
+                       });
+       },
+       removeData: function( key ){
+               return this.each(function(){
+                       jQuery.removeData( this, key );
+               });
+       },
+       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.length == 1 )
+                               queue[0].call(this);
+               });
+       },
+       dequeue: function(type){
+               return this.each(function(){
+                       jQuery.dequeue( this, type );
+               });
+       }
+});/*!
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
+       done = 0,
+       toString = Object.prototype.toString;
+var Sizzle = function(selector, context, results, seed) {
+       results = results || [];
+       context = context || document;
+       if ( context.nodeType !== 1 && context.nodeType !== 9 )
+               return [];
+
+       if ( !selector || typeof selector !== "string" ) {
+               return results;
+       }
+       var parts = [], m, set, checkSet, check, mode, extra, prune = true;
+
+       // Reset the position of the chunker regexp (start from head)
+       chunker.lastIndex = 0;
+
+       while ( (m = chunker.exec(selector)) !== null ) {
+               parts.push( m[1] );
+       
+               if ( m[2] ) {
+                       extra = RegExp.rightContext;
+                       break;
+               }
+       }
+       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 {
+               var ret = seed ?
+                       { expr: parts.pop(), set: makeArray(seed) } :
+                       Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
+               set = Sizzle.filter( ret.expr, ret.set );
+               if ( parts.length > 0 ) {
+                       checkSet = makeArray(set);
+               } else {
+                       prune = false;
+               }
+               while ( parts.length ) {
+                       var cur = parts.pop(), pop = cur;
+                       if ( !Expr.relative[ cur ] ) {
+                               cur = "";
+                       } else {
+                               pop = parts.pop();
+                       }
+                       if ( pop == null ) {
+                               pop = context;
+                       }
+                       Expr.relative[ cur ]( checkSet, pop, isXML(context) );
+               }
+       }
+       if ( !checkSet ) {
+               checkSet = set;
+       }
+       if ( !checkSet ) {
+               throw "Syntax error, unrecognized expression: " + (cur || selector);
+       }
+       if ( toString.call(checkSet) === "[object Array]" ) {
+               if ( !prune ) {
+                       results.push.apply( results, checkSet );
+               } else if ( context.nodeType === 1 ) {
+                       for ( var i = 0; checkSet[i] != null; i++ ) {
+                               if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+                                       results.push( set[i] );
+                               }
+                       }
+               } else {
+                       for ( var 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, context, results, seed );
+               if ( sortOrder ) {
+                       hasDuplicate = false;
+                       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.find = function(expr, context, isXML){
+       var set, match;
+       if ( !expr ) {
+               return [];
+       }
+       for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+               var type = Expr.order[i], match;
+       
+               if ( (match = Expr.match[ type ].exec( expr )) ) {
+                       var left = RegExp.leftContext;
+                       if ( left.substr( left.length - 1 ) !== "\\" ) {
+                               match[1] = (match[1] || "").replace(/\\/g, "");
+                               set = Expr.find[ type ]( match, context, isXML );
+                               if ( set != null ) {
+                                       expr = expr.replace( Expr.match[ type ], "" );
+                                       break;
+                               }
+                       }
+               }
+       }
+       if ( !set ) {
+               set = context.getElementsByTagName("*");
+       }
+       return {set: set, expr: expr};
+};
+Sizzle.filter = function(expr, set, inplace, not){
+       var old = expr, result = [], curLoop = set, match, anyFound,
+               isXMLFilter = set && set[0] && isXML(set[0]);
+       while ( expr && set.length ) {
+               for ( var type in Expr.filter ) {
+                       if ( (match = Expr.match[ type ].exec( expr )) != null ) {
+                               var filter = Expr.filter[ type ], found, item;
+                               anyFound = false;
+                               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 ) {
+                               throw "Syntax error, unrecognized expression: " + expr;
+                       } else {
+                               break;
+                       }
+               }
+               old = expr;
+       }
+       return curLoop;
+};
+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|)\s*\]/,
+               TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
+               CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+               POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+               PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
+       },
+       attrMap: {
+               "class": "className",
+               "for": "htmlFor"
+       },
+       attrHandle: {
+               href: function(elem){
+                       return elem.getAttribute("href");
+               }
+       },
+       relative: {
+               "+": function(checkSet, part, isXML){
+                       var isPartStr = typeof part === "string",
+                               isTag = isPartStr && !/\W/.test(part),
+                               isPartStrNotTag = isPartStr && !isTag;
+                       if ( isTag && !isXML ) {
+                               part = part.toUpperCase();
+                       }
+                       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 === part ?
+                                               elem || false :
+                                               elem === part;
+                               }
+                       }
+                       if ( isPartStrNotTag ) {
+                               Sizzle.filter( part, checkSet, true );
+                       }
+               },
+               ">": function(checkSet, part, isXML){
+                       var isPartStr = typeof part === "string";
+                       if ( isPartStr && !/\W/.test(part) ) {
+                               part = isXML ? part : part.toUpperCase();
+                               for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                                       var elem = checkSet[i];
+                                       if ( elem ) {
+                                               var parent = elem.parentNode;
+                                               checkSet[i] = parent.nodeName === part ? parent : false;
+                                       }
+                               }
+                       } else {
+                               for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                                       var 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 doneName = done++, checkFn = dirCheck;
+                       if ( !part.match(/\W/) ) {
+                               var nodeCheck = part = isXML ? part : part.toUpperCase();
+                               checkFn = dirNodeCheck;
+                       }
+                       checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+               },
+               "~": function(checkSet, part, isXML){
+                       var doneName = done++, checkFn = dirCheck;
+                       if ( typeof part === "string" && !part.match(/\W/) ) {
+                               var nodeCheck = part = isXML ? part : part.toUpperCase();
+                               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]);
+                               return m ? [m] : [];
+                       }
+               },
+               NAME: function(match, context, isXML){
+                       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){
+                       return context.getElementsByTagName(match[1]);
+               }
+       },
+       preFilter: {
+               CLASS: function(match, curLoop, inplace, result, not, isXML){
+                       match = " " + match[1].replace(/\\/g, "") + " ";
+                       if ( isXML ) {
+                               return match;
+                       }
+                       for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+                               if ( elem ) {
+                                       if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
+                                               if ( !inplace )
+                                                       result.push( elem );
+                                       } else if ( inplace ) {
+                                               curLoop[i] = false;
+                                       }
+                               }
+                       }
+                       return false;
+               },
+               ID: function(match){
+                       return match[1].replace(/\\/g, "");
+               },
+               TAG: function(match, curLoop){
+                       for ( var i = 0; curLoop[i] === false; i++ ){}
+                       return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
+               },
+               CHILD: function(match){
+                       if ( match[1] == "nth" ) {
+                               // 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;
+                       }
+                       // TODO: Move to normal caching system
+                       match[0] = done++;
+                       return match;
+               },
+               ATTR: function(match, curLoop, inplace, result, not, isXML){
+                       var name = match[1].replace(/\\/g, "");
+               
+                       if ( !isXML && Expr.attrMap[name] ) {
+                               match[1] = Expr.attrMap[name];
+                       }
+                       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 ( match[3].match(chunker).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
+                       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){
+                       return "text" === elem.type;
+               },
+               radio: function(elem){
+                       return "radio" === elem.type;
+               },
+               checkbox: function(elem){
+                       return "checkbox" === elem.type;
+               },
+               file: function(elem){
+                       return "file" === elem.type;
+               },
+               password: function(elem){
+                       return "password" === elem.type;
+               },
+               submit: function(elem){
+                       return "submit" === elem.type;
+               },
+               image: function(elem){
+                       return "image" === elem.type;
+               },
+               reset: function(elem){
+                       return "reset" === elem.type;
+               },
+               button: function(elem){
+                       return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
+               },
+               input: function(elem){
+                       return /input|select|textarea|button/i.test(elem.nodeName);
+               }
+       },
+       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 || "").indexOf(match[3]) >= 0;
+                       } else if ( name === "not" ) {
+                               var not = match[3];
+                               for ( var i = 0, l = not.length; i < l; i++ ) {
+                                       if ( not[i] === elem ) {
+                                               return false;
+                                       }
+                               }
+                               return true;
+                       }
+               },
+               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 === 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;
+for ( var type in Expr.match ) {
+       Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
+}
+var makeArray = function(array, results) {
+       array = Array.prototype.slice.call( array );
+       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.
+try {
+       Array.prototype.slice.call( document.documentElement.childNodes );
+// Provide a fallback method if it does not work
+} catch(e){
+       makeArray = function(array, results) {
+               var ret = results || [];
+               if ( toString.call(array) === "[object Array]" ) {
+                       Array.prototype.push.apply( ret, array );
+               } else {
+                       if ( typeof array.length === "number" ) {
+                               for ( var i = 0, l = array.length; i < l; i++ ) {
+                                       ret.push( array[i] );
+                               }
+                       } else {
+                               for ( var i = 0; array[i]; i++ ) {
+                                       ret.push( array[i] );
+                               }
+                       }
+               }
+               return ret;
+       };
+}
+var sortOrder;
+if ( document.documentElement.compareDocumentPosition ) {
+       sortOrder = function( a, b ) {
+               var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+               if ( ret === 0 ) {
+                       hasDuplicate = true;
+               }
+               return ret;
+       };
+} else if ( "sourceIndex" in document.documentElement ) {
+       sortOrder = function( a, b ) {
+               var ret = a.sourceIndex - b.sourceIndex;
+               if ( ret === 0 ) {
+                       hasDuplicate = true;
+               }
+               return ret;
+       };
+} else if ( document.createRange ) {
+       sortOrder = function( a, b ) {
+               var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+               aRange.selectNode(a);
+               aRange.collapse(true);
+               bRange.selectNode(b);
+               bRange.collapse(true);
+               var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+               if ( ret === 0 ) {
+                       hasDuplicate = true;
+               }
+               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("form"),
+               id = "script" + (new Date).getTime();
+       form.innerHTML = "<input name='" + id + "'/>";
+       // Inject it into the root element, check its status, and remove it quickly
+       var root = document.documentElement;
+       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 );
+})();
+(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);
+               };
+       }
+})();
+if ( document.querySelectorAll ) (function(){
+       var oldSizzle = Sizzle, div = document.createElement("div");
+       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 && context.nodeType === 9 && !isXML(context) ) {
+                       try {
+                               return makeArray( context.querySelectorAll(query), extra );
+                       } catch(e){}
+               }
+       
+               return oldSizzle(query, context, extra, seed);
+       };
+       Sizzle.find = oldSizzle.find;
+       Sizzle.filter = oldSizzle.filter;
+       Sizzle.selectors = oldSizzle.selectors;
+       Sizzle.matches = oldSizzle.matches;
+})();
+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (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)
+       if ( 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]);
+               }
+       };
+})();
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+       var sibDir = dir == "previousSibling" && !isXML;
+       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+               var elem = checkSet[i];
+               if ( elem ) {
+                       if ( sibDir && elem.nodeType === 1 ){
+                               elem.sizcache = doneName;
+                               elem.sizset = i;
+                       }
+                       elem = elem[dir];
+                       var match = false;
+                       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 === cur ) {
+                                       match = elem;
+                                       break;
+                               }
+                               elem = elem[dir];
+                       }
+                       checkSet[i] = match;
+               }
+       }
+}
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+       var sibDir = dir == "previousSibling" && !isXML;
+       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+               var elem = checkSet[i];
+               if ( elem ) {
+                       if ( sibDir && elem.nodeType === 1 ) {
+                               elem.sizcache = doneName;
+                               elem.sizset = i;
+                       }
+                       elem = elem[dir];
+                       var match = false;
+                       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;
+               }
+       }
+}
+var contains = document.compareDocumentPosition ?  function(a, b){
+       return a.compareDocumentPosition(b) & 16;
+} : function(a, b){
+       return a !== b && (a.contains ? a.contains(b) : true);
+};
+var isXML = function(elem){
+       return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+               !!elem.ownerDocument && isXML( elem.ownerDocument );
+};
+var posProcess = function(selector, context){
+       var tmpSet = [], later = "", match,
+               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.filter = Sizzle.filter;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+Sizzle.selectors.filters.hidden = function(elem){
+       return elem.offsetWidth === 0 || elem.offsetHeight === 0;
+};
+Sizzle.selectors.filters.visible = function(elem){
+       return elem.offsetWidth > 0 || elem.offsetHeight > 0;
+};
+Sizzle.selectors.filters.animated = function(elem){
+       return jQuery.grep(jQuery.timers, function(fn){
+               return elem === fn.elem;
+       }).length;
+};
+jQuery.multiFilter = function( expr, elems, not ) {
+       if ( not ) {
+               expr = ":not(" + expr + ")";
+       }
+       return Sizzle.matches(expr, elems);
+};
+jQuery.dir = function( elem, dir ){
+       var matched = [], cur = elem[dir];
+       while ( cur && cur != document ) {
+               if ( cur.nodeType == 1 )
+                       matched.push( cur );
+               cur = cur[dir];
+       }
+       return matched;
+};
+jQuery.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;
+};
+jQuery.sibling = function(n, elem){
+       var r = [];
+       for ( ; n; n = n.nextSibling ) {
+               if ( n.nodeType == 1 && n != elem )
+                       r.push( n );
+       }
+       return r;
+};
+return;
+window.Sizzle = Sizzle;
+})();
+/*
+ * 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;
+               // For whatever reason, IE has trouble passing the window object
+               // around, causing it to be cloned in the process
+               if ( elem.setInterval && elem != window )
+                       elem = window;
+               // Make sure that the function being executed has a unique ID
+               if ( !handler.guid )
+                       handler.guid = this.guid++;
+               // if data is passed, bind to handler
+               if ( data !== undefined ) {
+                       // Create temporary function pointer to original handler
+                       var fn = handler;
+                       // Create unique handler function, wrapped around original handler
+                       handler = this.proxy( fn );
+                       // Store data in unique handler
+                       handler.data = data;
+               }
+               // Init the element's event structure
+               var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+                       handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+                               // Handle the second event of a trigger and when
+                               // an event is called after a page has unloaded
+                               return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+                                       jQuery.event.handle.apply(arguments.callee.elem, arguments) :
+                                       undefined;
+                       });
+               // Add elem as a property of the handle function
+               // This is to prevent a memory leak with non-native
+               // event in IE.
+               handle.elem = elem;
+               // Handle multiple events separated by a space
+               // jQuery(...).bind("mouseover mouseout", fn);
+               jQuery.each(types.split(/\s+/), function(index, type) {
+                       // Namespaced event handlers
+                       var namespaces = type.split(".");
+                       type = namespaces.shift();
+                       handler.type = namespaces.slice().sort().join(".");
+                       // Get the current list of functions bound to this event
+                       var handlers = events[type];
+               
+                       if ( jQuery.event.specialAll[type] )
+                               jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
+                       // 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 ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
+                                       // Bind the global event handler to the element
+                                       if (elem.addEventListener)
+                                               elem.addEventListener(type, handle, false);
+                                       else if (elem.attachEvent)
+                                               elem.attachEvent("on" + type, handle);
+                               }
+                       }
+                       // Add the function to the element's handler list
+                       handlers[handler.guid] = handler;
+                       // Keep track of which events have been used, for global triggering
+                       jQuery.event.global[type] = true;
+               });
+               // Nullify elem to prevent memory leaks in IE
+               elem = null;
+       },
+       guid: 1,
+       global: {},
+       // Detach an event or set of events from an element
+       remove: function(elem, types, handler) {
+               // don't do events on text and comment nodes
+               if ( elem.nodeType == 3 || elem.nodeType == 8 )
+                       return;
+               var events = jQuery.data(elem, "events"), ret, index;
+               if ( events ) {
+                       // Unbind all events for the element
+                       if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") )
+                               for ( var type in events )
+                                       this.remove( elem, type + (types || "") );
+                       else {
+                               // types is actually an event object here
+                               if ( types.type ) {
+                                       handler = types.handler;
+                                       types = types.type;
+                               }
+                               // Handle multiple events seperated by a space
+                               // jQuery(...).unbind("mouseover mouseout", fn);
+                               jQuery.each(types.split(/\s+/), function(index, type){
+                                       // Namespaced event handlers
+                                       var namespaces = type.split(".");
+                                       type = namespaces.shift();
+                                       var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
+                                       if ( events[type] ) {
+                                               // remove the given handler for the given type
+                                               if ( handler )
+                                                       delete events[type][handler.guid];
+                                               // remove all handlers for the given type
+                                               else
+                                                       for ( var handle in events[type] )
+                                                               // Handle the removal of namespaced events
+                                                               if ( namespace.test(events[type][handle].type) )
+                                                                       delete events[type][handle];
+                                                               
+                                               if ( jQuery.event.specialAll[type] )
+                                                       jQuery.event.specialAll[type].teardown.call(elem, namespaces);
+                                               // remove generic event handler if no more handlers exist
+                                               for ( ret in events[type] ) break;
+                                               if ( !ret ) {
+                                                       if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
+                                                               if (elem.removeEventListener)
+                                                                       elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+                                                               else if (elem.detachEvent)
+                                                                       elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+                                                       }
+                                                       ret = null;
+                                                       delete events[type];
+                                               }
+                                       }
+                               });
+                       }
+                       // Remove the expando if it's no longer used
+                       for ( ret in events ) break;
+                       if ( !ret ) {
+                               var handle = jQuery.data( elem, "handle" );
+                               if ( handle ) handle.elem = null;
+                               jQuery.removeData( elem, "events" );
+                               jQuery.removeData( elem, "handle" );
+                       }
+               }
+       },
+       // bubbling is internal
+       trigger: function( event, data, elem, bubbling ) {
+               // Event object or event type
+               var type = event.type || event;
+               if( !bubbling ){
+                       event = typeof event === "object" ?
+                               // jQuery.Event object
+                               event[expando] ? event :
+                               // Object literal
+                               jQuery.extend( jQuery.Event(type), event ) :
+                               // Just the event type (string)
+                               jQuery.Event(type);
+                       if ( type.indexOf("!") >= 0 ) {
+                               event.type = type = type.slice(0, -1);
+                               event.exclusive = true;
+                       }
+                       // Handle a global trigger
+                       if ( !elem ) {
+                               // Don't bubble custom events when global (to avoid too much overhead)
+                               event.stopPropagation();
+                               // Only trigger if we've ever bound an event for it
+                               if ( this.global[type] )
+                                       jQuery.each( jQuery.cache, function(){
+                                               if ( this.events && this.events[type] )
+                                                       jQuery.event.trigger( event, data, this.handle.elem );
+                                       });
+                       }
+                       // Handle triggering a single element
+                       // don't do events on text and comment nodes
+                       if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 )
+                               return undefined;
+               
+                       // Clean up in case it is reused
+                       event.result = undefined;
+                       event.target = elem;
+               
+                       // Clone the incoming data, if any
+                       data = jQuery.makeArray(data);
+                       data.unshift( event );
+               }
+               event.currentTarget = elem;
+               // Trigger the event, it is assumed that "handle" is a function
+               var handle = jQuery.data(elem, "handle");
+               if ( handle )
+                       handle.apply( elem, data );
+               // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+               if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+                       event.result = false;
+               // Trigger the native events (except for clicks on links)
+               if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
+                       this.triggered = true;
+                       try {
+                               elem[ type ]();
+                       // prevent IE from throwing an error for some hidden elements
+                       } catch (e) {}
+               }
+               this.triggered = false;
+               if ( !event.isPropagationStopped() ) {
+                       var parent = elem.parentNode || elem.ownerDocument;
+                       if ( parent )
+                               jQuery.event.trigger(event, data, parent, true);
+               }
+       },
+       handle: function(event) {
+               // returned undefined or false
+               var all, handlers;
+               event = arguments[0] = jQuery.event.fix( event || window.event );
+               event.currentTarget = this;
+       
+               // Namespaced event handlers
+               var namespaces = event.type.split(".");
+               event.type = namespaces.shift();
+               // Cache this now, all = true means, any handler
+               all = !namespaces.length && !event.exclusive;
+       
+               var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
+               handlers = ( jQuery.data(this, "events") || {} )[event.type];
+               for ( var j in handlers ) {
+                       var handler = handlers[j];
+                       // Filter the functions by class
+                       if ( all || namespace.test(handler.type) ) {
+                               // Pass in a reference to the handler function itself
+                               // So that we can later remove it
+                               event.handler = handler;
+                               event.data = handler.data;
+                               var ret = handler.apply(this, arguments);
+                               if( ret !== undefined ){
+                                       event.result = ret;
+                                       if ( ret === false ) {
+                                               event.preventDefault();
+                                               event.stopPropagation();
+                                       }
+                               }
+                               if( event.isImmediatePropagationStopped() )
+                                       break;
+                       }
+               }
+       },
+       props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+       fix: function(event) {
+               if ( event[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 )
+                       event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+               // 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 doc = document.documentElement, body = document.body;
+                       event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+                       event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+               }
+               // Add which for key events
+               if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
+                       event.which = 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 )
+                       event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+               return event;
+       },
+       proxy: function( fn, proxy ){
+               proxy = proxy || function(){ return fn.apply(this, 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 || this.guid++;
+               // So proxy can be declared as an argument
+               return proxy;
+       },
+       special: {
+               ready: {
+                       // Make sure the ready event is setup
+                       setup: bindReady,
+                       teardown: function() {}
+               }
+       },
+
+       specialAll: {
+               live: {
+                       setup: function( selector, namespaces ){
+                               jQuery.event.add( this, namespaces[0], liveHandler );
+                       },
+                       teardown:  function( namespaces ){
+                               if ( namespaces.length ) {
+                                       var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
+                               
+                                       jQuery.each( (jQuery.data(this, "events").live || {}), function(){
+                                               if ( name.test(this.type) )
+                                                       remove++;
+                                       });
+                               
+                                       if ( remove < 1 )
+                                               jQuery.event.remove( this, namespaces[0], liveHandler );
+                               }
+                       }
+               }
+       }
+};
+jQuery.Event = function( src ){
+       // Allow instantiation without the 'new' keyword
+       if( !this.preventDefault )
+               return new jQuery.Event(src);
+
+       // Event object
+       if( src && src.type ){
+               this.originalEvent = src;
+               this.type = src.type;
+       // Event type
+       }else
+               this.type = src;
+       // timeStamp is buggy for some events on Firefox(#3843)
+       // So we won't rely on the native value
+       this.timeStamp = now();
+
+       // Mark it as fixed
+       this[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)
+               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;
+       // Traverse up the tree
+       while ( parent && parent != this )
+               try { parent = parent.parentNode; }
+               catch(e) { parent = this; }
+
+       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 );
+       }
+};
+
+jQuery.each({
+       mouseover: 'mouseenter',
+       mouseout: 'mouseleave'
+}, function( orig, fix ){
+       jQuery.event.special[ fix ] = {
+               setup: function(){
+                       jQuery.event.add( this, orig, withinElement, fix );
+               },
+               teardown: function(){
+                       jQuery.event.remove( this, orig, withinElement );
+               }
+       };                        
+});
+jQuery.fn.extend({
+       bind: function( type, data, fn ) {
+               return type == "unload" ? this.one(type, data, fn) : this.each(function(){
+                       jQuery.event.add( this, type, fn || data, fn && data );
+               });
+       },
+       one: function( type, data, fn ) {
+               var one = jQuery.event.proxy( fn || data, function(event) {
+                       jQuery(this).unbind(event, one);
+                       return (fn || data).apply( this, arguments );
+               });
+               return this.each(function(){
+                       jQuery.event.add( this, type, one, fn && data);
+               });
+       },
+       unbind: function( type, fn ) {
+               return this.each(function(){
+                       jQuery.event.remove( this, type, fn );
+               });
+       },
+       trigger: function( type, data ) {
+               return this.each(function(){
+                       jQuery.event.trigger( type, data, this );
+               });
+       },
+       triggerHandler: function( type, data ) {
+               if( this[0] ){
+                       var event = jQuery.Event(type);
+                       event.preventDefault();
+                       event.stopPropagation();
+                       jQuery.event.trigger( event, data, this[0] );
+                       return event.result;
+               }       
+       },
+       toggle: function( fn ) {
+               // Save reference to arguments for access in closure
+               var args = arguments, i = 1;
+               // link all the functions, so any of them can unbind this click handler
+               while( i < args.length )
+                       jQuery.event.proxy( fn, args[i++] );
+               return this.click( jQuery.event.proxy( fn, function(event) {
+                       // Figure out which function to execute
+                       this.lastToggle = ( this.lastToggle || 0 ) % i;
+                       // Make sure that clicks stop
+                       event.preventDefault();
+                       // and execute the function
+                       return args[ this.lastToggle++ ].apply( this, arguments ) || false;
+               }));
+       },
+       hover: function(fnOver, fnOut) {
+               return this.mouseenter(fnOver).mouseleave(fnOut);
+       },
+       ready: function(fn) {
+               // Attach the listeners
+               bindReady();
+               // If the DOM is already ready
+               if ( jQuery.isReady )
+                       // Execute the function immediately
+                       fn.call( document, jQuery );
+               // Otherwise, remember the function for later
+               else
+                       // Add the function to the wait list
+                       jQuery.readyList.push( fn );
+               return this;
+       },
+
+       live: function( type, fn ){
+               var proxy = jQuery.event.proxy( fn );
+               proxy.guid += this.selector + type;
+               jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy );
+               return this;
+       },
+
+       die: function( type, fn ){
+               jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
+               return this;
+       }
+});
+function liveHandler( event ){
+       var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"),
+               stop = true,
+               elems = [];
+       jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
+               if ( check.test(fn.type) ) {
+                       var elem = jQuery(event.target).closest(fn.data)[0];
+                       if ( elem )
+                               elems.push({ elem: elem, fn: fn });
+               }
+       });
+       elems.sort(function(a,b) {
+               return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
+       });
+
+       jQuery.each(elems, function(){
+               if ( this.fn.call(this.elem, event, this.fn.data) === false )
+                       return (stop = false);
+       });
+       return stop;
+}
+function liveConvert(type, selector){
+       return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
+}
+jQuery.extend({
+       isReady: false,
+       readyList: [],
+       // Handle when the DOM is ready
+       ready: function() {
+               // Make sure that the DOM is not already loaded
+               if ( !jQuery.isReady ) {
+                       // Remember that the DOM is ready
+                       jQuery.isReady = true;
+                       // If there are functions bound, to execute
+                       if ( jQuery.readyList ) {
+                               // Execute all of them
+                               jQuery.each( jQuery.readyList, function(){
+                                       this.call( document, jQuery );
+                               });
+                               // Reset the list of functions
+                               jQuery.readyList = null;
+                       }
+                       // Trigger any bound ready events
+                       jQuery(document).triggerHandler("ready");
+               }
+       }
+});
+var readyBound = false;
+function bindReady(){
+       if ( readyBound ) return;
+       readyBound = true;
+       // Mozilla, Opera and webkit nightlies currently support this event
+       if ( document.addEventListener ) {
+               // Use the handy event callback
+               document.addEventListener( "DOMContentLoaded", function(){
+                       document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
+                       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", function(){
+                       if ( document.readyState === "complete" ) {
+                               document.detachEvent( "onreadystatechange", arguments.callee );
+                               jQuery.ready();
+                       }
+               });
+               // If IE and not an iframe
+               // continually check to see if the document is ready
+               if ( document.documentElement.doScroll && window == window.top ) (function(){
+                       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( error ) {
+                               setTimeout( arguments.callee, 0 );
+                               return;
+                       }
+                       // and execute any waiting functions
+                       jQuery.ready();
+               })();
+       }
+       // A fallback to window.onload, that will always work
+       jQuery.event.add( window, "load", jQuery.ready );
+}
+jQuery.each( ("blur,focus,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(fn){
+               return fn ? this.bind(name, fn) : this.trigger(name);
+       };
+});
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery( window ).bind( 'unload', function(){
+       for ( var id in jQuery.cache )
+               // Skip the window
+               if ( id != 1 && jQuery.cache[ id ].handle )
+                       jQuery.event.remove( jQuery.cache[ id ].handle.elem );
+});
+(function(){
+       jQuery.support = {};
+       var root = document.documentElement,
+               script = document.createElement("script"),
+               div = document.createElement("div"),
+               id = "script" + (new Date).getTime();
+       div.style.display = "none";
+       div.innerHTML = '   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
+       var all = div.getElementsByTagName("*"),
+               a = div.getElementsByTagName("a")[0];
+       // Can't get basic test support
+       if ( !all || !all.length || !a ) {
+               return;
+       }
+       jQuery.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 you can get all elements in an <object> element
+               // IE 7 always returns no results
+               objectAll: !!div.getElementsByTagName("object")[0]
+                       .getElementsByTagName("*").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 insted)
+               style: /red/.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)
+               opacity: a.style.opacity === "0.5",
+       
+               // Verify style float existence
+               // (IE uses styleFloat instead of cssFloat)
+               cssFloat: !!a.style.cssFloat,
+               // Will be defined later
+               scriptEval: false,
+               noCloneEvent: true,
+               boxModel: null
+       };
+
+       script.type = "text/javascript";
+       try {
+               script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
+       } catch(e){}
+       root.insertBefore( script, root.firstChild );
+
+       // Make sure that the execution of code works by injecting a script
+       // tag with appendChild/createTextNode
+       // (IE doesn't support this, fails, and uses .text instead)
+       if ( window[ id ] ) {
+               jQuery.support.scriptEval = true;
+               delete window[ id ];
+       }
+       root.removeChild( script );
+       if ( div.attachEvent && div.fireEvent ) {
+               div.attachEvent("onclick", function(){
+                       // Cloning a node shouldn't copy over any
+                       // bound event handlers (IE does this)
+                       jQuery.support.noCloneEvent = false;
+                       div.detachEvent("onclick", arguments.callee);
+               });
+               div.cloneNode(true).fireEvent("onclick");
+       }
+       // Figure out if the W3C box model works as expected
+       // document.body must exist before we can do this
+       jQuery(function(){
+               var div = document.createElement("div");
+               div.style.width = div.style.paddingLeft = "1px";
+               document.body.appendChild( div );
+               jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
+               document.body.removeChild( div ).style.display = 'none';
+       });
+})();
+var styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat";
+jQuery.props = {
+       "for": "htmlFor",
+       "class": "className",
+       "float": styleFloat,
+       cssFloat: styleFloat,
+       styleFloat: styleFloat,
+       readonly: "readOnly",
+       maxlength: "maxLength",
+       cellspacing: "cellSpacing",
+       rowspan: "rowSpan",
+       tabindex: "tabIndex"
+};
+jQuery.fn.extend({
+       // Keep a copy of the old load
+       _load: jQuery.fn.load,
+       load: function( url, params, callback ) {
+               if ( typeof url !== "string" )
+                       return this._load( url );
+               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 = null;
+                       // Otherwise, build a param string
+                       } else if( typeof params === "object" ) {
+                               params = jQuery.param( params );
+                               type = "POST";
+                       }
+               var self = this;
+               // Request the remote document
+               jQuery.ajax({
+                       url: url,
+                       type: type,
+                       dataType: "html",
+                       data: params,
+                       complete: function(res, status){
+                               // If successful, inject the HTML into all the matched elements
+                               if ( status == "success" || status == "notmodified" )
+                                       // 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(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
+                                                       // Locate the specified elements
+                                                       .find(selector) :
+                                               // If not, just inject the full result
+                                               res.responseText );
+                               if( callback )
+                                       self.each( callback, [res.responseText, status, res] );
+                       }
+               });
+               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 || /select|textarea/i.test(this.nodeName) ||
+                                       /text|hidden|password|search/i.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};
+                                       }) :
+                                       {name: elem.name, value: val};
+               }).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);
+       };
+});
+var jsc = now();
+jQuery.extend({
+       get: function( url, data, callback, type ) {
+               // shift arguments if data argument was ommited
+               if ( jQuery.isFunction( data ) ) {
+                       callback = data;
+                       data = null;
+               }
+               return jQuery.ajax({
+                       type: "GET",
+                       url: url,
+                       data: data,
+                       success: callback,
+                       dataType: type
+               });
+       },
+       getScript: function( url, callback ) {
+               return jQuery.get(url, null, callback, "script");
+       },
+       getJSON: function( url, data, callback ) {
+               return jQuery.get(url, data, callback, "json");
+       },
+       post: function( url, data, callback, type ) {
+               if ( jQuery.isFunction( data ) ) {
+                       callback = data;
+                       data = {};
+               }
+               return jQuery.ajax({
+                       type: "POST",
+                       url: url,
+                       data: data,
+                       success: callback,
+                       dataType: type
+               });
+       },
+       ajaxSetup: function( settings ) {
+               jQuery.extend( jQuery.ajaxSettings, settings );
+       },
+       ajaxSettings: {
+               url: location.href,
+               global: true,
+               type: "GET",
+               contentType: "application/x-www-form-urlencoded",
+               processData: true,
+               async: true,
+               /*
+               timeout: 0,
+               data: null,
+               username: null,
+               password: null,
+               */
+               // Create the request object; Microsoft failed to properly
+               // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+               // This function can be overriden by calling jQuery.ajaxSetup
+               xhr:function(){
+                       return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+               },
+               accepts: {
+                       xml: "application/xml, text/xml",
+                       html: "text/html",
+                       script: "text/javascript, application/javascript",
+                       json: "application/json, text/javascript",
+                       text: "text/plain",
+                       _default: "*/*"
+               }
+       },
+       // Last-Modified header cache for next request
+       lastModified: {},
+       ajax: function( s ) {
+               // Extend the settings, but re-extend 's' so that it can be
+               // checked again later (in the test suite, specifically)
+               s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+               var jsonp, jsre = /=\?(&|$)/g, status, data,
+                       type = s.type.toUpperCase();
+               // convert data if not already a string
+               if ( s.data && s.processData && typeof s.data !== "string" )
+                       s.data = jQuery.param(s.data);
+               // Handle JSONP Parameter Callbacks
+               if ( s.dataType == "jsonp" ) {
+                       if ( type == "GET" ) {
+                               if ( !s.url.match(jsre) )
+                                       s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+                       } else if ( !s.data || !s.data.match(jsre) )
+                               s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+                       s.dataType = "json";
+               }
+               // Build temporary JSONP function
+               if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
+                       jsonp = "jsonp" + jsc++;
+                       // Replace the =? sequence both in the query string and the data
+                       if ( s.data )
+                               s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+                       s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+                       // We need to make sure
+                       // that a JSONP style response is executed properly
+                       s.dataType = "script";
+                       // Handle JSONP-style loading
+                       window[ jsonp ] = function(tmp){
+                               data = tmp;
+                               success();
+                               complete();
+                               // Garbage collect
+                               window[ jsonp ] = undefined;
+                               try{ delete window[ jsonp ]; } catch(e){}
+                               if ( head )
+                                       head.removeChild( script );
+                       };
+               }
+               if ( s.dataType == "script" && s.cache == null )
+                       s.cache = false;
+               if ( s.cache === false && type == "GET" ) {
+                       var ts = now();
+                       // try replacing _= if it is there
+                       var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
+                       // if nothing was replaced, add timestamp to the end
+                       s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
+               }
+               // If data is available, append data to url for get requests
+               if ( s.data && type == "GET" ) {
+                       s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
+                       // IE likes to send both get and post data, prevent this
+                       s.data = null;
+               }
+               // Watch for a new set of requests
+               if ( s.global && ! jQuery.active++ )
+                       jQuery.event.trigger( "ajaxStart" );
+               // Matches an absolute URL, and saves the domain
+               var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec( s.url );
+               // If we're requesting a remote document
+               // and trying to load JSON or Script with a GET
+               if ( s.dataType == "script" && type == "GET" && parts
+                       && ( parts[1] && parts[1] != location.protocol || parts[2] != location.host )){
+                       var head = document.getElementsByTagName("head")[0];
+                       var script = document.createElement("script");
+                       script.src = s.url;
+                       if (s.scriptCharset)
+                               script.charset = s.scriptCharset;
+                       // Handle Script loading
+                       if ( !jsonp ) {
+                               var done = false;
+                               // Attach handlers for all browsers
+                               script.onload = script.onreadystatechange = function(){
+                                       if ( !done && (!this.readyState ||
+                                                       this.readyState == "loaded" || this.readyState == "complete") ) {
+                                               done = true;
+                                               success();
+                                               complete();
+                                               // Handle memory leak in IE
+                                               script.onload = script.onreadystatechange = null;
+                                               head.removeChild( script );
+                                       }
+                               };
+                       }
+                       head.appendChild(script);
+                       // We handle everything using the script element injection
+                       return undefined;
+               }
+               var requestDone = false;
+               // Create the request object
+               var xhr = s.xhr();
+               // Open the socket
+               // Passing null username, generates a login popup on Opera (#2865)
+               if( s.username )
+                       xhr.open(type, s.url, s.async, s.username, s.password);
+               else
+                       xhr.open(type, s.url, s.async);
+               // Need an extra try/catch for cross domain requests in Firefox 3
+               try {
+                       // Set the correct header, if data is being sent
+                       if ( s.data )
+                               xhr.setRequestHeader("Content-Type", s.contentType);
+                       // Set the If-Modified-Since header, if ifModified mode.
+                       if ( s.ifModified )
+                               xhr.setRequestHeader("If-Modified-Since",
+                                       jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+                       // Set header so the called script knows that it's an XMLHttpRequest
+                       xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+                       // Set the Accepts header for the server, depending on the dataType
+                       xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+                               s.accepts[ s.dataType ] + ", */*" :
+                               s.accepts._default );
+               } catch(e){}
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
+                       // Handle the global AJAX counter
+                       if ( s.global && ! --jQuery.active )
+                               jQuery.event.trigger( "ajaxStop" );
+                       // close opended socket
+                       xhr.abort();
+                       return false;
+               }
+               if ( s.global )
+                       jQuery.event.trigger("ajaxSend", [xhr, s]);
+               // Wait for a response to come back
+               var onreadystatechange = function(isTimeout){
+                       // The request was aborted, clear the interval and decrement jQuery.active
+                       if (xhr.readyState == 0) {
+                               if (ival) {
+                                       // clear poll interval
+                                       clearInterval(ival);
+                                       ival = null;
+                                       // Handle the global AJAX counter
+                                       if ( s.global && ! --jQuery.active )
+                                               jQuery.event.trigger( "ajaxStop" );
+                               }
+                       // The transfer is complete and the data is available, or the request timed out
+                       } else if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
+                               requestDone = true;
+                               // clear poll interval
+                               if (ival) {
+                                       clearInterval(ival);
+                                       ival = null;
+                               }
+                               status = isTimeout == "timeout" ? "timeout" :
+                                       !jQuery.httpSuccess( xhr ) ? "error" :
+                                       s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
+                                       "success";
+                               if ( status == "success" ) {
+                                       // Watch for, and catch, XML document parse errors
+                                       try {
+                                               // process the data (runs the xml through httpData regardless of callback)
+                                               data = jQuery.httpData( xhr, s.dataType, s );
+                                       } catch(e) {
+                                               status = "parsererror";
+                                       }
+                               }
+                               // Make sure that the request was successful or notmodified
+                               if ( status == "success" ) {
+                                       // Cache Last-Modified header, if ifModified mode.
+                                       var modRes;
+                                       try {
+                                               modRes = xhr.getResponseHeader("Last-Modified");
+                                       } catch(e) {} // swallow exception thrown by FF if header is not available
+                                       if ( s.ifModified && modRes )
+                                               jQuery.lastModified[s.url] = modRes;
+                                       // JSONP handles its own success callback
+                                       if ( !jsonp )
+                                               success();
+                               } else
+                                       jQuery.handleError(s, xhr, status);
+                               // Fire the complete handlers
+                               complete();
+                               if ( isTimeout )
+                                       xhr.abort();
+                               // Stop memory leaks
+                               if ( s.async )
+                                       xhr = null;
+                       }
+               };
+               if ( s.async ) {
+                       // don't attach the handler to the request, just poll it instead
+                       var ival = setInterval(onreadystatechange, 13);
+                       // Timeout checker
+                       if ( s.timeout > 0 )
+                               setTimeout(function(){
+                                       // Check to see if the request is still happening
+                                       if ( xhr && !requestDone )
+                                               onreadystatechange( "timeout" );
+                               }, s.timeout);
+               }
+               // Send the data
+               try {
+                       xhr.send(s.data);
+               } catch(e) {
+                       jQuery.handleError(s, xhr, null, e);
+               }
+               // firefox 1.5 doesn't fire statechange for sync requests
+               if ( !s.async )
+                       onreadystatechange();
+               function success(){
+                       // If a local callback was specified, fire it and pass it the data
+                       if ( s.success )
+                               s.success( data, status );
+                       // Fire the global callback
+                       if ( s.global )
+                               jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
+               }
+               function complete(){
+                       // Process result
+                       if ( s.complete )
+                               s.complete(xhr, status);
+                       // The request was completed
+                       if ( s.global )
+                               jQuery.event.trigger( "ajaxComplete", [xhr, s] );
+                       // Handle the global AJAX counter
+                       if ( s.global && ! --jQuery.active )
+                               jQuery.event.trigger( "ajaxStop" );
+               }
+               // return XMLHttpRequest to allow aborting the request etc.
+               return xhr;
+       },
+       handleError: function( s, xhr, status, e ) {
+               // If a local callback was specified, fire it
+               if ( s.error ) s.error( xhr, status, e );
+               // Fire the global callback
+               if ( s.global )
+                       jQuery.event.trigger( "ajaxError", [xhr, s, e] );
+       },
+       // Counter for holding the number of active queries
+       active: 0,
+       // Determines if an XMLHttpRequest was successful or not
+       httpSuccess: function( xhr ) {
+               try {
+                       // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+                       return !xhr.status && location.protocol == "file:" ||
+                               ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
+               } catch(e){}
+               return false;
+       },
+       // Determines if an XMLHttpRequest returns NotModified
+       httpNotModified: function( xhr, url ) {
+               try {
+                       var xhrRes = xhr.getResponseHeader("Last-Modified");
+                       // Firefox always returns 200. check Last-Modified date
+                       return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
+               } catch(e){}
+               return false;
+       },
+       httpData: function( xhr, type, s ) {
+               var ct = xhr.getResponseHeader("content-type"),
+                       xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
+                       data = xml ? xhr.responseXML : xhr.responseText;
+               if ( xml && data.documentElement.tagName == "parsererror" )
+                       throw "parsererror";
+               
+               // Allow a pre-filtering function to sanitize the response
+               // s != null is checked to keep backwards compatibility
+               if( s && s.dataFilter )
+                       data = s.dataFilter( data, type );
+               // The filter can actually parse the response
+               if( typeof data === "string" ){
+                       // If the type is "script", eval it in global context
+                       if ( type == "script" )
+                               jQuery.globalEval( data );
+                       // Get the JavaScript object, if JSON is used.
+                       if ( type == "json" )
+                               data = window["eval"]("(" + data + ")");
+               }
+       
+               return data;
+       },
+       // Serialize an array of form elements or a set of
+       // key/values into a query string
+       param: function( a ) {
+               var s = [ ];
+               function add( key, value ){
+                       s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
+               };
+               // If an array was passed in, assume that it is an array
+               // of form elements
+               if ( jQuery.isArray(a) || a.jquery )
+                       // Serialize the form elements
+                       jQuery.each( a, function(){
+                               add( this.name, this.value );
+                       });
+               // Otherwise, assume that it's an object of key/value pairs
+               else
+                       // Serialize the key/values
+                       for ( var j in a )
+                               // If the value is an array then the key names need to be repeated
+                               if ( jQuery.isArray(a[j]) )
+                                       jQuery.each( a[j], function(){
+                                               add( j, this );
+                                       });
+                               else
+                                       add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
+               // Return the resulting serialization
+               return s.join("&").replace(/%20/g, "+");
+       }
+});
+var elemdisplay = {},
+       timerId,
+       fxAttrs = [
+               // height animations
+               [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+               // width animations
+               [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+               // opacity animations
+               [ "opacity" ]
+       ];
+function genFx( type, num ){
+       var obj = {};
+       jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
+               obj[ this ] = type;
+       });
+       return obj;
+}
+jQuery.fn.extend({
+       show: function(speed,callback){
+               if ( speed ) {
+                       return this.animate( genFx("show", 3), speed, callback);
+               } else {
+                       for ( var i = 0, l = this.length; i < l; i++ ){
+                               var old = jQuery.data(this[i], "olddisplay");
+                       
+                               this[i].style.display = old || "";
+                       
+                               if ( jQuery.css(this[i], "display") === "none" ) {
+                                       var tagName = this[i].tagName, display;
+                               
+                                       if ( elemdisplay[ tagName ] ) {
+                                               display = elemdisplay[ tagName ];
+                                       } else {
+                                               var elem = jQuery("<" + tagName + " />").appendTo("body");
+                                       
+                                               display = elem.css("display");
+                                               if ( display === "none" )
+                                                       display = "block";
+                                       
+                                               elem.remove();
+                                       
+                                               elemdisplay[ tagName ] = display;
+                                       }
+                               
+                                       jQuery.data(this[i], "olddisplay", display);
+                               }
+                       }
+                       // Set the display of the elements in a second loop
+                       // to avoid the constant reflow
+                       for ( var i = 0, l = this.length; i < l; i++ ){
+                               this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
+                       }
+               
+                       return this;
+               }
+       },
+       hide: function(speed,callback){
+               if ( speed ) {
+                       return this.animate( genFx("hide", 3), speed, callback);
+               } else {
+                       for ( var i = 0, l = this.length; i < l; i++ ){
+                               var old = jQuery.data(this[i], "olddisplay");
+                               if ( !old && old !== "none" )
+                                       jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
+                       }
+                       // Set the display of the elements in a second loop
+                       // to avoid the constant reflow
+                       for ( var i = 0, l = this.length; i < l; i++ ){
+                               this[i].style.display = "none";
+                       }
+                       return this;
+               }
+       },
+       // Save the old toggle function
+       _toggle: jQuery.fn.toggle,
+       toggle: function( fn, fn2 ){
+               var bool = typeof fn === "boolean";
+               return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+                       this._toggle.apply( this, arguments ) :
+                       fn == null || bool ?
+                               this.each(function(){
+                                       var state = bool ? fn : jQuery(this).is(":hidden");
+                                       jQuery(this)[ state ? "show" : "hide" ]();
+                               }) :
+                               this.animate(genFx("toggle", 3), fn, fn2);
+       },
+       fadeTo: function(speed,to,callback){
+               return this.animate({opacity: to}, speed, callback);
+       },
+       animate: function( prop, speed, easing, callback ) {
+               var optall = jQuery.speed(speed, easing, callback);
+               return this[ optall.queue === false ? "each" : "queue" ](function(){
+       
+                       var opt = jQuery.extend({}, optall), p,
+                               hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
+                               self = this;
+
+                       for ( p in prop ) {
+                               if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+                                       return opt.complete.call(this);
+                               if ( ( p == "height" || p == "width" ) && this.style ) {
+                                       // Store display property
+                                       opt.display = jQuery.css(this, "display");
+                                       // Make sure that nothing sneaks out
+                                       opt.overflow = this.style.overflow;
+                               }
+                       }
+                       if ( opt.overflow != null )
+                               this.style.overflow = "hidden";
+                       opt.curAnim = jQuery.extend({}, prop);
+                       jQuery.each( prop, function(name, val){
+                               var e = new jQuery.fx( self, opt, name );
+                               if ( /toggle|show|hide/.test(val) )
+                                       e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+                               else {
+                                       var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
+                                               start = e.cur(true) || 0;
+                                       if ( parts ) {
+                                               var end = parseFloat(parts[2]),
+                                                       unit = parts[3] || "px";
+                                               // We need to compute starting value
+                                               if ( unit != "px" ) {
+                                                       self.style[ name ] = (end || 1) + unit;
+                                                       start = ((end || 1) / e.cur(true)) * start;
+                                                       self.style[ name ] = 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){
+               var timers = jQuery.timers;
+               if (clearQueue)
+                       this.queue([]);
+               this.each(function(){
+                       // go in reverse order so anything added to the queue during the loop is ignored
+                       for ( var i = timers.length - 1; i >= 0; 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;
+       }
+});
+// 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" }
+}, function( name, props ){
+       jQuery.fn[ name ] = function( speed, callback ){
+               return this.animate( props, speed, callback );
+       };
+});
+jQuery.extend({
+       speed: function(speed, easing, fn) {
+               var opt = typeof speed === "object" ? 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 :
+                       jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
+               // Queueing
+               opt.old = opt.complete;
+               opt.complete = function(){
+                       if ( opt.queue !== false )
+                               jQuery(this).dequeue();
+                       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;
+               if ( !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 );
+               // Set display property to block for height/width animations
+               if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style )
+                       this.elem.style.display = "block";
+       },
+       // Get the current size
+       cur: function(force){
+               if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) )
+                       return this.elem[ this.prop ];
+               var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+               return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+       },
+       // Start an animation from one number to another
+       custom: function(from, to, unit){
+               this.startTime = now();
+               this.start = from;
+               this.end = to;
+               this.unit = unit || this.unit || "px";
+               this.now = this.start;
+               this.pos = this.state = 0;
+               var self = this;
+               function t(gotoEnd){
+                       return self.step(gotoEnd);
+               }
+               t.elem = this.elem;
+               if ( t() && jQuery.timers.push(t) && !timerId ) {
+                       timerId = setInterval(function(){
+                               var timers = jQuery.timers;
+                               for ( var i = 0; i < timers.length; i++ )
+                                       if ( !timers[i]() )
+                                               timers.splice(i--, 1);
+                               if ( !timers.length ) {
+                                       clearInterval( timerId );
+                                       timerId = undefined;
+                               }
+                       }, 13);
+               }
+       },
+       // Simple 'show' function
+       show: function(){
+               // Remember where we started, so that we can go back to it later
+               this.options.orig[this.prop] = jQuery.attr( this.elem.style, 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.attr( this.elem.style, this.prop );
+               this.options.hide = true;
+               // Begin the animation
+               this.custom(this.cur(), 0);
+       },
+       // Each step of an animation
+       step: function(gotoEnd){
+               var t = now();
+               if ( gotoEnd || t >= this.options.duration + this.startTime ) {
+                       this.now = this.end;
+                       this.pos = this.state = 1;
+                       this.update();
+                       this.options.curAnim[ this.prop ] = true;
+                       var done = true;
+                       for ( var i in this.options.curAnim )
+                               if ( this.options.curAnim[i] !== true )
+                                       done = false;
+                       if ( done ) {
+                               if ( this.options.display != null ) {
+                                       // Reset the overflow
+                                       this.elem.style.overflow = this.options.overflow;
+                                       // Reset the display
+                                       this.elem.style.display = this.options.display;
+                                       if ( jQuery.css(this.elem, "display") == "none" )
+                                               this.elem.style.display = "block";
+                               }
+                               // Hide the element if the "hide" operation was done
+                               if ( this.options.hide )
+                                       jQuery(this.elem).hide();
+                               // Reset the properties, if the item has been hidden or shown
+                               if ( this.options.hide || this.options.show )
+                                       for ( var p in this.options.curAnim )
+                                               jQuery.attr(this.elem.style, p, this.options.orig[p]);
+                               
+                               // Execute the complete function
+                               this.options.complete.call( this.elem );
+                       }
+                       return false;
+               } else {
+                       var n = t - this.startTime;
+                       this.state = n / this.options.duration;
+                       // Perform the easing function, defaults to swing
+                       this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.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, {
+       speeds:{
+               slow: 600,
+               fast: 200,
+               // Default speed
+               _default: 400
+       },
+       step: {
+               opacity: function(fx){
+                       jQuery.attr(fx.elem.style, "opacity", fx.now);
+               },
+               _default: function(fx){
+                       if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
+                               fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+                       else
+                               fx.elem[ fx.prop ] = fx.now;
+               }
+       }
+});
+if ( document.documentElement["getBoundingClientRect"] )
+       jQuery.fn.offset = function() {
+               if ( !this[0] ) return { top: 0, left: 0 };
+               if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
+               var box  = this[0].getBoundingClientRect(), doc = this[0].ownerDocument, body = doc.body, docElem = doc.documentElement,
+                       clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+                       top  = box.top  + (self.pageYOffset || jQuery.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
+                       left = box.left + (self.pageXOffset || jQuery.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
+               return { top: top, left: left };
+       };
+else
+       jQuery.fn.offset = function() {
+               if ( !this[0] ) return { top: 0, left: 0 };
+               if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
+               jQuery.offset.initialized || jQuery.offset.initialize();
+               var elem = this[0], offsetParent = elem.offsetParent, prevOffsetParent = elem,
+                       doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
+                       body = doc.body, defaultView = doc.defaultView,
+                       prevComputedStyle = defaultView.getComputedStyle(elem, null),
+                       top = elem.offsetTop, left = elem.offsetLeft;
+               while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+                       computedStyle = defaultView.getComputedStyle(elem, null);
+                       top -= elem.scrollTop, left -= elem.scrollLeft;
+                       if ( elem === offsetParent ) {
+                               top += elem.offsetTop, left += elem.offsetLeft;
+                               if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName)) )
+                                       top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
+                                       left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
+                               prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
+                       }
+                       if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" )
+                               top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
+                               left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
+                       prevComputedStyle = computedStyle;
+               }
+               if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" )
+                       top  += body.offsetTop,
+                       left += body.offsetLeft;
+               if ( 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() {
+               if ( this.initialized ) return;
+               var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
+                       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>';
+               rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
+               for ( prop in rules ) container.style[prop] = rules[prop];
+               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);
+               innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
+               this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+               body.style.marginTop = '1px';
+               this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
+               body.style.marginTop = bodyMarginTop;
+               body.removeChild(container);
+               this.initialized = true;
+       },
+       bodyOffset: function(body) {
+               jQuery.offset.initialized || jQuery.offset.initialize();
+               var top = body.offsetTop, left = body.offsetLeft;
+               if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
+                       top  += parseInt( jQuery.curCSS(body, 'marginTop',  true), 10 ) || 0,
+                       left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) || 0;
+               return { top: top, left: left };
+       }
+};
+
+jQuery.fn.extend({
+       position: function() {
+               var left = 0, top = 0, results;
+               if ( this[0] ) {
+                       // Get *real* offsetParent
+                       var offsetParent = this.offsetParent(),
+                       // Get correct offsets
+                       offset     = this.offset(),
+                       parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { 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  -= num( this, 'marginTop'  );
+                       offset.left -= num( this, 'marginLeft' );
+                       // Add offsetParent borders
+                       parentOffset.top  += num( offsetParent, 'borderTopWidth'  );
+                       parentOffset.left += num( offsetParent, 'borderLeftWidth' );
+                       // Subtract the two offsets
+                       results = {
+                               top:  offset.top  - parentOffset.top,
+                               left: offset.left - parentOffset.left
+                       };
+               }
+               return results;
+       },
+       offsetParent: function() {
+               var offsetParent = this[0].offsetParent || document.body;
+               while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
+                       offsetParent = offsetParent.offsetParent;
+               return jQuery(offsetParent);
+       }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ['Left', 'Top'], function(i, name) {
+       var method = 'scroll' + name;
+
+       jQuery.fn[ method ] = function(val) {
+               if (!this[0]) return null;
+               return val !== undefined ?
+                       // Set the scroll offset
+                       this.each(function() {
+                               this == window || this == document ?
+                                       window.scrollTo(
+                                               !i ? val : jQuery(window).scrollLeft(),
+                                                i ? val : jQuery(window).scrollTop()
+                                       ) :
+                                       this[ method ] = val;
+                       }) :
+                       // Return the scroll offset
+                       this[0] == window || this[0] == document ?
+                               self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
+                                       jQuery.boxModel && document.documentElement[ method ] ||
+                                       document.body[ method ] :
+                               this[0][ method ];
+       };
+});
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function(i, name){
+       var tl = i ? "Left"  : "Top",  // top or left
+               br = i ? "Right" : "Bottom", // bottom or right
+               lower = name.toLowerCase();
+       // innerHeight and innerWidth
+       jQuery.fn["inner" + name] = function(){
+               return this[0] ?
+                       jQuery.css( this[0], lower, false, "padding" ) :
+                       null;
+       };
+       // outerHeight and outerWidth
+       jQuery.fn["outer" + name] = function(margin) {
+               return this[0] ?
+                       jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
+                       null;
+       };
+
+       var type = name.toLowerCase();
+       jQuery.fn[ type ] = function( size ) {
+               // Get window width or height
+               return this[0] == window ?
+                       // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+                       document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] ||
+                       document.body[ "client" + name ] :
+                       // Get document width or height
+                       this[0] == document ?
+                               // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+                               Math.max(
+                                       document.documentElement["client" + name],
+                                       document.body["scroll" + name], document.documentElement["scroll" + name],
+                                       document.body["offset" + name], document.documentElement["offset" + name]
+                               ) :
+                               // Get or set width or height on the element
+                               size === undefined ?
+                                       // Get width or height on the element
+                                       (this.length ? jQuery.css( this[0], type ) : null) :
+                                       // Set the width or height on the element (default to pixels if value is unitless)
+                                       this.css( type, typeof size === "string" ? size : size + "px" );
+       };
+});
+})();
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery-1.3.2.min.js b/js2/mwEmbed/jquery/jquery-1.3.2.min.js
new file mode 100644 (file)
index 0000000..b1ae21d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.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|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<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>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/AUTHORS.txt b/js2/mwEmbed/jquery/jquery.ui-1.7.1/AUTHORS.txt
new file mode 100644 (file)
index 0000000..637175b
--- /dev/null
@@ -0,0 +1,30 @@
+jQuery UI Authors (http://ui.jquery.com/about)
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+and logs, available at http://jquery-ui.googlecode.com/svn/
+
+Brandon Aaron
+Paul Bakaus (paulbakaus.com)
+David Bolter
+Rich Caloggero
+Chi Cheng (cloudream@gmail.com)
+Colin Clark (http://colin.atrc.utoronto.ca/)
+Michelle D'Souza
+Aaron Eisenberger (aaronchi@gmail.com)
+Ariel Flesler
+Bohdan Ganicky
+Scott González
+Marc Grabanski (m@marcgrabanski.com)
+Klaus Hartl (stilbuero.de)
+Scott Jehl
+Cody Lindley
+Eduardo Lundgren (eduardolundgren@gmail.com)
+Todd Parker
+John Resig
+Patty Toland
+Ca-Phun Ung (yelotofu.com)
+Keith Wood (kbwood@virginbroadband.com.au)
+Maggie Costello Wachs
+Richard D. Worth (rdworth.org)
+Jörn Zaefferer (bassistance.de)
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/GPL-LICENSE.txt b/js2/mwEmbed/jquery/jquery.ui-1.7.1/GPL-LICENSE.txt
new file mode 100644 (file)
index 0000000..11dddd0
--- /dev/null
@@ -0,0 +1,278 @@
+        GNU GENERAL PUBLIC LICENSE
+           Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+          Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+        GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+          NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/MIT-LICENSE.txt b/js2/mwEmbed/jquery/jquery.ui-1.7.1/MIT-LICENSE.txt
new file mode 100644 (file)
index 0000000..f0f2ba9
--- /dev/null
@@ -0,0 +1,25 @@
+Copyright (c) 2009 Paul Bakaus, http://jqueryui.com/
+
+This software consists of voluntary contributions made by many
+individuals (AUTHORS.txt, http://jqueryui.com/about) For exact
+contribution history, see the revision history and logs, available
+at http://jquery-ui.googlecode.com/svn/
+
+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.
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/ChangeLog.txt b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/ChangeLog.txt
new file mode 100644 (file)
index 0000000..995b351
--- /dev/null
@@ -0,0 +1,20 @@
+== New and Noteworthy ==
+
+== 2.1.1 ==
+
+* Removed $.browser.version for jQuery < 1.1.3
+
+== 2.1 ==
+
+* Updated to work with jQuery 1.1.3
+* Added $.browser.version for jQuery < 1.1.3
+* Optimized duplication check by using child selector and using .length test
+
+== 2.0 ==
+
+* Added ability change settings like width, height, src and more.
+
+== 1.0 ==
+
+* Only adds iframe once per an element
+* Works with SSL enabled pages
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/META.json b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/META.json
new file mode 100644 (file)
index 0000000..766190b
--- /dev/null
@@ -0,0 +1,32 @@
+{
+       "name": "jQuery-bgiframe",
+       "version": 2.1,
+       "author": [
+               "Brandon Aaron <brandon.aaron@gmail.com>"
+       ],
+       "abstract": "jQuery plugin for fixing z-index issues in IE6",
+       "license": "mit, gpl",
+       "distribution_type": "plugin",
+       "requires": {
+               "jQuery": ">=1.0.3"
+       },
+       "provides": {
+               "jQuery.bgiframe": {
+                       "version": 2.1,
+                       "file": "jquery.bgiframe.js"
+               }
+       },
+       "keywords": [
+               "iframe",
+               "hack",
+               "zIndex",
+               "z-index",
+               "ie6"
+       ],
+       "stability": "Official",
+       "meta-spec": {
+               "version": 1.3,
+               "url": "http://module-build.sourceforge.net/META-spec-v1.3.html"
+       },
+       "generated_by": "Brandon Aaron"
+}
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/docs/index.html b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/docs/index.html
new file mode 100644 (file)
index 0000000..1776b4d
--- /dev/null
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+       "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+       <head>
+               <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+               <title>bgiframe 2.1.1 docs</title>
+               <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.2.2/build/reset/reset-min.css">
+               <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.2.2/build/fonts/fonts-min.css">
+               <style type="text/css" media="screen">
+                       body { margin: 25px; }
+                       h1 { margin: 1.0em 0; font-size: 167%; font-weight: bold; }
+                       #toc { margin: 0 0 3.0em; }
+                               #toc li { margin: 0.4em 0; font-size: 100%; }
+                       #qa { margin: 0 0 3.0em; }
+                               #qa dt.question { margin: 2.0em 0 1.0em; font-size: 122%; font-weight: bold; }
+                               #qa dd.answer { margin: 0 2.0em; }
+                                       #qa dd.answer p { margin: 0 0 1.5em; }
+                                       #qa dd.answer code { font-size: 92%; }
+                                       
+                                       #qa dd.answer #options dt { margin: 2.0em 0 1.0em;  }
+                                       #qa dd.answer #options dd { margin: 0 2.0em; }
+                                       
+               </style>
+       </head>
+       <body>
+               <div id="wrapper">
+                       <div id="container">
+                               <h1>bgiframe 2.1.1</h1>
+                               <ul id="toc">
+                                       <li><a href="#what_does_it_do">What does it do</a></li>
+                                       <li><a href="#when_should_i_use_it">When should I use it</a></li>
+                                       <li><a href="#how_do_i_use_it">How do I use it</a></li>
+                                       <li><a href="#how_does_it_work">How does it work</a></li>
+                                       <li><a href="#where_can_i_get_it">Where can I get it</a></li>
+                                       <li><a href="#what_has_changed">What has changed</a></li>
+                                       <li><a href="#suggestions_bugs_patches">Suggestions? Bugs? Patches?</a></li>
+                               </ul>
+                               <dl id="qa">
+                                       <dt id="what_does_it_do" class="question">What does it do?</dt>
+                                       <dd class="answer">
+                                               <p>Have you ever experienced the select form element z-index issue in Internet Explorer 6? Most likely you have if you've implemented some sort of drop down menu navigation that shows up over a select form element.</p>
+                                               <p>The background iframe (bgiframe) plugin provides a very small, quick and easy way to fix that problem so you don't have to worry about it. No matter the size, borders or position the bgiframe plugin can fix it.</p>
+                                       </dd>
+                                       
+                                       <dt id="when_should_i_use_it" class="question">When should I use it?</dt>
+                                       <dd class="answer">
+                                               <p>The bgiframe plugin should be used when you are trying to show elements above a select form control in Internet Explorer 6.</p>
+                                       </dd>
+                                       
+                                       <dt id="how_do_i_use_it" class="question">How do I use it?</dt>
+                                       <dd class="answer">
+                                               <p>The usage is simple. Just call <code>bgiframe</code> on a jQuery collection of elements.</p>
+                                               <p><code>$('.fix-z-index').bgiframe();</code></p>
+                                               <p>The plugin tries its best to handle most situations but sometimes some configuration is necessary. For example if your borders are defined in a unit other than pixels, you will need to manually set the <code>top</code> and <code>left</code> properties to the negative width of the border. Here are the options/settings available to configure the output.</p>
+                                               <dl id="options">
+                                                       <dt><code>top</code></dt>
+                                                       <dd>
+                                                               <p>The iframe must be offset to the top by the width of the top border. This should be a negative number representing the border-top-width. If a number is is used here, pixels will be assumed. Otherwise, be sure to specify a unit. An expression could also be used. By default the value is "auto" which will use an expression to get the border-top-width if it is in pixels.</p>
+                                                               <p><code>$('.fix-z-index').bgiframe({ top: '-1em' });</code></p>
+                                                       </dd>
+                                                       <dt><code>left</code></dt>
+                                                       <dd>
+                                                               <p>The iframe must be offset to the left by the width of the left border. This should be a negative number representing the border-left-width. If a number is used here, pixels will be assumed. Otherwise, be sure to specify a unit. An expression could also be used. By default the value is "auto" which will use an expression to get the border-left-width if it is in pixels.</p>
+                                                               <p><code>$('.fix-z-index').bgiframe({ left: '-1em' });</code></p>
+                                                       </dd>
+                                                       <dt><code>width</code></dt>
+                                                       <dd>
+                                                               <p>This is the width of the iframe. If a number is used here, pixels will be assume. Otherwise, be sure to specify a unit. An expression could also be used. By default the value is "auto" which will use an expression to get the offsetWidth.</p>
+                                                               <p><code>$('.fix-z-index').bgiframe({ width: 100 });</code></p>
+                                                       </dd>
+                                                       <dt><code>height</code></dt>
+                                                       <dd>
+                                                               <p>This is the height of the iframe. If a number is used here, pixels will be assume. Otherwise, be sure to specify a unit. An expression could also be used. By default the value is "auto" which will use an expression to get the offsetHeight.</p>
+                                                               <p><code>$('.fix-z-index').bgiframe({ height: 100 });</code></p>
+                                                       </dd>
+                                                       <dt><code>opacity</code></dt>
+                                                       <dd>
+                                                               <p>This is a boolean representing whether or not to use opacity. If set to true, the opacity of 0 is applied. If set to false, the opacity filter is not applied. Default: true.</p>
+                                                               <p><code>$('.fix-z-index').bgiframe({ opacity: false });</code></p>
+                                                       </dd>
+                                                       <dt><code>src</code></dt>
+                                                       <dd>
+                                                               <p>This setting is provided so that one could change the src of the iframe to whatever they need. Default: "javascript:false;"</p>
+                                                               <p><code>$('.fix-z-index').bgiframe({ src: '#' });</code></p>
+                                                       </dd>
+                                               </dl>
+                                       </dd>
+
+                                       <dt id="how_does_it_work" class="question">How does it work?</dt>
+                                       <dd class="answer">
+                                               <p>The bgiframe plugin works by prepending an iframe to the element. The iframe is given a class of bgiframe and positioned below all the other children of the element. In the default configuration it automatically adjusts to the width and height of the element (including the borders) and the opacity is set to 0. The element needs to have position (relative or absolute) and should have a background (color or image).</p>
+                                               <p>Check out the <a href="http://brandonaaron.net/jquery/plugins/bgiframe/test/">test page</a> to see the plugin in action.</p>
+                                       </dd>
+
+                                       <dt id="where_can_i_get_it" class="question">Where can I get it?</dt>
+                                       <dd class="answer">
+                                               <ul>
+                                                       <li><a href="http://jquery.com/plugins/files/bgiframe-2.1.zip">2.1 zip</a> from the bgiframe <a href="http://jquery.com/plugins/project/bgiframe">project page</a>.</li>
+                                                       <li>Latest SVN: http://jqueryjs.googlecode.com/svn/trunk/plugins/bgiframe/</li>
+                                                       <li>Tagged Versions in SVN: Latest SVN: http://jqueryjs.googlecode.com/svn/tags/plugins/bgiframe/</li>
+                                               </ul>
+                                       </dd>
+                                       
+                                       <dt id="suggestions_bugs_patches" class="question">Suggestions? Bugs? Patches?</dt>
+                                       <dd class="answer">
+                                               <p>Feel free to make any suggestions, bug reports or add any patches via the <a href="http://jquery.com/plugins/project/bgiframe">project page</a>.</p>
+                                       </dd>
+                               </dl>
+                               <p>The bgiframe plugin is authored by <a href="http://blog.brandonaaron.net/">Brandon Aaron (http://brandonaaron.net/)</a></p>
+                       </div>
+               </div>
+       </body>
+</html>
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.js
new file mode 100644 (file)
index 0000000..df52f50
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-07-21 18:44:59 -0500 (Sat, 21 Jul 2007) $
+ * $Rev: 2446 $
+ *
+ * Version 2.1.1
+ */
+
+(function($){
+
+/**
+ * The bgiframe is chainable and applies the iframe hack to get 
+ * around zIndex issues in IE6. It will only apply itself in IE6 
+ * and adds a class to the iframe called 'bgiframe'. The iframe
+ * is appeneded as the first child of the matched element(s) 
+ * with a tabIndex and zIndex of -1.
+ * 
+ * By default the plugin will take borders, sized with pixel units,
+ * into account. If a different unit is used for the border's width,
+ * then you will need to use the top and left settings as explained below.
+ *
+ * NOTICE: This plugin has been reported to cause perfromance problems
+ * when used on elements that change properties (like width, height and
+ * opacity) a lot in IE6. Most of these problems have been caused by 
+ * the expressions used to calculate the elements width, height and 
+ * borders. Some have reported it is due to the opacity filter. All 
+ * these settings can be changed if needed as explained below.
+ *
+ * @example $('div').bgiframe();
+ * @before <div><p>Paragraph</p></div>
+ * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
+ *
+ * @param Map settings Optional settings to configure the iframe.
+ * @option String|Number top The iframe must be offset to the top
+ *             by the width of the top border. This should be a negative 
+ *       number representing the border-top-width. If a number is 
+ *             is used here, pixels will be assumed. Otherwise, be sure
+ *             to specify a unit. An expression could also be used. 
+ *             By default the value is "auto" which will use an expression 
+ *             to get the border-top-width if it is in pixels.
+ * @option String|Number left The iframe must be offset to the left
+ *             by the width of the left border. This should be a negative 
+ *       number representing the border-left-width. If a number is 
+ *             is used here, pixels will be assumed. Otherwise, be sure
+ *             to specify a unit. An expression could also be used. 
+ *             By default the value is "auto" which will use an expression 
+ *             to get the border-left-width if it is in pixels.
+ * @option String|Number width This is the width of the iframe. If
+ *             a number is used here, pixels will be assume. Otherwise, be sure
+ *             to specify a unit. An experssion could also be used.
+ *             By default the value is "auto" which will use an experssion
+ *             to get the offsetWidth.
+ * @option String|Number height This is the height of the iframe. If
+ *             a number is used here, pixels will be assume. Otherwise, be sure
+ *             to specify a unit. An experssion could also be used.
+ *             By default the value is "auto" which will use an experssion
+ *             to get the offsetHeight.
+ * @option Boolean opacity This is a boolean representing whether or not
+ *             to use opacity. If set to true, the opacity of 0 is applied. If
+ *             set to false, the opacity filter is not applied. Default: true.
+ * @option String src This setting is provided so that one could change 
+ *             the src of the iframe to whatever they need.
+ *             Default: "javascript:false;"
+ *
+ * @name bgiframe
+ * @type jQuery
+ * @cat Plugins/bgiframe
+ * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ */
+$.fn.bgIframe = $.fn.bgiframe = function(s) {
+       // This is only for IE6
+       if ( $.browser.msie && /6.0/.test(navigator.userAgent) ) {
+               s = $.extend({
+                       top      : 'auto', // auto == .currentStyle.borderTopWidth
+                       left    : 'auto', // auto == .currentStyle.borderLeftWidth
+                       width   : 'auto', // auto == offsetWidth
+                       height  : 'auto', // auto == offsetHeight
+                       opacity : true,
+                       src     : 'javascript:false;'
+               }, s || {});
+               var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
+                   html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
+                              'style="display:block;position:absolute;z-index:-1;'+
+                                      (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
+                                              'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
+                                              'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
+                                              'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
+                                              'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
+                                       '"/>';
+               return this.each(function() {
+                       if ( $('> iframe.bgiframe', this).length == 0 )
+                               this.insertBefore( document.createElement(html), this.firstChild );
+               });
+       }
+       return this;
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.min.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.min.js
new file mode 100644 (file)
index 0000000..ef8679d
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-07-21 18:45:56 -0500 (Sat, 21 Jul 2007) $
+ * $Rev: 2447 $
+ *
+ * Version 2.1.1
+ */
+(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.pack.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/jquery.bgiframe.pack.js
new file mode 100644 (file)
index 0000000..90dee9a
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-07-21 18:44:59 -0500 (Sat, 21 Jul 2007) $
+ * $Rev: 2446 $
+ *
+ * Version 2.1.1
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(b($){$.m.E=$.m.g=b(s){h($.x.10&&/6.0/.I(D.B)){s=$.w({c:\'3\',5:\'3\',8:\'3\',d:\'3\',k:M,e:\'F:i;\'},s||{});C a=b(n){f n&&n.t==r?n+\'4\':n},p=\'<o Y="g"W="0"R="-1"e="\'+s.e+\'"\'+\'Q="P:O;N:L;z-H:-1;\'+(s.k!==i?\'G:J(K=\\\'0\\\');\':\'\')+\'c:\'+(s.c==\'3\'?\'7(((l(2.9.j.A)||0)*-1)+\\\'4\\\')\':a(s.c))+\';\'+\'5:\'+(s.5==\'3\'?\'7(((l(2.9.j.y)||0)*-1)+\\\'4\\\')\':a(s.5))+\';\'+\'8:\'+(s.8==\'3\'?\'7(2.9.S+\\\'4\\\')\':a(s.8))+\';\'+\'d:\'+(s.d==\'3\'?\'7(2.9.v+\\\'4\\\')\':a(s.d))+\';\'+\'"/>\';f 2.T(b(){h($(\'> o.g\',2).U==0)2.V(q.X(p),2.u)})}f 2}})(Z);',62,63,'||this|auto|px|left||expression|width|parentNode||function|top|height|src|return|bgiframe|if|false|currentStyle|opacity|parseInt|fn||iframe|html|document|Number||constructor|firstChild|offsetHeight|extend|browser|borderLeftWidth||borderTopWidth|userAgent|var|navigator|bgIframe|javascript|filter|index|test|Alpha|Opacity|absolute|true|position|block|display|style|tabindex|offsetWidth|each|length|insertBefore|frameborder|createElement|class|jQuery|msie'.split('|'),0,{}))
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/test/index.html b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/bgiframe/test/index.html
new file mode 100644 (file)
index 0000000..82be8e8
--- /dev/null
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+       "http://www.w3.org/TR/html4/strict.dtd">
+<html debug="true">
+       <head>
+               <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+               <title>jQuery bgiframe Visual Test</title>
+               
+               <!-- load latest build of jquery.js -->
+               <script type="text/javascript" src="../../../jquery/dist/jquery.js"></script>
+
+               <!-- load dimensions.js (this is what we're testing! -->
+               <script type="text/javascript" src="../jquery.bgiframe.js"></script>
+               
+               <!-- load firebug lite 
+               <script type="text/javascript" src="http://brandon.jquery.com/firebuglite/firebug.js"></script>-->
+               
+               <link rel="Stylesheet" media="screen" href="../../../jquery/test/data/testsuite.css" />
+               
+               <script type="text/javascript" charset="utf-8">
+                       $(function() {
+                               $('#userAgent').html(navigator.userAgent);
+                               $('#box2').bgiframe();
+                               $('#box3').bgiframe({top: -5, left: -5});
+                               $('#box4').bgiframe({top: -5, left: -5, width: 270, height: 120});
+                               $('#box5').bgiframe({top: 0, left: 0, width: 260, height: 110});
+                               $('#box6').bgiframe({top: '-5px', left: '-5px', width: '270px', height: '120px'});
+                               $('#box7').bgiframe({top: '-.5em', left: '-.5em', width: '17em', height: '12em'});
+                               $('#box8').bgiframe({top: '-.5em', left: '-.5em'});
+                               $('#box9').bgiframe({opacity:false});
+                       });
+               </script>
+               
+               <style type="text/css" media="screen">
+                       #wrapper { position: relative; width: 100%; font: 12px Arial; }
+                               form { position: absolute; top: 0; left: 0; width: 100%; }
+                                       select { position: relative; width: 100%; margin: 0 0 2px; z-index: 1; }
+                               
+                               .box { position: relative; z-index: 2; float: left; margin: 5px; border: 5px solid #666; padding: 5px; width: 250px; height: 100px; color: #000; background-color: #999; }
+                                       dl { margin: 0; padding: 0; }
+                                               dt { float: left; margin: 0; padding: 0; width: 50px; }
+                                               dd { margin: 0; padding: 0; }
+                               #box7, #box8 { border-width: .5em; padding: .5em; width: 15em; height: 10em; }
+               </style>
+       </head>
+       <body>
+               <h1 id="banner">jQuery bgiframe - Visual Test</h1>
+               <h2 id="userAgent"></h2>
+               <div id="wrapper">
+                       <form action="#" method="get" accept-charset="utf-8">
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                               <select name="test"><option>Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing Testing</option></select>
+                       </form>
+                       
+                       <div id="box1" class="box">nothing</div>
+                       <div id="box2" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>'auto'</dd>
+                               </dl>
+                       </div>
+                       <div id="box3" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>0</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>0</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>'auto'</dd>
+                               </dl>
+                       </div>
+                       <div id="box4" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>-5</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>-5</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>270</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>120</dd>
+                               </dl>
+                       </div>
+                       <div id="box5" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>0</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>0</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>260</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>110</dd>
+                               </dl>
+                       </div>
+                       <div id="box6" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>'-5px'</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>'-5px'</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>'270px'</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>'120px'</dd>
+                               </dl>
+                       </div>
+                       <div id="box7" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>'-.5em'</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>'-.5em'</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>'17em'</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>'12em'</dd>
+                               </dl>
+                       </div>
+                       <div id="box8" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>'-.5em'</dd>
+
+                                       <dt>left:</dt>
+                                       <dd>'-.5em'</dd>
+
+                                       <dt>width:</dt>
+                                       <dd>'auto'</dd>
+
+                                       <dt>height:</dt>
+                                       <dd>'auto'</dd>
+                               </dl>
+                       </div>
+                       <div id="box9" class="box">
+                               <dl>
+                                       <dt>top:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>left:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>width:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>height:</dt>
+                                       <dd>'auto'</dd>
+                                       
+                                       <dt>opacity:</dt>
+                                       <dd>false</dd>
+                               </dl>
+                       </div>
+               </div>
+       </body>
+</html>
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.min.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.min.js
new file mode 100644 (file)
index 0000000..cb09af9
--- /dev/null
@@ -0,0 +1,10 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options=$.extend({},options);options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}return cookieValue;}};
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.pack.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.pack.js
new file mode 100644 (file)
index 0000000..adf66b7
--- /dev/null
@@ -0,0 +1,10 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('q.5=x(k,d,a){4(m d!=\'H\'){a=a||{};4(d===p){d=\'\';a=$.A({},a);a.3=-1}2 g=\'\';4(a.3&&(m a.3==\'u\'||a.3.s)){2 f;4(m a.3==\'u\'){f=F C();f.B(f.z()+(a.3*y*o*o*v))}n{f=a.3}g=\'; 3=\'+f.s()}2 b=a.7?\'; 7=\'+(a.7):\'\';2 e=a.9?\'; 9=\'+(a.9):\'\';2 l=a.t?\'; t\':\'\';6.5=[k,\'=\',L(d),g,b,e,l].K(\'\')}n{2 h=p;4(6.5&&6.5!=\'\'){2 c=6.5.E(\';\');D(2 i=0;i<c.8;i++){2 j=q.G(c[i]);4(j.r(0,k.8+1)==(k+\'=\')){h=I(j.r(k.8+1));J}}}w h}};',48,48,'||var|expires|if|cookie|document|path|length|domain|||||||||||||typeof|else|60|null|jQuery|substring|toUTCString|secure|number|1000|return|function|24|getTime|extend|setTime|Date|for|split|new|trim|undefined|decodeURIComponent|break|join|encodeURIComponent'.split('|'),0,{}))
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.zip b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.zip
new file mode 100644 (file)
index 0000000..90f540b
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/cookie/jquery.cookie.zip differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/jsdiff/jsdiff.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/jsdiff/jsdiff.js
new file mode 100644 (file)
index 0000000..cc3a998
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Javascript Diff Algorithm
+ *  By John Resig (http://ejohn.org/)
+ *  Modified by Chu Alan "sprite"
+ *
+ * More Info:
+ *  http://ejohn.org/projects/javascript-diff-algorithm/
+ */
+
+function escape(s) {
+       var n = s;
+       n = n.replace(/&/g, "&amp;");
+       n = n.replace(/</g, "&lt;");
+       n = n.replace(/>/g, "&gt;");
+       n = n.replace(/"/g, "&quot;");
+
+       return n;
+}
+
+function diffString( o, n ) {
+  o = o.replace(/\s+$/, '');
+  n = n.replace(/\s+$/, '');
+
+  var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
+  var str = "";
+
+  var oSpace = o.match(/\s+/g);
+  if (oSpace == null) {
+       oSpace = ["\n"];
+  } else {
+       oSpace.push("\n");
+  }
+  var nSpace = n.match(/\s+/g);
+  if (nSpace == null) {
+       nSpace = ["\n"];
+  } else {
+       nSpace.push("\n");
+  }
+
+  if (out.n.length == 0) {
+         for (var i = 0; i < out.o.length; i++) {
+               str += '<del>' + escape(out.o[i]) + oSpace[i] + "</del>";
+         }
+  } else {
+       if (out.n[0].text == null) {
+         for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
+               str += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
+         }
+       }
+
+       for ( var i = 0; i < out.n.length; i++ ) {
+         if (out.n[i].text == null) {
+               str += '<ins>' + escape(out.n[i]) + nSpace[i] + "</ins>";
+         } else {
+               var pre = "";
+
+               for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
+                 pre += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
+               }
+               str += " " + out.n[i].text + nSpace[i] + pre;
+         }
+       }
+  }
+  
+  return str;
+}
+
+function randomColor() {
+       return "rgb(" + (Math.random() * 100) + "%, " + 
+                                       (Math.random() * 100) + "%, " + 
+                                       (Math.random() * 100) + "%)";
+}
+function diffString2( o, n ) {
+  o = o.replace(/\s+$/, '');
+  n = n.replace(/\s+$/, '');
+
+  var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
+
+  var oSpace = o.match(/\s+/g);
+  if (oSpace == null) {
+       oSpace = ["\n"];
+  } else {
+       oSpace.push("\n");
+  }
+  var nSpace = n.match(/\s+/g);
+  if (nSpace == null) {
+       nSpace = ["\n"];
+  } else {
+       nSpace.push("\n");
+  }
+
+  var os = "";
+  var colors = new Array();
+  for (var i = 0; i < out.o.length; i++) {
+         colors[i] = randomColor();
+
+         if (out.o[i].text != null) {
+                 os += '<span style="background-color: ' +colors[i]+ '">' + 
+                               escape(out.o[i].text) + oSpace[i] + "</span>";
+         } else {
+                 os += "<del>" + escape(out.o[i]) + oSpace[i] + "</del>";
+         }
+  }
+
+  var ns = "";
+  for (var i = 0; i < out.n.length; i++) {
+         if (out.n[i].text != null) {
+                 ns += '<span style="background-color: ' +colors[out.n[i].row]+ '">' + 
+                               escape(out.n[i].text) + nSpace[i] + "</span>";
+         } else {
+                 ns += "<ins>" + escape(out.n[i]) + nSpace[i] + "</ins>";
+         }
+  }
+
+  return { o : os , n : ns };
+}
+
+function diff( o, n ) {
+  var ns = new Object();
+  var os = new Object();
+  
+  for ( var i = 0; i < n.length; i++ ) {
+       if ( ns[ n[i] ] == null )
+         ns[ n[i] ] = { rows: new Array(), o: null };
+       ns[ n[i] ].rows.push( i );
+  }
+  
+  for ( var i = 0; i < o.length; i++ ) {
+       if ( os[ o[i] ] == null )
+         os[ o[i] ] = { rows: new Array(), n: null };
+       os[ o[i] ].rows.push( i );
+  }
+  
+  for ( var i in ns ) {
+       if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) {
+         n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] };
+         o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] };
+       }
+  }
+  
+  for ( var i = 0; i < n.length - 1; i++ ) {
+       if ( n[i].text != null && n[i+1].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && 
+                n[i+1] == o[ n[i].row + 1 ] ) {
+         n[i+1] = { text: n[i+1], row: n[i].row + 1 };
+         o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 };
+       }
+  }
+  
+  for ( var i = n.length - 1; i > 0; i-- ) {
+       if ( n[i].text != null && n[i-1].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && 
+                n[i-1] == o[ n[i].row - 1 ] ) {
+         n[i-1] = { text: n[i-1], row: n[i].row - 1 };
+         o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 };
+       }
+  }
+  
+  return { o: o, n: n };
+}
+
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/qunit/testrunner.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/qunit/testrunner.js
new file mode 100644 (file)
index 0000000..4a408d3
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * QUnit - jQuery unit testrunner
+ * 
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2008 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Id: testrunner.js 6173 2009-02-02 20:09:32Z jeresig $
+ */
+
+(function($) {
+
+// Tests for equality any JavaScript type and structure without unexpected results.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+var equiv = function () {
+
+       var innerEquiv; // the real equiv function
+       var callers = []; // stack to decide between skip/abort functions
+
+       // Determine what is o.
+       function hoozit(o) {
+               if (typeof o === "string") {
+                       return "string";
+
+               } else if (typeof o === "boolean") {
+                       return "boolean";
+
+               } else if (typeof o === "number") {
+
+                       if (isNaN(o)) {
+                               return "nan";
+                       } else {
+                               return "number";
+                       }
+
+               } else if (typeof o === "undefined") {
+                       return "undefined";
+
+               // consider: typeof null === object
+               } else if (o === null) {
+                       return "null";
+
+               // consider: typeof [] === object
+               } else if (o instanceof Array) {
+                       return "array";
+               
+               // consider: typeof new Date() === object
+               } else if (o instanceof Date) {
+                       return "date";
+
+               // consider: /./ instanceof Object;
+               //                 /./ instanceof RegExp;
+               //                typeof /./ === "function"; // => false in IE and Opera,
+               //                                                                                true in FF and Safari
+               } else if (o instanceof RegExp) {
+                       return "regexp";
+
+               } else if (typeof o === "object") {
+                       return "object";
+
+               } else if (o instanceof Function) {
+                       return "function";
+               }
+       }
+
+       // Call the o related callback with the given arguments.
+       function bindCallbacks(o, callbacks, args) {
+               var prop = hoozit(o);
+               if (prop) {
+                       if (hoozit(callbacks[prop]) === "function") {
+                               return callbacks[prop].apply(callbacks, args);
+                       } else {
+                               return callbacks[prop]; // or undefined
+                       }
+               }
+       }
+
+       var callbacks = function () {
+
+               // for string, boolean, number and null
+               function useStrictEquality(b, a) {
+                       return a === b;
+               }
+
+               return {
+                       "string": useStrictEquality,
+                       "boolean": useStrictEquality,
+                       "number": useStrictEquality,
+                       "null": useStrictEquality,
+                       "undefined": useStrictEquality,
+
+                       "nan": function (b) {
+                               return isNaN(b);
+                       },
+
+                       "date": function (b, a) {
+                               return hoozit(b) === "date" && a.valueOf() === b.valueOf();
+                       },
+
+                       "regexp": function (b, a) {
+                               return hoozit(b) === "regexp" &&
+                                       a.source === b.source && // the regex itself
+                                       a.global === b.global && // and its modifers (gmi) ...
+                                       a.ignoreCase === b.ignoreCase &&
+                                       a.multiline === b.multiline;
+                       },
+
+                       // - skip when the property is a method of an instance (OOP)
+                       // - abort otherwise,
+                       //   initial === would have catch identical references anyway
+                       "function": function () {
+                               var caller = callers[callers.length - 1];
+                               return caller !== Object &&
+                                               typeof caller !== "undefined";
+                       },
+
+                       "array": function (b, a) {
+                               var i;
+                               var len;
+
+                               // b could be an object literal here
+                               if ( ! (hoozit(b) === "array")) {
+                                       return false;
+                               }
+
+                               len = a.length;
+                               if (len !== b.length) { // safe and faster
+                                       return false;
+                               }
+                               for (i = 0; i < len; i++) {
+                                       if( ! innerEquiv(a[i], b[i])) {
+                                               return false;
+                                       }
+                               }
+                               return true;
+                       },
+
+                       "object": function (b, a) {
+                               var i;
+                               var eq = true; // unless we can proove it
+                               var aProperties = [], bProperties = []; // collection of strings
+
+                               // comparing constructors is more strict than using instanceof
+                               if ( a.constructor !== b.constructor) {
+                                       return false;
+                               }
+
+                               // stack constructor before traversing properties
+                               callers.push(a.constructor);
+
+                               for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
+
+                                       aProperties.push(i); // collect a's properties
+
+                                       if ( ! innerEquiv(a[i], b[i])) {
+                                               eq = false;
+                                       }
+                               }
+
+                               callers.pop(); // unstack, we are done
+
+                               for (i in b) {
+                                       bProperties.push(i); // collect b's properties
+                               }
+
+                               // Ensures identical properties name
+                               return eq && innerEquiv(aProperties.sort(), bProperties.sort());
+                       }
+               };
+       }();
+
+       innerEquiv = function () { // can take multiple arguments
+               var args = Array.prototype.slice.apply(arguments);
+               if (args.length < 2) {
+                       return true; // end transition
+               }
+
+               return (function (a, b) {
+                       if (a === b) {
+                               return true; // catch the most you can
+
+                       } else if (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") {
+                               return false; // don't lose time with error prone cases
+
+                       } else {
+                               return bindCallbacks(a, callbacks, [b, a]);
+                       }
+
+               // apply transition with (1..n) arguments
+               })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
+       };
+
+       return innerEquiv;
+}(); // equiv
+
+var GETParams = $.map( location.search.slice(1).split('&'), decodeURIComponent ),
+       ngindex = $.inArray("noglobals", GETParams),
+       noglobals = ngindex !== -1;
+
+if( noglobals )
+       GETParams.splice( ngindex, 1 );
+       
+var config = {
+       stats: {
+               all: 0,
+               bad: 0
+       },
+       queue: [],
+       // block until document ready
+       blocking: true,
+       //restrict modules/tests by get parameters
+       filters: GETParams,
+       isLocal: !!(window.location.protocol == 'file:')
+};
+
+// public API as global methods
+$.extend(window, {
+       test: test,
+       module: module,
+       expect: expect,
+       ok: ok,
+       equals: equals,
+       start: start,
+       stop: stop,
+       reset: reset,
+       isLocal: config.isLocal,
+       same: function(a, b, message) {
+               push(equiv(a, b), a, b, message);
+       },
+       QUnit: {
+               equiv: equiv,
+               ok: ok,
+               done: function(failures, total){},
+               log: function(result, message){}
+       },
+       // legacy methods below
+       isSet: isSet,
+       isObj: isObj,
+       compare: function() {
+               throw "compare is deprecated - use same() instead";
+       },
+       compare2: function() {
+               throw "compare2 is deprecated - use same() instead";
+       },
+       serialArray: function() {
+               throw "serialArray is deprecated - use jsDump.parse() instead";
+       },
+       q: q,
+       t: t,
+       url: url,
+       triggerEvent: triggerEvent
+});
+
+$(window).load(function() {
+       $('#userAgent').html(navigator.userAgent);
+       var head = $('<div class="testrunner-toolbar"><label for="filter-pass">Hide passed tests</label></div>').insertAfter("#userAgent");
+       $('<input type="checkbox" id="filter-pass" />').attr("disabled", true).prependTo(head).click(function() {
+               $('li.pass')[this.checked ? 'hide' : 'show']();
+       });
+       $('<input type="checkbox" id="filter-missing">').attr("disabled", true).appendTo(head).click(function() {
+               $("li.fail:contains('missing test - untested code is broken code')").parent('ol').parent('li.fail')[this.checked ? 'hide' : 'show']();
+       });
+       $("#filter-missing").after('<label for="filter-missing">Hide missing tests (untested code is broken code)</label>');
+       runTest();      
+});
+
+function synchronize(callback) {
+       config.queue.push(callback);
+       if(!config.blocking) {
+               process();
+       }
+}
+
+function process() {
+       while(config.queue.length && !config.blocking) {
+               config.queue.shift()();
+       }
+}
+
+function stop(timeout) {
+       config.blocking = true;
+       if (timeout)
+               config.timeout = setTimeout(function() {
+                       QUnit.ok( false, "Test timed out" );
+                       start();
+               }, timeout);
+}
+function start() {
+       // A slight delay, to avoid any current callbacks
+       setTimeout(function() {
+               if(config.timeout)
+                       clearTimeout(config.timeout);
+               config.blocking = false;
+               process();
+       }, 13);
+}
+
+function validTest( name ) {
+       var i = config.filters.length,
+               run = false;
+
+       if( !i )
+               return true;
+       
+       while( i-- ){
+               var filter = config.filters[i],
+                       not = filter.charAt(0) == '!';
+               if( not ) 
+                       filter = filter.slice(1);
+               if( name.indexOf(filter) != -1 )
+                       return !not;
+               if( not )
+                       run = true;
+       }
+       return run;
+}
+
+function runTest() {
+       config.blocking = false;
+       var started = +new Date;
+       config.fixture = document.getElementById('main').innerHTML;
+       config.ajaxSettings = $.ajaxSettings;
+       synchronize(function() {
+               $('<p id="testresult" class="result"/>').html(['Tests completed in ',
+                       +new Date - started, ' milliseconds.<br/>',
+                       '<span class="bad">', config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> failed.']
+                       .join(''))
+                       .appendTo("body");
+               $("#banner").addClass(config.stats.bad ? "fail" : "pass");
+               QUnit.done( config.stats.bad, config.stats.all );
+       });
+}
+
+var pollution;
+
+function saveGlobal(){
+       pollution = [ ];
+       
+       if( noglobals )
+               for( var key in window )
+                       pollution.push(key);
+}
+function checkPollution( name ){
+       var old = pollution;
+       saveGlobal();
+       
+       if( pollution.length > old.length ){
+               ok( false, "Introduced global variable(s): " + diff(old, pollution).join(", ") );
+               config.expected++;
+       }
+}
+
+function diff( clean, dirty ){
+       return $.grep( dirty, function(name){
+               return $.inArray( name, clean ) == -1;
+       });
+}
+
+function test(name, callback) {
+       if(config.currentModule)
+               name = config.currentModule + " module: " + name;
+       var lifecycle = $.extend({
+               setup: function() {},
+               teardown: function() {}
+       }, config.moduleLifecycle);
+       
+       if ( !validTest(name) )
+               return;
+       
+       synchronize(function() {
+               config.assertions = [];
+               config.expected = null;
+               try {
+                       if( !pollution )
+                               saveGlobal();
+                       lifecycle.setup();
+               } catch(e) {
+                       QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
+               }
+       })
+       synchronize(function() {
+               try {
+                       callback();
+               } catch(e) {
+                       if( typeof console != "undefined" && console.error && console.warn ) {
+                               console.error("Test " + name + " died, exception and test follows");
+                               console.error(e);
+                               console.warn(callback.toString());
+                       }
+                       QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
+                       // else next test will carry the responsibility
+                       saveGlobal();
+               }
+       });
+       synchronize(function() {
+               try {
+                       checkPollution();
+                       lifecycle.teardown();
+               } catch(e) {
+                       QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
+               }
+       })
+       synchronize(function() {
+               try {
+                       reset();
+               } catch(e) {
+                       if( typeof console != "undefined" && console.error && console.warn ) {
+                               console.error("reset() failed, following Test " + name + ", exception and reset fn follows");
+                               console.error(e);
+                               console.warn(reset.toString());
+                       }
+               }
+               
+               if(config.expected && config.expected != config.assertions.length) {
+                       QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
+               }
+               
+               var good = 0, bad = 0;
+               var ol  = $("<ol/>").hide();
+               config.stats.all += config.assertions.length;
+               for ( var i = 0; i < config.assertions.length; i++ ) {
+                       var assertion = config.assertions[i];
+                       $("<li/>").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol);
+                       assertion.result ? good++ : bad++;
+               }
+               config.stats.bad += bad;
+       
+               var b = $("<strong/>").html(name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>")
+               .click(function(){
+                       $(this).next().toggle();
+               })
+               .dblclick(function(event) {
+                       var target = $(event.target).filter("strong").clone();
+                       if ( target.length ) {
+                               target.children().remove();
+                               location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text()));
+                       }
+               });
+               
+               $("<li/>").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests");
+       
+               if(bad) {
+                       $("#filter-pass").attr("disabled", null);
+                       $("#filter-missing").attr("disabled", null);
+               }
+       });
+}
+
+// call on start of module test to prepend name to all tests
+function module(name, lifecycle) {
+       config.currentModule = name;
+       config.moduleLifecycle = lifecycle;
+}
+
+/**
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
+ */
+function expect(asserts) {
+       config.expected = asserts;
+}
+
+/**
+ * Resets the test setup. Useful for tests that modify the DOM.
+ */
+function reset() {
+       $("#main").html( config.fixture );
+       $.event.global = {};
+       $.ajaxSettings = $.extend({}, config.ajaxSettings);
+}
+
+/**
+ * Asserts true.
+ * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
+ */
+function ok(a, msg) {
+       QUnit.log(a, msg);
+
+       config.assertions.push({
+               result: !!a,
+               message: msg
+       });
+}
+
+/**
+ * Asserts that two arrays are the same
+ */
+function isSet(a, b, msg) {
+       function serialArray( a ) {
+               var r = [];
+               
+               if ( a && a.length )
+                       for ( var i = 0; i < a.length; i++ ) {
+                               var str = a[i].nodeName;
+                               if ( str ) {
+                                       str = str.toLowerCase();
+                                       if ( a[i].id )
+                                               str += "#" + a[i].id;
+                               } else
+                                       str = a[i];
+                               r.push( str );
+                       }
+       
+               return "[ " + r.join(", ") + " ]";
+       }
+       var ret = true;
+       if ( a && b && a.length != undefined && a.length == b.length ) {
+               for ( var i = 0; i < a.length; i++ )
+                       if ( a[i] != b[i] )
+                               ret = false;
+       } else
+               ret = false;
+       QUnit.ok( ret, !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg );
+}
+
+/**
+ * Asserts that two objects are equivalent
+ */
+function isObj(a, b, msg) {
+       var ret = true;
+       
+       if ( a && b ) {
+               for ( var i in a )
+                       if ( a[i] != b[i] )
+                               ret = false;
+
+               for ( i in b )
+                       if ( a[i] != b[i] )
+                               ret = false;
+       } else
+               ret = false;
+
+       QUnit.ok( ret, msg );
+}
+
+/**
+ * Returns an array of elements with the given IDs, eg.
+ * @example q("main", "foo", "bar")
+ * @result [<div id="main">, <span id="foo">, <input id="bar">]
+ */
+function q() {
+       var r = [];
+       for ( var i = 0; i < arguments.length; i++ )
+               r.push( document.getElementById( arguments[i] ) );
+       return r;
+}
+
+/**
+ * Asserts that a select matches the given IDs
+ * @example t("Check for something", "//[a]", ["foo", "baar"]);
+ * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
+ */
+function t(a,b,c) {
+       var f = $(b);
+       var s = "";
+       for ( var i = 0; i < f.length; i++ )
+               s += (s && ",") + '"' + f[i].id + '"';
+       isSet(f, q.apply(q,c), a + " (" + b + ")");
+}
+
+/**
+ * Add random number to url to stop IE from caching
+ *
+ * @example url("data/test.html")
+ * @result "data/test.html?10538358428943"
+ *
+ * @example url("data/test.php?foo=bar")
+ * @result "data/test.php?foo=bar&10538358345554"
+ */
+function url(value) {
+       return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
+}
+
+/**
+ * Checks that the first two arguments are equal, with an optional message.
+ * Prints out both actual and expected values.
+ *
+ * Prefered to ok( actual == expected, message )
+ *
+ * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." );
+ *
+ * @param Object actual
+ * @param Object expected
+ * @param String message (optional)
+ */
+function equals(actual, expected, message) {
+       push(expected == actual, actual, expected, message);
+}
+
+function push(result, actual, expected, message) {
+       message = message || (result ? "okay" : "failed");
+       QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual) );
+}
+
+/**
+ * Trigger an event on an element.
+ *
+ * @example triggerEvent( document.body, "click" );
+ *
+ * @param DOMElement elem
+ * @param String type
+ */
+function triggerEvent( elem, type, event ) {
+       if ( $.browser.mozilla || $.browser.opera ) {
+               event = document.createEvent("MouseEvents");
+               event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
+                       0, 0, 0, 0, 0, false, false, false, false, 0, null);
+               elem.dispatchEvent( event );
+       } else if ( $.browser.msie ) {
+               elem.fireEvent("on"+type);
+       }
+}
+
+})(jQuery);
+
+/**
+ * jsDump
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
+ * Date: 5/15/2008
+ * @projectDescription Advanced and extensible data dumping for Javascript.
+ * @version 1.0.0
+ * @author Ariel Flesler
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
+ */
+(function(){
+       function quote( str ){
+               return '"' + str.toString().replace(/"/g, '\\"') + '"';
+       };
+       function literal( o ){
+               return o + '';  
+       };
+       function join( pre, arr, post ){
+               var s = jsDump.separator(),
+                       base = jsDump.indent();
+                       inner = jsDump.indent(1);
+               if( arr.join )
+                       arr = arr.join( ',' + s + inner );
+               if( !arr )
+                       return pre + post;
+               return [ pre, inner + arr, base + post ].join(s);
+       };
+       function array( arr ){
+               var i = arr.length,     ret = Array(i);                                 
+               this.up();
+               while( i-- )
+                       ret[i] = this.parse( arr[i] );                          
+               this.down();
+               return join( '[', ret, ']' );
+       };
+       
+       var reName = /^function (\w+)/;
+       
+       var jsDump = window.jsDump = {
+               parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance
+                       var     parser = this.parsers[ type || this.typeOf(obj) ];
+                       type = typeof parser;                   
+                       
+                       return type == 'function' ? parser.call( this, obj ) :
+                                  type == 'string' ? parser :
+                                  this.parsers.error;
+               },
+               typeOf:function( obj ){
+                       var type = typeof obj,
+                               f = 'function';//we'll use it 3 times, save it
+                       return type != 'object' && type != f ? type :
+                               !obj ? 'null' :
+                               obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions
+                               obj.getHours ? 'date' :
+                               obj.scrollBy ?  'window' :
+                               obj.nodeName == '#document' ? 'document' :
+                               obj.nodeName ? 'node' :
+                               obj.item ? 'nodelist' : // Safari reports nodelists as functions
+                               obj.callee ? 'arguments' :
+                               obj.call || obj.constructor != Array && //an array would also fall on this hack
+                                       (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects
+                               'length' in obj ? 'array' :
+                               type;
+               },
+               separator:function(){
+                       return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
+               },
+               indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing
+                       if( !this.multiline )
+                               return '';
+                       var chr = this.indentChar;
+                       if( this.HTML )
+                               chr = chr.replace(/\t/g,'   ').replace(/ /g,'&nbsp;');
+                       return Array( this._depth_ + (extra||0) ).join(chr);
+               },
+               up:function( a ){
+                       this._depth_ += a || 1;
+               },
+               down:function( a ){
+                       this._depth_ -= a || 1;
+               },
+               setParser:function( name, parser ){
+                       this.parsers[name] = parser;
+               },
+               // The next 3 are exposed so you can use them
+               quote:quote, 
+               literal:literal,
+               join:join,
+               //
+               _depth_: 1,
+               // This is the list of parsers, to modify them, use jsDump.setParser
+               parsers:{
+                       window: '[Window]',
+                       document: '[Document]',
+                       error:'[ERROR]', //when no parser is found, shouldn't happen
+                       unknown: '[Unknown]',
+                       'null':'null',
+                       undefined:'undefined',
+                       'function':function( fn ){
+                               var ret = 'function',
+                                       name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
+                               if( name )
+                                       ret += ' ' + name;
+                               ret += '(';
+                               
+                               ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
+                               return join( ret, this.parse(fn,'functionCode'), '}' );
+                       },
+                       array: array,
+                       nodelist: array,
+                       arguments: array,
+                       object:function( map ){
+                               var ret = [ ];
+                               this.up();
+                               for( var key in map )
+                                       ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
+                               this.down();
+                               return join( '{', ret, '}' );
+                       },
+                       node:function( node ){
+                               var open = this.HTML ? '&lt;' : '<',
+                                       close = this.HTML ? '&gt;' : '>';
+                                       
+                               var tag = node.nodeName.toLowerCase(),
+                                       ret = open + tag;
+                                       
+                               for( var a in this.DOMAttrs ){
+                                       var val = node[this.DOMAttrs[a]];
+                                       if( val )
+                                               ret += ' ' + a + '=' + this.parse( val, 'attribute' );
+                               }
+                               return ret + close + open + '/' + tag + close;
+                       },
+                       functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function
+                               var l = fn.length;
+                               if( !l ) return '';                             
+                               
+                               var args = Array(l);
+                               while( l-- )
+                                       args[l] = String.fromCharCode(97+l);//97 is 'a'
+                               return ' ' + args.join(', ') + ' ';
+                       },
+                       key:quote, //object calls it internally, the key part of an item in a map
+                       functionCode:'[code]', //function calls it internally, it's the content of the function
+                       attribute:quote, //node calls it internally, it's an html attribute value
+                       string:quote,
+                       date:quote,
+                       regexp:literal, //regex
+                       number:literal,
+                       'boolean':literal
+               },
+               DOMAttrs:{//attributes to dump from nodes, name=>realName
+                       id:'id',
+                       name:'name',
+                       'class':'className'
+               },
+               HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
+               indentChar:'   ',//indentation unit
+               multiline:true //if true, items in a collection, are separated by a \n, else just a space.
+       };
+
+})();
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/qunit/testsuite.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/qunit/testsuite.css
new file mode 100644 (file)
index 0000000..dbfc43a
--- /dev/null
@@ -0,0 +1,120 @@
+body, div, h1 { font-family: 'trebuchet ms', verdana, arial; margin: 0; padding: 0 }
+body {font-size: 10pt; }
+h1 { padding: 15px; font-size: large; background-color: #06b; color: white; }
+h1 a { color: white; }
+h2 { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal }
+
+.pass { color: green; } 
+.fail { color: red; } 
+p.result { margin-left: 1em; }
+
+#banner { height: 2em; border-bottom: 1px solid white; }
+h2.pass { background-color: green; }
+h2.fail { background-color: red; }
+
+div.testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; }
+
+ol#tests > li > strong { cursor:pointer; }
+
+div#fx-tests h4 {
+       background: red;
+}
+
+div#fx-tests h4.pass {
+       background: green;
+}
+
+div#fx-tests div.box {
+       background: red url(data/cow.jpg) no-repeat;
+       overflow: hidden;
+       border: 2px solid #000;
+}
+
+div#fx-tests div.overflow {
+       overflow: visible;
+}
+
+div.inline {
+       display: inline;
+}
+
+div.autoheight {
+       height: auto;
+}
+
+div.autowidth {
+       width: auto;
+}
+
+div.autoopacity {
+       opacity: auto;
+}
+
+div.largewidth {
+       width: 100px;
+}
+
+div.largeheight {
+       height: 100px;
+}
+
+div.largeopacity {
+       filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100);
+}
+
+div.medwidth {
+       width: 50px;
+}
+
+div.medheight {
+       height: 50px;
+}
+
+div.medopacity {
+       opacity: 0.5;
+       filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50);
+}
+
+div.nowidth {
+       width: 0px;
+}
+
+div.noheight {
+       height: 0px;
+}
+
+div.noopacity {
+       opacity: 0;
+       filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
+}
+
+div.hidden {
+       display: none;
+}
+
+div#fx-tests div.widewidth {
+       background-repeat: repeat-x;
+}
+
+div#fx-tests div.wideheight {
+       background-repeat: repeat-y;
+}
+
+div#fx-tests div.widewidth.wideheight {
+       background-repeat: repeat;
+}
+
+div#fx-tests div.noback {
+       background-image: none;
+}
+
+div.chain, div.chain div { width: 100px; height: 20px; position: relative; float: left; }
+div.chain div { position: absolute; top: 0px; left: 0px; }
+
+div.chain.test { background: red; }
+div.chain.test div { background: green; }
+
+div.chain.out { background: green; }
+div.chain.out div { background: red; display: none; }
+
+div#show-tests * { display: none; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/simulate/jquery.simulate.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/external/simulate/jquery.simulate.js
new file mode 100644 (file)
index 0000000..d52140b
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * jquery.simulate - simulate browser mouse and keyboard events
+ *
+ * Copyright (c) 2009 Eduardo Lundgren (eduardolundgren@gmail.com)
+ * and Richard D. Worth (rdworth@gmail.com)
+ *
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ */
+
+;(function($) {
+
+$.fn.extend({
+       simulate: function(type, options) {
+               return this.each(function() {
+                       var opt = $.extend({}, $.simulate.defaults, options || {});
+                       new $.simulate(this, type, opt);
+               });
+       }
+});
+
+$.simulate = function(el, type, options) {
+       this.target = el;
+       this.options = options;
+
+       if (/^drag$/.test(type)) {
+               this[type].apply(this, [this.target, options]);
+       } else {
+               this.simulateEvent(el, type, options);
+       }
+}
+
+$.extend($.simulate.prototype, {
+       simulateEvent: function(el, type, options) {
+               var evt = this.createEvent(type, options);
+               this.dispatchEvent(el, type, evt, options);
+               return evt;
+       },
+       createEvent: function(type, options) {
+               if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) {
+                       return this.mouseEvent(type, options);
+               } else if (/^key(up|down|press)$/.test(type)) {
+                       return this.keyboardEvent(type, options);
+               }
+       },
+       mouseEvent: function(type, options) {
+               var evt;
+               var e = $.extend({
+                       bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0,
+                       screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+                       ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+                       button: 0, relatedTarget: undefined
+               }, options);
+
+               var relatedTarget = $(e.relatedTarget)[0];
+
+               if ($.isFunction(document.createEvent)) {
+                       evt = document.createEvent("MouseEvents");
+                       evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
+                               e.screenX, e.screenY, e.clientX, e.clientY,
+                               e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
+                               e.button, e.relatedTarget || document.body.parentNode);
+               } else if (document.createEventObject) {
+                       evt = document.createEventObject();
+                       $.extend(evt, e);
+                       evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
+               }
+               return evt;
+       },
+       keyboardEvent: function(type, options) {
+               var evt;
+
+               var e = $.extend({ bubbles: true, cancelable: true, view: window,
+                       ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+                       keyCode: 0, charCode: 0
+               }, options);
+
+               if ($.isFunction(document.createEvent)) {
+                       try {
+                               evt = document.createEvent("KeyEvents");
+                               evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view,
+                                       e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
+                                       e.keyCode, e.charCode);
+                       } catch(err) {
+                               evt = document.createEvent("Events");
+                               evt.initEvent(type, e.bubbles, e.cancelable);
+                               $.extend(evt, { view: e.view,
+                                       ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey,
+                                       keyCode: e.keyCode, charCode: e.charCode
+                               });
+                       }
+               } else if (document.createEventObject) {
+                       evt = document.createEventObject();
+                       $.extend(evt, e);
+               }
+               if ($.browser.msie || $.browser.opera) {
+                       evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode;
+                       evt.charCode = undefined;
+               }
+               return evt;
+       },
+
+       dispatchEvent: function(el, type, evt) {
+               if (el.dispatchEvent) {
+                       el.dispatchEvent(evt);
+               } else if (el.fireEvent) {
+                       el.fireEvent('on' + type, evt);
+               }
+               return evt;
+       },
+
+       drag: function(el) {
+               var self = this, center = this.findCenter(this.target), 
+                       options = this.options, x = Math.floor(center.x), y = Math.floor(center.y), 
+                       dx = options.dx || 0, dy = options.dy || 0, target = this.target;
+               var coord = { clientX: x, clientY: y };
+               this.simulateEvent(target, "mousedown", coord);
+               coord = { clientX: x + 1, clientY: y + 1 };
+               this.simulateEvent(document, "mousemove", coord);
+               coord = { clientX: x + dx, clientY: y + dy };
+               this.simulateEvent(document, "mousemove", coord);
+               this.simulateEvent(document, "mousemove", coord);
+               this.simulateEvent(target, "mouseup", coord);
+       },
+       findCenter: function(el) {
+               var el = $(this.target), o = el.offset();
+               return {
+                       x: o.left + el.outerWidth() / 2,
+                       y: o.top + el.outerHeight() / 2
+               };
+       }
+});
+
+$.extend($.simulate, {
+       defaults: {
+               speed: 'sync'
+       },
+       VK_TAB: 9,
+       VK_ENTER: 13,
+       VK_ESC: 27,
+       VK_PGUP: 33,
+       VK_PGDN: 34,
+       VK_END: 35,
+       VK_HOME: 36,
+       VK_LEFT: 37,
+       VK_UP: 38,
+       VK_RIGHT: 39,
+       VK_DOWN: 40
+});
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png
new file mode 100644 (file)
index 0000000..64ece57
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644 (file)
index 0000000..5b5dab2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644 (file)
index 0000000..ad3d634
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644 (file)
index 0000000..42ccba2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_65_ffffff_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644 (file)
index 0000000..5a46b47
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_dadada_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644 (file)
index 0000000..86c2baa
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_ffffff_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_ffffff_1x400.png
new file mode 100644 (file)
index 0000000..e65ca12
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_glass_75_ffffff_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644 (file)
index 0000000..7c9fa6c
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png
new file mode 100644 (file)
index 0000000..0e05810
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_222222_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_222222_256x240.png
new file mode 100644 (file)
index 0000000..67560da
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_222222_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_2e83ff_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_2e83ff_256x240.png
new file mode 100644 (file)
index 0000000..b2c9052
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_2e83ff_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_454545_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_454545_256x240.png
new file mode 100644 (file)
index 0000000..0cd64a2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_454545_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_888888_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_888888_256x240.png
new file mode 100644 (file)
index 0000000..2e5180e
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_888888_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_cd0a0a_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_cd0a0a_256x240.png
new file mode 100644 (file)
index 0000000..2db88b7
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.accordion.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.accordion.css
new file mode 100644 (file)
index 0000000..ee1b1b6
--- /dev/null
@@ -0,0 +1,9 @@
+/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
+.ui-accordion .ui-accordion-content-active { display: block; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.all.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.all.css
new file mode 100644 (file)
index 0000000..543e4c3
--- /dev/null
@@ -0,0 +1,2 @@
+@import "ui.base.css";
+@import "ui.theme.css";
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.base.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.base.css
new file mode 100644 (file)
index 0000000..d716095
--- /dev/null
@@ -0,0 +1,8 @@
+@import url("ui.core.css");
+@import url("ui.resizable.css");
+@import url("ui.accordion.css");
+@import url("ui.dialog.css");
+@import url("ui.slider.css");
+@import url("ui.tabs.css");
+@import url("ui.datepicker.css");
+@import url("ui.progressbar.css");
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.core.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.core.css
new file mode 100644 (file)
index 0000000..c2f18f2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.datepicker.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.datepicker.css
new file mode 100644 (file)
index 0000000..d18ee63
--- /dev/null
@@ -0,0 +1,62 @@
+/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month, 
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+       display: none; /*sorry for IE5*/
+       display/**/: block; /*sorry for IE5*/
+       position: absolute; /*must have*/
+       z-index: -1; /*must have*/
+       filter: mask(); /*must have*/
+       top: -4px; /*must have*/
+       left: -4px; /*must have*/
+       width: 200px; /*must have*/
+       height: 200px; /*must have*/
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.dialog.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.dialog.css
new file mode 100644 (file)
index 0000000..2997595
--- /dev/null
@@ -0,0 +1,13 @@
+/* Dialog
+----------------------------------*/
+.ui-dialog { position: relative; padding: .2em; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative;  }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } 
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.progressbar.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.progressbar.css
new file mode 100644 (file)
index 0000000..bc0939e
--- /dev/null
@@ -0,0 +1,4 @@
+/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.resizable.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.resizable.css
new file mode 100644 (file)
index 0000000..44efeb2
--- /dev/null
@@ -0,0 +1,13 @@
+/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.slider.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.slider.css
new file mode 100644 (file)
index 0000000..4c56218
--- /dev/null
@@ -0,0 +1,17 @@
+/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.tabs.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.tabs.css
new file mode 100644 (file)
index 0000000..3ca6b9a
--- /dev/null
@@ -0,0 +1,11 @@
+/* Tabs
+----------------------------------*/
+.ui-tabs { padding: .2em; zoom: 1; }
+.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
+.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.theme.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/base/ui.theme.css
new file mode 100644 (file)
index 0000000..014fcfc
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://jqueryui.com/themeroller/
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_glass_75_ffffff_1x400.png)/*{bgImgUrlContent}*/ 0/*{bgContentXPos}*/ 0/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; }
+.ui-widget-content a { color: #222222/*{fcContent}*/; }
+.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 0/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; }
+.ui-widget-header a { color: #222222/*{fcHeader}*/; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 0/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; outline: none; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; outline: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 0/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; outline: none; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; outline: none; }
+.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 0/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; outline: none; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; outline: none; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 0/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
+.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_inset-soft_95_fef1ec_1x100.png)/*{bgImgUrlError}*/ 0/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
+.ui-state-error a, .ui-widget-content .ui-state-error a { color: #363636/*{fcError}*/; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-right {  -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ none/*{bgImgUrlOverlay}*/ 0/*{bgOverlayXPos}*/ 0/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
+.ui-widget-shadow { margin: -4px/*{offsetTopShadow}*/ 0 0 -4px/*{offsetLeftShadow}*/; padding: 4px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ none/*{bgImgUrlShadow}*/ 0/*{bgShadowXPos}*/ 0/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .35;filter:Alpha(Opacity=35)/*{opacityShadow}*/; -moz-border-radius: 4px/*{cornerRadiusShadow}*/; -webkit-border-radius: 4px/*{cornerRadiusShadow}*/; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644 (file)
index 0000000..5b5dab2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png
new file mode 100644 (file)
index 0000000..47acaad
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png
new file mode 100644 (file)
index 0000000..9fb564f
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png
new file mode 100644 (file)
index 0000000..0149515
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644 (file)
index 0000000..4443fdc
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png
new file mode 100644 (file)
index 0000000..81ecc36
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png
new file mode 100644 (file)
index 0000000..4f3faf8
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png
new file mode 100644 (file)
index 0000000..38c3833
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_217bc0_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_217bc0_256x240.png
new file mode 100644 (file)
index 0000000..9c88458
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_217bc0_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_2e83ff_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_2e83ff_256x240.png
new file mode 100644 (file)
index 0000000..b425c44
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_2e83ff_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_469bdd_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_469bdd_256x240.png
new file mode 100644 (file)
index 0000000..5e7915f
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_469bdd_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_6da8d5_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_6da8d5_256x240.png
new file mode 100644 (file)
index 0000000..60e20ca
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_6da8d5_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_cd0a0a_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_cd0a0a_256x240.png
new file mode 100644 (file)
index 0000000..2db88b7
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_d8e7f3_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_d8e7f3_256x240.png
new file mode 100644 (file)
index 0000000..2c8aac4
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_d8e7f3_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_f9bd01_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_f9bd01_256x240.png
new file mode 100644 (file)
index 0000000..e81603f
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/images/ui-icons_f9bd01_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/jquery-ui-1.7.1.custom.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/redmond/jquery-ui-1.7.1.custom.css
new file mode 100644 (file)
index 0000000..5876717
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
+.ui-widget-header a { color: #ffffff; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; outline: none; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; outline: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; outline: none; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; outline: none; }
+.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; outline: none; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; outline: none; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; }
+.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
+.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
+.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
+.ui-corner-right {  -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
+.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
+.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
+.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month, 
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+    display: none; /*sorry for IE5*/
+       display/**/: block; /*sorry for IE5*/
+       position: absolute; /*must have*/
+       z-index: -1; /*must have*/
+       filter: mask(); /*must have*/
+       top: -4px; /*must have*/
+       left: -4px; /*must have*/
+       width: 200px; /*must have*/
+       height: 200px; /*must have*/
+}/* Dialog
+----------------------------------*/
+.ui-dialog { position: relative; padding: .2em; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative;  }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } 
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
+----------------------------------*/
+.ui-tabs { padding: .2em; zoom: 1; }
+.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
+.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png
new file mode 100644 (file)
index 0000000..64ece57
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644 (file)
index 0000000..5b5dab2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644 (file)
index 0000000..ac8b229
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644 (file)
index 0000000..ad3d634
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644 (file)
index 0000000..42ccba2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644 (file)
index 0000000..5a46b47
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644 (file)
index 0000000..86c2baa
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644 (file)
index 0000000..4443fdc
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644 (file)
index 0000000..7c9fa6c
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_222222_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_222222_256x240.png
new file mode 100644 (file)
index 0000000..67560da
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_222222_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_2e83ff_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_2e83ff_256x240.png
new file mode 100644 (file)
index 0000000..b425c44
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_2e83ff_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_454545_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_454545_256x240.png
new file mode 100644 (file)
index 0000000..0cd64a2
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_454545_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_888888_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_888888_256x240.png
new file mode 100644 (file)
index 0000000..2e5180e
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_888888_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_cd0a0a_256x240.png b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_cd0a0a_256x240.png
new file mode 100644 (file)
index 0000000..2db88b7
Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/jquery-ui-1.7.1.custom.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/jquery-ui-1.7.1.custom.css
new file mode 100644 (file)
index 0000000..303ec94
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; outline: none; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; outline: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; outline: none; }
+.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; outline: none; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; }
+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-right {  -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }
+.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
+.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month, 
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+       display: none; /*sorry for IE5*/
+       display/**/: block; /*sorry for IE5*/
+       position: absolute; /*must have*/
+       z-index: -1; /*must have*/
+       filter: mask(); /*must have*/
+       top: -4px; /*must have*/
+       left: -4px; /*must have*/
+       width: 200px; /*must have*/
+       height: 200px; /*must have*/
+}/* Dialog
+----------------------------------*/
+.ui-dialog { position: relative; padding: .2em; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative;  }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } 
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
+----------------------------------*/
+.ui-tabs { padding: .2em; zoom: 1; }
+.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
+.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.accordion.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.accordion.css
new file mode 100644 (file)
index 0000000..ee1b1b6
--- /dev/null
@@ -0,0 +1,9 @@
+/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
+.ui-accordion .ui-accordion-content-active { display: block; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.all.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.all.css
new file mode 100644 (file)
index 0000000..543e4c3
--- /dev/null
@@ -0,0 +1,2 @@
+@import "ui.base.css";
+@import "ui.theme.css";
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.base.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.base.css
new file mode 100644 (file)
index 0000000..d716095
--- /dev/null
@@ -0,0 +1,8 @@
+@import url("ui.core.css");
+@import url("ui.resizable.css");
+@import url("ui.accordion.css");
+@import url("ui.dialog.css");
+@import url("ui.slider.css");
+@import url("ui.tabs.css");
+@import url("ui.datepicker.css");
+@import url("ui.progressbar.css");
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.core.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.core.css
new file mode 100644 (file)
index 0000000..c2f18f2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.datepicker.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.datepicker.css
new file mode 100644 (file)
index 0000000..d18ee63
--- /dev/null
@@ -0,0 +1,62 @@
+/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month, 
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+       display: none; /*sorry for IE5*/
+       display/**/: block; /*sorry for IE5*/
+       position: absolute; /*must have*/
+       z-index: -1; /*must have*/
+       filter: mask(); /*must have*/
+       top: -4px; /*must have*/
+       left: -4px; /*must have*/
+       width: 200px; /*must have*/
+       height: 200px; /*must have*/
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.dialog.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.dialog.css
new file mode 100644 (file)
index 0000000..2997595
--- /dev/null
@@ -0,0 +1,13 @@
+/* Dialog
+----------------------------------*/
+.ui-dialog { position: relative; padding: .2em; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative;  }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } 
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.progressbar.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.progressbar.css
new file mode 100644 (file)
index 0000000..bc0939e
--- /dev/null
@@ -0,0 +1,4 @@
+/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.resizable.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.resizable.css
new file mode 100644 (file)
index 0000000..44efeb2
--- /dev/null
@@ -0,0 +1,13 @@
+/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.slider.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.slider.css
new file mode 100644 (file)
index 0000000..4c56218
--- /dev/null
@@ -0,0 +1,17 @@
+/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.tabs.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.tabs.css
new file mode 100644 (file)
index 0000000..3ca6b9a
--- /dev/null
@@ -0,0 +1,11 @@
+/* Tabs
+----------------------------------*/
+.ui-tabs { padding: .2em; zoom: 1; }
+.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
+.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.theme.css b/js2/mwEmbed/jquery/jquery.ui-1.7.1/themes/smoothness/ui.theme.css
new file mode 100644 (file)
index 0000000..10f76b4
--- /dev/null
@@ -0,0 +1,245 @@
+
+
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; outline: none; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; outline: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; outline: none; }
+.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; outline: none; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; }
+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-right {  -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }
+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }
+.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.blind.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.blind.js
new file mode 100644 (file)
index 0000000..e49d96c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * jQuery UI Effects Blind 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Blind
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.blind = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.bounce.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.bounce.js
new file mode 100644 (file)
index 0000000..fae3d1e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * jQuery UI Effects Bounce 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Bounce
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.bounce = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.clip.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.clip.js
new file mode 100644 (file)
index 0000000..a14a194
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * jQuery UI Effects Clip 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Clip
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.clip = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left','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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.core.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.core.js
new file mode 100644 (file)
index 0000000..c52a312
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * jQuery UI Effects 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/
+ */
+;jQuery.effects || (function($) {
+
+$.effects = {
+       version: "1.7.1",
+
+       // 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();
+
+               //Cache width,height and float properties of the element, and create a wrapper around it
+               var props = { width: element.outerWidth(true), height: element.outerHeight(true), 'float': element.css('float') };
+               element.wrap('<div class="ui-effects-wrapper" style="font-size:100%;background:transparent;border:none;margin:0;padding:0"></div>');
+               var wrapper = element.parent();
+
+               //Transfer the positioning of the element to the wrapper
+               if (element.css('position') == 'static') {
+                       wrapper.css({ position: 'relative' });
+                       element.css({ position: 'relative'} );
+               } else {
+                       var top = element.css('top'); if(isNaN(parseInt(top,10))) top = 'auto';
+                       var left = element.css('left'); if(isNaN(parseInt(left,10))) left = 'auto';
+                       wrapper.css({ position: element.css('position'), top: top, left: left, zIndex: element.css('z-index') }).show();
+                       element.css({position: 'relative', top: 0, left: 0 });
+               }
+
+               wrapper.css(props);
+               return wrapper;
+       },
+
+       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;
+       },
+
+       //Base function to animate from one class to another in a seamless transition
+       animateClass: function(value, duration, easing, callback) {
+
+               var cb = (typeof easing == "function" ? easing : (callback ? callback : null));
+               var ea = (typeof easing == "string" ? easing : null);
+
+               return this.each(function() {
+
+                       var offset = {}; var that = $(this); var oldStyleAttr = that.attr("style") || '';
+                       if(typeof oldStyleAttr == 'object') oldStyleAttr = oldStyleAttr["cssText"]; /* Stupidly in IE, style is a object.. */
+                       if(value.toggle) { that.hasClass(value.toggle) ? value.remove = value.toggle : value.add = value.toggle; }
+
+                       //Let's get a style offset
+                       var oldStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle));
+                       if(value.add) that.addClass(value.add); if(value.remove) that.removeClass(value.remove);
+                       var newStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle));
+                       if(value.add) that.removeClass(value.add); if(value.remove) that.addClass(value.remove);
+
+                       // The main function to form the object for animation
+                       for(var n in newStyle) {
+                               if( typeof newStyle[n] != "function" && newStyle[n] /* No functions and null properties */
+                               && n.indexOf("Moz") == -1 && n.indexOf("length") == -1 /* No mozilla spezific render properties. */
+                               && newStyle[n] != oldStyle[n] /* Only values that have changed are used for the animation */
+                               && (n.match(/color/i) || (!n.match(/color/i) && !isNaN(parseInt(newStyle[n],10)))) /* Only things that can be parsed to integers or colors */
+                               && (oldStyle.position != "static" || (oldStyle.position == "static" && !n.match(/left|top|bottom|right/))) /* No need for positions when dealing with static positions */
+                               ) offset[n] = newStyle[n];
+                       }
+
+                       that.animate(offset, duration, ea, function() { // Animate the newly constructed offset object
+                               // Change style attribute back to original. For stupid IE, we need to clear the damn object.
+                               if(typeof $(this).attr("style") == 'object') { $(this).attr("style")["cssText"] = ""; $(this).attr("style")["cssText"] = oldStyleAttr; } else $(this).attr("style", oldStyleAttr);
+                               if(value.add) $(this).addClass(value.add); if(value.remove) $(this).removeClass(value.remove);
+                               if(cb) cb.apply(this, arguments);
+                       });
+
+               });
+       }
+};
+
+
+function _normalizeArguments(a, m) {
+
+       var o = a[1] && a[1].constructor == Object ? a[1] : {}; if(m) o.mode = m;
+       var speed = a[1] && a[1].constructor != Object ? a[1] : (o.duration ? o.duration : a[2]); //either comes from options.duration or the secon/third argument
+               speed = $.fx.off ? 0 : typeof speed === "number" ? speed : $.fx.speeds[speed] || $.fx.speeds._default;
+       var callback = o.callback || ( $.isFunction(a[1]) && a[1] ) || ( $.isFunction(a[2]) && a[2] ) || ( $.isFunction(a[3]) && a[3] );
+
+       return [a[0], o, speed, callback];
+       
+}
+
+//Extend the methods of jQuery
+$.fn.extend({
+
+       //Save old methods
+       _show: $.fn.show,
+       _hide: $.fn.hide,
+       __toggle: $.fn.toggle,
+       _addClass: $.fn.addClass,
+       _removeClass: $.fn.removeClass,
+       _toggleClass: $.fn.toggleClass,
+
+       // New effect methods
+       effect: function(fx, options, speed, callback) {
+               return $.effects[fx] ? $.effects[fx].call(this, {method: fx, options: options || {}, duration: speed, callback: callback }) : null;
+       },
+
+       show: function() {
+               if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])))
+                       return this._show.apply(this, arguments);
+               else {
+                       return this.effect.apply(this, _normalizeArguments(arguments, 'show'));
+               }
+       },
+
+       hide: function() {
+               if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])))
+                       return this._hide.apply(this, arguments);
+               else {
+                       return this.effect.apply(this, _normalizeArguments(arguments, 'hide'));
+               }
+       },
+
+       toggle: function(){
+               if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])) || (arguments[0].constructor == Function))
+                       return this.__toggle.apply(this, arguments);
+               else {
+                       return this.effect.apply(this, _normalizeArguments(arguments, 'toggle'));
+               }
+       },
+
+       addClass: function(classNames, speed, easing, callback) {
+               return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);
+       },
+       removeClass: function(classNames,speed,easing,callback) {
+               return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);
+       },
+       toggleClass: function(classNames,speed,easing,callback) {
+               return ( (typeof speed !== "boolean") && speed ) ? $.effects.animateClass.apply(this, [{ toggle: classNames },speed,easing,callback]) : this._toggleClass(classNames, speed);
+       },
+       morph: function(remove,add,speed,easing,callback) {
+               return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);
+       },
+       switchClass: function() {
+               return this.morph.apply(this, arguments);
+       },
+
+       // 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;
+       }
+});
+
+/*
+ * jQuery Color Animations
+ * Copyright 2007 John Resig
+ * Released under the MIT and GPL licenses.
+ */
+
+// We override the animation for all of these color styles
+$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
+               $.fx.step[attr] = function(fx) {
+                               if ( fx.state == 0 ) {
+                                               fx.start = getColor( fx.elem, attr );
+                                               fx.end = getRGB( fx.end );
+                               }
+
+                               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)
+                               ].join(",") + ")";
+                       };
+});
+
+// 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]
+};
+
+/*
+ * 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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.drop.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.drop.js
new file mode 100644 (file)
index 0000000..2a3ffd4
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * jQuery UI Effects Drop 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Drop
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.drop = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left','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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.explode.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.explode.js
new file mode 100644 (file)
index 0000000..5bfc854
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * jQuery UI Effects Explode 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Explode
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.fold.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.fold.js
new file mode 100644 (file)
index 0000000..77f8a9d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * jQuery UI Effects Fold 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Fold
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.fold = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.highlight.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.highlight.js
new file mode 100644 (file)
index 0000000..680bacd
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * jQuery UI Effects Highlight 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Highlight
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.highlight = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['backgroundImage','backgroundColor','opacity'];
+
+               // Set options
+               var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
+               var color = o.options.color || "#ffff99"; // Default highlight color
+               var oldColor = el.css("backgroundColor");
+
+               // Adjust
+               $.effects.save(el, props); el.show(); // Save & Show
+               el.css({backgroundImage: 'none', backgroundColor: color}); // Shift
+
+               // Animation
+               var animation = {backgroundColor: oldColor };
+               if (mode == "hide") animation['opacity'] = 0;
+
+               // Animate
+               el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
+                       if(mode == "hide") el.hide();
+                       $.effects.restore(el, props);
+               if (mode == "show" && $.browser.msie) this.style.removeAttribute('filter');
+                       if(o.callback) o.callback.apply(this, arguments);
+                       el.dequeue();
+               }});
+
+       });
+
+};
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.pulsate.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.pulsate.js
new file mode 100644 (file)
index 0000000..e845634
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * jQuery UI Effects Pulsate 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Pulsate
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.pulsate = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this);
+
+               // Set options
+               var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
+               var times = o.options.times || 5; // Default # of times
+               var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;
+
+               // Adjust
+               if (mode == 'hide') times--;
+               if (el.is(':hidden')) { // Show fadeIn
+                       el.css('opacity', 0);
+                       el.show(); // Show
+                       el.animate({opacity: 1}, duration, o.options.easing);
+                       times = times-2;
+               }
+
+               // Animate
+               for (var i = 0; i < times; i++) { // Pulsate
+                       el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing);
+               };
+               if (mode == 'hide') { // Last Pulse
+                       el.animate({opacity: 0}, duration, o.options.easing, function(){
+                               el.hide(); // Hide
+                               if(o.callback) o.callback.apply(this, arguments); // Callback
+                       });
+               } else {
+                       el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing, function(){
+                               if(o.callback) o.callback.apply(this, arguments); // Callback
+                       });
+               };
+               el.queue('fx', function() { el.dequeue(); });
+               el.dequeue();
+       });
+
+};
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.scale.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.scale.js
new file mode 100644 (file)
index 0000000..e02dca0
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * jQuery UI Effects Scale 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Scale
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.puff = 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 || 'hide'); // Set Mode
+               var percent = parseInt(o.options.percent,10) || 150; // Set default puff percent
+               options.fade = true; // It's not a puff if it doesn't fade! :)
+               var original = {height: el.height(), width: el.width()}; // Save original
+
+               // Adjust
+               var factor = percent / 100;
+               el.from = (mode == 'hide') ? original : {height: original.height * factor, width: original.width * factor};
+
+               // Animation
+               options.from = el.from;
+               options.percent = (mode == 'hide') ? percent : 100;
+               options.mode = mode;
+
+               // Animate
+               el.effect('scale', options, o.duration, o.callback);
+               el.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','left','width','height','overflow','opacity'];
+               var props1 = ['position','top','left','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(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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.shake.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.shake.js
new file mode 100644 (file)
index 0000000..3bcf822
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * jQuery UI Effects Shake 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Shake
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.shake = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.slide.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.slide.js
new file mode 100644 (file)
index 0000000..1085ae6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * jQuery UI Effects Slide 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Slide
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.slide = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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' ? -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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.transfer.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/effects.transfer.js
new file mode 100644 (file)
index 0000000..b042cfd
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * jQuery UI Effects Transfer 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Transfer
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/jquery-ui-i18n.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/jquery-ui-i18n.js
new file mode 100644 (file)
index 0000000..2d90b4f
--- /dev/null
@@ -0,0 +1,771 @@
+/* Arabic Translation for jQuery UI date picker plugin. */\r
+/* Khaled Al Horani -- koko.dw@gmail.com */\r
+/* خالد الحوراني -- koko.dw@gmail.com */\r
+/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */\r
+jQuery(function($){\r
+       $.datepicker.regional['ar'] = {\r
+               closeText: 'إغلاق',\r
+               prevText: '&#x3c;السابق',\r
+               nextText: 'التالي&#x3e;',\r
+               currentText: 'اليوم',\r
+               monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران',\r
+               'تموز', 'آب', 'أيلول',       'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\r
+               monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],\r
+               dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'],\r
+               dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],\r
+               dayNamesMin: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+  isRTL: true};\r
+       $.datepicker.setDefaults($.datepicker.regional['ar']);\r
+});/* Bulgarian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Stoyan Kyosev (http://svest.org). */\r
+jQuery(function($){\r
+    $.datepicker.regional['bg'] = {\r
+        closeText: 'затвори',\r
+        prevText: '&#x3c;назад',\r
+        nextText: 'напред&#x3e;',\r
+               nextBigText: '&#x3e;&#x3e;',\r
+        currentText: 'днес',\r
+        monthNames: ['Януари','Февруари','Март','Април','Май','Юни',\r
+        'Юли','Август','Септември','Октомври','Ноември','Декември'],\r
+        monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни',\r
+        'Юли','Авг','Сеп','Окт','Нов','Дек'],\r
+        dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'],\r
+        dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'],\r
+        dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'],\r
+        dateFormat: 'dd.mm.yy', firstDay: 1,\r
+        isRTL: false};\r
+    $.datepicker.setDefaults($.datepicker.regional['bg']);\r
+});\r
+/* Inicialitzaci� en catal� per a l'extenci� 'calendar' per jQuery. */\r
+/* Writers: (joan.leon@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['ca'] = {\r
+               closeText: 'Tancar',\r
+               prevText: '&#x3c;Ant',\r
+               nextText: 'Seg&#x3e;',\r
+               currentText: 'Avui',\r
+               monthNames: ['Gener','Febrer','Mar&ccedil;','Abril','Maig','Juny',\r
+               'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'],\r
+               monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun',\r
+               'Jul','Ago','Set','Oct','Nov','Des'],\r
+               dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'],\r
+               dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'],\r
+               dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'],\r
+               dateFormat: 'mm/dd/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['ca']);\r
+});/* Czech initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Tomas Muller (tomas@tomas-muller.net). */\r
+jQuery(function($){\r
+       $.datepicker.regional['cs'] = {\r
+               closeText: 'Zavřít',\r
+               prevText: '&#x3c;Dříve',\r
+               nextText: 'Později&#x3e;',\r
+               currentText: 'Nyní',\r
+               monthNames: ['leden','únor','březen','duben','květen','červen',\r
+        'červenec','srpen','září','říjen','listopad','prosinec'],\r
+               monthNamesShort: ['led','úno','bře','dub','kvě','čer',\r
+               'čvc','srp','zář','říj','lis','pro'],\r
+               dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'],\r
+               dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'],\r
+               dayNamesMin: ['ne','po','út','st','čt','pá','so'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['cs']);\r
+});\r
+/* Danish initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Jan Christensen ( deletestuff@gmail.com). */\r
+jQuery(function($){\r
+    $.datepicker.regional['da'] = {\r
+               closeText: 'Luk',\r
+        prevText: '&#x3c;Forrige',\r
+               nextText: 'Næste&#x3e;',\r
+               currentText: 'Idag',\r
+        monthNames: ['Januar','Februar','Marts','April','Maj','Juni',\r
+        'Juli','August','September','Oktober','November','December'],\r
+        monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',\r
+        'Jul','Aug','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'],\r
+               dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'],\r
+               dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],\r
+        dateFormat: 'dd-mm-yy', firstDay: 0,\r
+               isRTL: false};\r
+    $.datepicker.setDefaults($.datepicker.regional['da']);\r
+});\r
+/* German initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Milian Wolff (mail@milianw.de). */\r
+jQuery(function($){\r
+       $.datepicker.regional['de'] = {\r
+               closeText: 'schließen',\r
+               prevText: '&#x3c;zurück',\r
+               nextText: 'Vor&#x3e;',\r
+               currentText: 'heute',\r
+               monthNames: ['Januar','Februar','März','April','Mai','Juni',\r
+               'Juli','August','September','Oktober','November','Dezember'],\r
+               monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',\r
+               'Jul','Aug','Sep','Okt','Nov','Dez'],\r
+               dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],\r
+               dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],\r
+               dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['de']);\r
+});\r
+/* Greek (el) initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Alex Cicovic (http://www.alexcicovic.com) */\r
+jQuery(function($){\r
+       $.datepicker.regional['el'] = {\r
+               closeText: 'Κλείσιμο',\r
+               prevText: 'Προηγούμενος',\r
+               nextText: 'Επόμενος',\r
+               currentText: 'Τρέχων Μήνας',\r
+               monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος',\r
+               'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'],\r
+               monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν',\r
+               'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'],\r
+               dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'],\r
+               dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'],\r
+               dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['el']);\r
+});/* Esperanto initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Olivier M. (olivierweb@ifrance.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['eo'] = {\r
+               closeText: 'Fermi',\r
+               prevText: '&lt;Anta',\r
+               nextText: 'Sekv&gt;',\r
+               currentText: 'Nuna',\r
+               monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio',\r
+               'Julio','Aŭgusto','Septembro','Oktobro','Novembro','Decembro'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',\r
+               'Jul','Aŭg','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ĵaŭdo','Vendredo','Sabato'],\r
+               dayNamesShort: ['Dim','Lun','Mar','Mer','Ĵaŭ','Ven','Sab'],\r
+               dayNamesMin: ['Di','Lu','Ma','Me','Ĵa','Ve','Sa'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['eo']);\r
+});\r
+/* Inicializaci�n en espa�ol para la extensi�n 'UI date picker' para jQuery. */\r
+/* Traducido por Vester (xvester@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['es'] = {\r
+               closeText: 'Cerrar',\r
+               prevText: '&#x3c;Ant',\r
+               nextText: 'Sig&#x3e;',\r
+               currentText: 'Hoy',\r
+               monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio',\r
+               'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],\r
+               monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun',\r
+               'Jul','Ago','Sep','Oct','Nov','Dic'],\r
+               dayNames: ['Domingo','Lunes','Martes','Mi&eacute;rcoles','Jueves','Viernes','S&aacute;bado'],\r
+               dayNamesShort: ['Dom','Lun','Mar','Mi&eacute;','Juv','Vie','S&aacute;b'],\r
+               dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','S&aacute;'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['es']);\r
+});/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */\r
+/* Javad Mowlanezhad -- jmowla@gmail.com */\r
+/* Jalali calendar should supported soon! (Its implemented but I have to test it) */\r
+jQuery(function($) {\r
+       $.datepicker.regional['fa'] = {\r
+               closeText: 'بستن',\r
+               prevText: '&#x3c;قبلي',\r
+               nextText: 'بعدي&#x3e;',\r
+               currentText: 'امروز',\r
+               monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور',\r
+               'مهر','آبان','آذر','دي','بهمن','اسفند'],\r
+               monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],\r
+               dayNames: ['يکشنبه','دوشنبه','سه‌شنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'],\r
+               dayNamesShort: ['ي','د','س','چ','پ','ج', 'ش'],\r
+               dayNamesMin: ['ي','د','س','چ','پ','ج', 'ش'],\r
+               dateFormat: 'yy/mm/dd', firstDay: 6,\r
+  isRTL: true};\r
+       $.datepicker.setDefaults($.datepicker.regional['fa']);\r
+});/* Finnish initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Harri Kilpi� (harrikilpio@gmail.com). */\r
+jQuery(function($){\r
+    $.datepicker.regional['fi'] = {\r
+               closeText: 'Sulje',\r
+               prevText: '&laquo;Edellinen',\r
+               nextText: 'Seuraava&raquo;',\r
+               currentText: 'T&auml;n&auml;&auml;n',\r
+        monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kes&auml;kuu',\r
+        'Hein&auml;kuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'],\r
+        monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kes&auml;',\r
+        'Hein&auml;','Elo','Syys','Loka','Marras','Joulu'],\r
+               dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','Su'],\r
+               dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'],\r
+               dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'],\r
+        dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+    $.datepicker.setDefaults($.datepicker.regional['fi']);\r
+});\r
+/* French initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Keith Wood (kbwood@virginbroadband.com.au) and Stéphane Nahmani (sholby@sholby.net). */\r
+jQuery(function($){\r
+       $.datepicker.regional['fr'] = {\r
+               closeText: 'Fermer',\r
+               prevText: '&#x3c;Préc',\r
+               nextText: 'Suiv&#x3e;',\r
+               currentText: 'Courant',\r
+               monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin',\r
+               'Juillet','Août','Septembre','Octobre','Novembre','Décembre'],\r
+               monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun',\r
+               'Jul','Aoû','Sep','Oct','Nov','Déc'],\r
+               dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],\r
+               dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'],\r
+               dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['fr']);\r
+});/* Hebrew initialisation for the UI Datepicker extension. */\r
+/* Written by Amir Hardon (ahardon at gmail dot com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['he'] = {\r
+               closeText: 'סגור',\r
+               prevText: '&#x3c;הקודם',\r
+               nextText: 'הבא&#x3e;',\r
+               currentText: 'היום',\r
+               monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני',\r
+               'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'],\r
+               monthNamesShort: ['1','2','3','4','5','6',\r
+               '7','8','9','10','11','12'],\r
+               dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'],\r
+               dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'],\r
+               dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: true};\r
+       $.datepicker.setDefaults($.datepicker.regional['he']);\r
+});\r
+/* Croatian i18n for the jQuery UI date picker plugin. */\r
+/* Written by Vjekoslav Nesek. */\r
+jQuery(function($){\r
+       $.datepicker.regional['hr'] = {\r
+               closeText: 'Zatvori',\r
+               prevText: '&#x3c;',\r
+               nextText: '&#x3e;',\r
+               currentText: 'Danas',\r
+               monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipani',\r
+               'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'],\r
+               monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip',\r
+               'Srp','Kol','Ruj','Lis','Stu','Pro'],\r
+               dayNames: ['Nedjalja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'],\r
+               dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'],\r
+               dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'],\r
+               dateFormat: 'dd.mm.yy.', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['hr']);\r
+});/* Hungarian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Istvan Karaszi (jquerycalendar@spam.raszi.hu). */\r
+jQuery(function($){\r
+       $.datepicker.regional['hu'] = {\r
+               closeText: 'bezárás',\r
+               prevText: '&laquo;&nbsp;vissza',\r
+               nextText: 'előre&nbsp;&raquo;',\r
+               currentText: 'ma',\r
+               monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június',\r
+               'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'],\r
+               monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún',\r
+               'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'],\r
+               dayNames: ['Vasámap', 'Hétfö', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'],\r
+               dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'],\r
+               dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'],\r
+               dateFormat: 'yy-mm-dd', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['hu']);\r
+});\r
+/* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/\r
+jQuery(function($){\r
+       $.datepicker.regional['hy'] = {\r
+               closeText: 'Փակել',\r
+               prevText: '&#x3c;Նախ.',\r
+               nextText: 'Հաջ.&#x3e;',\r
+               currentText: 'Այսօր',\r
+               monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս',\r
+               'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'],\r
+               monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս',\r
+               'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Դեկ'],\r
+               dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','հինգշաբթի','ուրբաթ','շաբաթ'],\r
+               dayNamesShort: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'],\r
+               dayNamesMin: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['hy']);\r
+});/* Indonesian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Deden Fathurahman (dedenf@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['id'] = {\r
+               closeText: 'Tutup',\r
+               prevText: '&#x3c;mundur',\r
+               nextText: 'maju&#x3e;',\r
+               currentText: 'hari ini',\r
+               monthNames: ['Januari','Februari','Maret','April','Mei','Juni',\r
+               'Juli','Agustus','September','Oktober','Nopember','Desember'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun',\r
+               'Jul','Agus','Sep','Okt','Nop','Des'],\r
+               dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'],\r
+               dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'],\r
+               dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['id']);\r
+});/* Icelandic initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Haukur H. Thorsson (haukur@eskill.is). */\r
+jQuery(function($){\r
+       $.datepicker.regional['is'] = {\r
+               closeText: 'Loka',\r
+               prevText: '&#x3c; Fyrri',\r
+               nextText: 'N&aelig;sti &#x3e;',\r
+               currentText: '&Iacute; dag',\r
+               monthNames: ['Jan&uacute;ar','Febr&uacute;ar','Mars','Apr&iacute;l','Ma&iacute','J&uacute;n&iacute;',\r
+               'J&uacute;l&iacute;','&Aacute;g&uacute;st','September','Okt&oacute;ber','N&oacute;vember','Desember'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Ma&iacute;','J&uacute;n',\r
+               'J&uacute;l','&Aacute;g&uacute;','Sep','Okt','N&oacute;v','Des'],\r
+               dayNames: ['Sunnudagur','M&aacute;nudagur','&THORN;ri&eth;judagur','Mi&eth;vikudagur','Fimmtudagur','F&ouml;studagur','Laugardagur'],\r
+               dayNamesShort: ['Sun','M&aacute;n','&THORN;ri','Mi&eth;','Fim','F&ouml;s','Lau'],\r
+               dayNamesMin: ['Su','M&aacute;','&THORN;r','Mi','Fi','F&ouml;','La'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['is']);\r
+});/* Italian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Apaella (apaella@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['it'] = {\r
+               closeText: 'Chiudi',\r
+               prevText: '&#x3c;Prec',\r
+               nextText: 'Succ&#x3e;',\r
+               currentText: 'Oggi',\r
+               monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno',\r
+               'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'],\r
+               monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu',\r
+               'Lug','Ago','Set','Ott','Nov','Dic'],\r
+               dayNames: ['Domenica','Luned&#236','Marted&#236','Mercoled&#236','Gioved&#236','Venerd&#236','Sabato'],\r
+               dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'],\r
+               dayNamesMin: ['Do','Lu','Ma','Me','Gio','Ve','Sa'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['it']);\r
+});\r
+/* Japanese initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Kentaro SATO (kentaro@ranvis.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['ja'] = {\r
+               closeText: '閉じる',\r
+               prevText: '&#x3c;前',\r
+               nextText: '次&#x3e;',\r
+               currentText: '今日',\r
+               monthNames: ['1月','2月','3月','4月','5月','6月',\r
+               '7月','8月','9月','10月','11月','12月'],\r
+               monthNamesShort: ['1月','2月','3月','4月','5月','6月',\r
+               '7月','8月','9月','10月','11月','12月'],\r
+               dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'],\r
+               dayNamesShort: ['日','月','火','水','木','金','土'],\r
+               dayNamesMin: ['日','月','火','水','木','金','土'],\r
+               dateFormat: 'yy/mm/dd', firstDay: 0,\r
+               isRTL: false,\r
+               showMonthAfterYear: true};\r
+       $.datepicker.setDefaults($.datepicker.regional['ja']);\r
+});/* Korean initialisation for the jQuery calendar extension. */\r
+/* Written by DaeKwon Kang (ncrash.dk@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['ko'] = {\r
+               closeText: '닫기',\r
+               prevText: '이전달',\r
+               nextText: '다음달',\r
+               currentText: '오늘',\r
+               monthNames: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)',\r
+               '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'],\r
+               monthNamesShort: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)',\r
+               '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'],\r
+               dayNames: ['일','월','화','수','목','금','토'],\r
+               dayNamesShort: ['일','월','화','수','목','금','토'],\r
+               dayNamesMin: ['일','월','화','수','목','금','토'],\r
+               dateFormat: 'yy-mm-dd', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['ko']);\r
+});/* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */\r
+/* @author Arturas Paleicikas <arturas@avalon.lt> */\r
+jQuery(function($){\r
+       $.datepicker.regional['lt'] = {\r
+               closeText: 'Uždaryti',\r
+               prevText: '&#x3c;Atgal',\r
+               nextText: 'Pirmyn&#x3e;',\r
+               currentText: 'Šiandien',\r
+               monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis',\r
+               'Liepa','Rugpjūtis','Rugsėjis','Spalis','Lapkritis','Gruodis'],\r
+               monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir',\r
+               'Lie','Rugp','Rugs','Spa','Lap','Gru'],\r
+               dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'],\r
+               dayNamesShort: ['sek','pir','ant','tre','ket','pen','šeš'],\r
+               dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Še'],\r
+               dateFormat: 'yy-mm-dd', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['lt']);\r
+});/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */\r
+/* @author Arturas Paleicikas <arturas.paleicikas@metasite.net> */\r
+jQuery(function($){\r
+       $.datepicker.regional['lv'] = {\r
+               closeText: 'Aizvērt',\r
+               prevText: 'Iepr',\r
+               nextText: 'Nāka',\r
+               currentText: 'Šodien',\r
+               monthNames: ['Janvāris','Februāris','Marts','Aprīlis','Maijs','Jūnijs',\r
+               'Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jūn',\r
+               'Jūl','Aug','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['svētdiena','pirmdiena','otrdiena','trešdiena','ceturtdiena','piektdiena','sestdiena'],\r
+               dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'],\r
+               dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'],\r
+               dateFormat: 'dd-mm-yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['lv']);\r
+});/* Malaysian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */\r
+jQuery(function($){\r
+       $.datepicker.regional['ms'] = {\r
+               closeText: 'Tutup',\r
+               prevText: '&#x3c;Sebelum',\r
+               nextText: 'Selepas&#x3e;',\r
+               currentText: 'hari ini',\r
+               monthNames: ['Januari','Februari','Mac','April','Mei','Jun',\r
+               'Julai','Ogos','September','Oktober','November','Disember'],\r
+               monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun',\r
+               'Jul','Ogo','Sep','Okt','Nov','Dis'],\r
+               dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'],\r
+               dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'],\r
+               dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['ms']);\r
+});/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Mathias Bynens <http://mathiasbynens.be/> */\r
+jQuery(function($){\r
+       $.datepicker.regional.nl = {\r
+               closeText: 'Sluiten',\r
+               prevText: '←',\r
+               nextText: '→',\r
+               currentText: 'Vandaag',\r
+               monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni',\r
+               'juli', 'augustus', 'september', 'oktober', 'november', 'december'],\r
+               monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun',\r
+               'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\r
+               dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],\r
+               dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'],\r
+               dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional.nl);\r
+});/* Norwegian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Naimdjon Takhirov (naimdjon@gmail.com). */\r
+jQuery(function($){\r
+    $.datepicker.regional['no'] = {\r
+               closeText: 'Lukk',\r
+        prevText: '&laquo;Forrige',\r
+               nextText: 'Neste&raquo;',\r
+               currentText: 'I dag',\r
+        monthNames: ['Januar','Februar','Mars','April','Mai','Juni',\r
+        'Juli','August','September','Oktober','November','Desember'],\r
+        monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jun',\r
+        'Jul','Aug','Sep','Okt','Nov','Des'],\r
+               dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'],\r
+               dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'],\r
+               dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],\r
+        dateFormat: 'yy-mm-dd', firstDay: 0,\r
+               isRTL: false};\r
+    $.datepicker.setDefaults($.datepicker.regional['no']);\r
+});\r
+/* Polish initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['pl'] = {\r
+               closeText: 'Zamknij',\r
+               prevText: '&#x3c;Poprzedni',\r
+               nextText: 'Następny&#x3e;',\r
+               currentText: 'Dziś',\r
+               monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec',\r
+               'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'],\r
+               monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze',\r
+               'Lip','Sie','Wrz','Pa','Lis','Gru'],\r
+               dayNames: ['Niedziela','Poniedzialek','Wtorek','Środa','Czwartek','Piątek','Sobota'],\r
+               dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'],\r
+               dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'],\r
+               dateFormat: 'yy-mm-dd', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['pl']);\r
+});\r
+/* Brazilian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Leonildo Costa Silva (leocsilva@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['pt-BR'] = {\r
+               closeText: 'Fechar',\r
+               prevText: '&#x3c;Anterior',\r
+               nextText: 'Pr&oacute;ximo&#x3e;',\r
+               currentText: 'Hoje',\r
+               monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho',\r
+               'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],\r
+               monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun',\r
+               'Jul','Ago','Set','Out','Nov','Dez'],\r
+               dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sabado'],\r
+               dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'],\r
+               dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['pt-BR']);\r
+});/* Romanian initialisation for the jQuery UI date picker plugin.\r
+ *\r
+ * Written by Edmond L. (ll_edmond@walla.com)\r
+ * and Ionut G. Stan (ionut.g.stan@gmail.com)\r
+ */\r
+jQuery(function($){\r
+       $.datepicker.regional['ro'] = {\r
+               closeText: 'Închide',\r
+               prevText: '&laquo; Luna precedentă',\r
+               nextText: 'Luna următoare &raquo;',\r
+               currentText: 'Azi',\r
+               monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie',\r
+               'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'],\r
+               monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun',\r
+               'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\r
+               dayNames: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'],\r
+               dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'],\r
+               dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'],\r
+               dateFormat: 'dd MM yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['ro']);\r
+});\r
+/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Andrew Stromnov (stromnov@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['ru'] = {\r
+               closeText: 'Закрыть',\r
+               prevText: '&#x3c;Пред',\r
+               nextText: 'След&#x3e;',\r
+               currentText: 'Сегодня',\r
+               monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь',\r
+               'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],\r
+               monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн',\r
+               'Июл','Авг','Сен','Окт','Ноя','Дек'],\r
+               dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'],\r
+               dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'],\r
+               dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['ru']);\r
+});/* Slovak initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Vojtech Rinik (vojto@hmm.sk). */\r
+jQuery(function($){\r
+       $.datepicker.regional['sk'] = {\r
+               closeText: 'Zavrieť',\r
+               prevText: '&#x3c;Predchádzajúci',\r
+               nextText: 'Nasledujúci&#x3e;',\r
+               currentText: 'Dnes',\r
+               monthNames: ['Január','Február','Marec','Apríl','Máj','Jún',\r
+               'Júl','August','September','Október','November','December'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún',\r
+               'Júl','Aug','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['Nedel\'a','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota'],\r
+               dayNamesShort: ['Ned','Pon','Uto','Str','Štv','Pia','Sob'],\r
+               dayNamesMin: ['Ne','Po','Ut','St','Št','Pia','So'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sk']);\r
+});\r
+/* Slovenian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Jaka Jancar (jaka@kubje.org). */\r
+/* c = &#x10D;, s = &#x161; z = &#x17E; C = &#x10C; S = &#x160; Z = &#x17D; */\r
+jQuery(function($){\r
+       $.datepicker.regional['sl'] = {\r
+               closeText: 'Zapri',\r
+               prevText: '&lt;Prej&#x161;nji',\r
+               nextText: 'Naslednji&gt;',\r
+               currentText: 'Trenutni',\r
+               monthNames: ['Januar','Februar','Marec','April','Maj','Junij',\r
+               'Julij','Avgust','September','Oktober','November','December'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',\r
+               'Jul','Avg','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','&#x10C;etrtek','Petek','Sobota'],\r
+               dayNamesShort: ['Ned','Pon','Tor','Sre','&#x10C;et','Pet','Sob'],\r
+               dayNamesMin: ['Ne','Po','To','Sr','&#x10C;e','Pe','So'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sl']);\r
+});\r
+/* Albanian initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Flakron Bytyqi (flakron@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['sq'] = {\r
+               closeText: 'mbylle',\r
+               prevText: '&#x3c;mbrapa',\r
+               nextText: 'Përpara&#x3e;',\r
+               currentText: 'sot',\r
+               monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor',\r
+               'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'],\r
+               monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer',\r
+               'Kor','Gus','Sht','Tet','Nën','Dhj'],\r
+               dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'],\r
+               dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'],\r
+               dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sq']);\r
+});\r
+/* Serbian i18n for the jQuery UI date picker plugin. */\r
+/* Written by Dejan Dimić. */\r
+jQuery(function($){\r
+       $.datepicker.regional['sr-SR'] = {\r
+               closeText: 'Zatvori',\r
+               prevText: '&#x3c;',\r
+               nextText: '&#x3e;',\r
+               currentText: 'Danas',\r
+               monthNames: ['Januar','Februar','Mart','April','Maj','Jun',\r
+               'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',\r
+               'Jul','Avg','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'],\r
+               dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'],\r
+               dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sr-SR']);\r
+});
+/* Serbian i18n for the jQuery UI date picker plugin. */\r
+/* Written by Dejan Dimić. */\r
+jQuery(function($){\r
+       $.datepicker.regional['sr'] = {\r
+               closeText: 'Затвори',\r
+               prevText: '&#x3c;',\r
+               nextText: '&#x3e;',\r
+               currentText: 'Данас',\r
+               monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун',\r
+               'Јул','Август','Септембар','Октобар','Новембар','Децембар'],\r
+               monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун',\r
+               'Јул','Авг','Сеп','Окт','Нов','Дец'],\r
+               dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'],\r
+               dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'],\r
+               dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sr']);\r
+});
+/* Swedish initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Anders Ekdahl ( anders@nomadiz.se). */\r
+jQuery(function($){\r
+    $.datepicker.regional['sv'] = {\r
+               closeText: 'Stäng',\r
+        prevText: '&laquo;Förra',\r
+               nextText: 'Nästa&raquo;',\r
+               currentText: 'Idag',\r
+        monthNames: ['Januari','Februari','Mars','April','Maj','Juni',\r
+        'Juli','Augusti','September','Oktober','November','December'],\r
+        monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',\r
+        'Jul','Aug','Sep','Okt','Nov','Dec'],\r
+               dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'],\r
+               dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'],\r
+               dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'],\r
+        dateFormat: 'yy-mm-dd', firstDay: 1,\r
+               isRTL: false};\r
+    $.datepicker.setDefaults($.datepicker.regional['sv']);\r
+});\r
+/* Thai initialisation for the jQuery UI date picker plugin. */\r
+/* Written by pipo (pipo@sixhead.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['th'] = {\r
+               closeText: 'ปิด',\r
+               prevText: '&laquo;&nbsp;ย้อน',\r
+               nextText: 'ถัดไป&nbsp;&raquo;',\r
+               currentText: 'วันนี้',\r
+               monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน',\r
+               'กรกฏาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'],\r
+               monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.',\r
+               'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'],\r
+               dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'],\r
+               dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'],\r
+               dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 0,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['th']);\r
+});/* Turkish initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Izzet Emre Erkan (kara@karalamalar.net). */\r
+jQuery(function($){\r
+       $.datepicker.regional['tr'] = {\r
+               closeText: 'kapat',\r
+               prevText: '&#x3c;geri',\r
+               nextText: 'ileri&#x3e',\r
+               currentText: 'bugün',\r
+               monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran',\r
+               'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'],\r
+               monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz',\r
+               'Tem','Ağu','Eyl','Eki','Kas','Ara'],\r
+               dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'],\r
+               dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'],\r
+               dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'],\r
+               dateFormat: 'dd.mm.yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['tr']);\r
+});/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Maxim Drogobitskiy (maxdao@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['uk'] = {\r
+               clearText: 'Очистити', clearStatus: '',\r
+               closeText: 'Закрити', closeStatus: '',\r
+               prevText: '&#x3c;',  prevStatus: '',\r
+               prevBigText: '&#x3c;&#x3c;', prevBigStatus: '',\r
+               nextText: '&#x3e;', nextStatus: '',\r
+               nextBigText: '&#x3e;&#x3e;', nextBigStatus: '',\r
+               currentText: 'Сьогодні', currentStatus: '',\r
+               monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень',\r
+               'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'],\r
+               monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер',\r
+               'Лип','Сер','Вер','Жов','Лис','Гру'],\r
+               monthStatus: '', yearStatus: '',\r
+               weekHeader: 'Не', weekStatus: '',\r
+               dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'],\r
+               dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'],\r
+               dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'],\r
+               dayStatus: 'DD', dateStatus: 'D, M d',\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               initStatus: '', isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['uk']);\r
+});/* Chinese initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Cloudream (cloudream@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['zh-CN'] = {\r
+               closeText: '关闭',\r
+               prevText: '&#x3c;上月',\r
+               nextText: '下月&#x3e;',\r
+               currentText: '今天',\r
+               monthNames: ['一月','二月','三月','四月','五月','六月',\r
+               '七月','八月','九月','十月','十一月','十二月'],\r
+               monthNamesShort: ['一','二','三','四','五','六',\r
+               '七','八','九','十','十一','十二'],\r
+               dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],\r
+               dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'],\r
+               dayNamesMin: ['日','一','二','三','四','五','六'],\r
+               dateFormat: 'yy-mm-dd', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['zh-CN']);\r
+});\r
+/* Chinese initialisation for the jQuery UI date picker plugin. */\r
+/* Written by Ressol (ressol@gmail.com). */\r
+jQuery(function($){\r
+       $.datepicker.regional['zh-TW'] = {\r
+               closeText: '關閉',\r
+               prevText: '&#x3c;上月',\r
+               nextText: '下月&#x3e;',\r
+               currentText: '今天',\r
+               monthNames: ['一月','二月','三月','四月','五月','六月',\r
+               '七月','八月','九月','十月','十一月','十二月'],\r
+               monthNamesShort: ['一','二','三','四','五','六',\r
+               '七','八','九','十','十一','十二'],\r
+               dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],\r
+               dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'],\r
+               dayNamesMin: ['日','一','二','三','四','五','六'],\r
+               dateFormat: 'yy/mm/dd', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['zh-TW']);\r
+});\r
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ar.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ar.js
new file mode 100644 (file)
index 0000000..b605878
--- /dev/null
@@ -0,0 +1,20 @@
+/* Arabic Translation for jQuery UI date picker plugin. */
+/* Khaled Al Horani -- koko.dw@gmail.com */
+/* خالد الحوراني -- koko.dw@gmail.com */
+/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */
+jQuery(function($){
+       $.datepicker.regional['ar'] = {
+               closeText: 'إغلاق',
+               prevText: '&#x3c;السابق',
+               nextText: 'التالي&#x3e;',
+               currentText: 'اليوم',
+               monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران',
+               'تموز', 'آب', 'أيلول',       'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],
+               monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
+               dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'],
+               dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],
+               dayNamesMin: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+  isRTL: true};
+       $.datepicker.setDefaults($.datepicker.regional['ar']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-bg.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-bg.js
new file mode 100644 (file)
index 0000000..a73884e
--- /dev/null
@@ -0,0 +1,20 @@
+/* Bulgarian initialisation for the jQuery UI date picker plugin. */
+/* Written by Stoyan Kyosev (http://svest.org). */
+jQuery(function($){
+    $.datepicker.regional['bg'] = {
+        closeText: 'затвори',
+        prevText: '&#x3c;назад',
+        nextText: 'напред&#x3e;',
+               nextBigText: '&#x3e;&#x3e;',
+        currentText: 'днес',
+        monthNames: ['Януари','Февруари','Март','Април','Май','Юни',
+        'Юли','Август','Септември','Октомври','Ноември','Декември'],
+        monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни',
+        'Юли','Авг','Сеп','Окт','Нов','Дек'],
+        dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'],
+        dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'],
+        dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'],
+        dateFormat: 'dd.mm.yy', firstDay: 1,
+        isRTL: false};
+    $.datepicker.setDefaults($.datepicker.regional['bg']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ca.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ca.js
new file mode 100644 (file)
index 0000000..ad47af0
--- /dev/null
@@ -0,0 +1,19 @@
+/* Inicialitzaci� en catal� per a l'extenci� 'calendar' per jQuery. */
+/* Writers: (joan.leon@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['ca'] = {
+               closeText: 'Tancar',
+               prevText: '&#x3c;Ant',
+               nextText: 'Seg&#x3e;',
+               currentText: 'Avui',
+               monthNames: ['Gener','Febrer','Mar&ccedil;','Abril','Maig','Juny',
+               'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'],
+               monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun',
+               'Jul','Ago','Set','Oct','Nov','Des'],
+               dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'],
+               dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'],
+               dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'],
+               dateFormat: 'mm/dd/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['ca']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-cs.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-cs.js
new file mode 100644 (file)
index 0000000..334ae2f
--- /dev/null
@@ -0,0 +1,19 @@
+/* Czech initialisation for the jQuery UI date picker plugin. */
+/* Written by Tomas Muller (tomas@tomas-muller.net). */
+jQuery(function($){
+       $.datepicker.regional['cs'] = {
+               closeText: 'Zavřít',
+               prevText: '&#x3c;Dříve',
+               nextText: 'Později&#x3e;',
+               currentText: 'Nyní',
+               monthNames: ['leden','únor','březen','duben','květen','červen',
+        'červenec','srpen','září','říjen','listopad','prosinec'],
+               monthNamesShort: ['led','úno','bře','dub','kvě','čer',
+               'čvc','srp','zář','říj','lis','pro'],
+               dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'],
+               dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'],
+               dayNamesMin: ['ne','po','út','st','čt','pá','so'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['cs']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-da.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-da.js
new file mode 100644 (file)
index 0000000..8ad1e2c
--- /dev/null
@@ -0,0 +1,19 @@
+/* Danish initialisation for the jQuery UI date picker plugin. */
+/* Written by Jan Christensen ( deletestuff@gmail.com). */
+jQuery(function($){
+    $.datepicker.regional['da'] = {
+               closeText: 'Luk',
+        prevText: '&#x3c;Forrige',
+               nextText: 'Næste&#x3e;',
+               currentText: 'Idag',
+        monthNames: ['Januar','Februar','Marts','April','Maj','Juni',
+        'Juli','August','September','Oktober','November','December'],
+        monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',
+        'Jul','Aug','Sep','Okt','Nov','Dec'],
+               dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'],
+               dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'],
+               dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],
+        dateFormat: 'dd-mm-yy', firstDay: 0,
+               isRTL: false};
+    $.datepicker.setDefaults($.datepicker.regional['da']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-de.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-de.js
new file mode 100644 (file)
index 0000000..f9299c8
--- /dev/null
@@ -0,0 +1,19 @@
+/* German initialisation for the jQuery UI date picker plugin. */
+/* Written by Milian Wolff (mail@milianw.de). */
+jQuery(function($){
+       $.datepicker.regional['de'] = {
+               closeText: 'schließen',
+               prevText: '&#x3c;zurück',
+               nextText: 'Vor&#x3e;',
+               currentText: 'heute',
+               monthNames: ['Januar','Februar','März','April','Mai','Juni',
+               'Juli','August','September','Oktober','November','Dezember'],
+               monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
+               'Jul','Aug','Sep','Okt','Nov','Dez'],
+               dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
+               dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
+               dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['de']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-el.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-el.js
new file mode 100644 (file)
index 0000000..535080d
--- /dev/null
@@ -0,0 +1,19 @@
+/* Greek (el) initialisation for the jQuery UI date picker plugin. */
+/* Written by Alex Cicovic (http://www.alexcicovic.com) */
+jQuery(function($){
+       $.datepicker.regional['el'] = {
+               closeText: 'Κλείσιμο',
+               prevText: 'Προηγούμενος',
+               nextText: 'Επόμενος',
+               currentText: 'Τρέχων Μήνας',
+               monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος',
+               'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'],
+               monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν',
+               'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'],
+               dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'],
+               dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'],
+               dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'],
+               dateFormat: 'dd/mm/yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['el']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-eo.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-eo.js
new file mode 100644 (file)
index 0000000..28abac4
--- /dev/null
@@ -0,0 +1,19 @@
+/* Esperanto initialisation for the jQuery UI date picker plugin. */
+/* Written by Olivier M. (olivierweb@ifrance.com). */
+jQuery(function($){
+       $.datepicker.regional['eo'] = {
+               closeText: 'Fermi',
+               prevText: '&lt;Anta',
+               nextText: 'Sekv&gt;',
+               currentText: 'Nuna',
+               monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio',
+               'Julio','Aŭgusto','Septembro','Oktobro','Novembro','Decembro'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',
+               'Jul','Aŭg','Sep','Okt','Nov','Dec'],
+               dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ĵaŭdo','Vendredo','Sabato'],
+               dayNamesShort: ['Dim','Lun','Mar','Mer','Ĵaŭ','Ven','Sab'],
+               dayNamesMin: ['Di','Lu','Ma','Me','Ĵa','Ve','Sa'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['eo']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-es.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-es.js
new file mode 100644 (file)
index 0000000..0a699af
--- /dev/null
@@ -0,0 +1,19 @@
+/* Inicializaci�n en espa�ol para la extensi�n 'UI date picker' para jQuery. */
+/* Traducido por Vester (xvester@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['es'] = {
+               closeText: 'Cerrar',
+               prevText: '&#x3c;Ant',
+               nextText: 'Sig&#x3e;',
+               currentText: 'Hoy',
+               monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio',
+               'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],
+               monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun',
+               'Jul','Ago','Sep','Oct','Nov','Dic'],
+               dayNames: ['Domingo','Lunes','Martes','Mi&eacute;rcoles','Jueves','Viernes','S&aacute;bado'],
+               dayNamesShort: ['Dom','Lun','Mar','Mi&eacute;','Juv','Vie','S&aacute;b'],
+               dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','S&aacute;'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['es']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fa.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fa.js
new file mode 100644 (file)
index 0000000..e40e1ac
--- /dev/null
@@ -0,0 +1,19 @@
+/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */
+/* Javad Mowlanezhad -- jmowla@gmail.com */
+/* Jalali calendar should supported soon! (Its implemented but I have to test it) */
+jQuery(function($) {
+       $.datepicker.regional['fa'] = {
+               closeText: 'بستن',
+               prevText: '&#x3c;قبلي',
+               nextText: 'بعدي&#x3e;',
+               currentText: 'امروز',
+               monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور',
+               'مهر','آبان','آذر','دي','بهمن','اسفند'],
+               monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
+               dayNames: ['يکشنبه','دوشنبه','سه‌شنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'],
+               dayNamesShort: ['ي','د','س','چ','پ','ج', 'ش'],
+               dayNamesMin: ['ي','د','س','چ','پ','ج', 'ش'],
+               dateFormat: 'yy/mm/dd', firstDay: 6,
+  isRTL: true};
+       $.datepicker.setDefaults($.datepicker.regional['fa']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fi.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fi.js
new file mode 100644 (file)
index 0000000..980e0bb
--- /dev/null
@@ -0,0 +1,19 @@
+/* Finnish initialisation for the jQuery UI date picker plugin. */
+/* Written by Harri Kilpi� (harrikilpio@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['fi'] = {
+               closeText: 'Sulje',
+               prevText: '&laquo;Edellinen',
+               nextText: 'Seuraava&raquo;',
+               currentText: 'T&auml;n&auml;&auml;n',
+               monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kes&auml;kuu',
+               'Hein&auml;kuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'],
+               monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kes&auml;',
+               'Hein&auml;','Elo','Syys','Loka','Marras','Joulu'],
+               dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','Su'],
+               dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'],
+               dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['fi']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fr.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-fr.js
new file mode 100644 (file)
index 0000000..02edda2
--- /dev/null
@@ -0,0 +1,19 @@
+/* French initialisation for the jQuery UI date picker plugin. */
+/* Written by Keith Wood (kbwood@virginbroadband.com.au) and Stéphane Nahmani (sholby@sholby.net). */
+jQuery(function($){
+       $.datepicker.regional['fr'] = {
+               closeText: 'Fermer',
+               prevText: '&#x3c;Préc',
+               nextText: 'Suiv&#x3e;',
+               currentText: 'Courant',
+               monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin',
+               'Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
+               monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun',
+               'Jul','Aoû','Sep','Oct','Nov','Déc'],
+               dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
+               dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'],
+               dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'],
+               dateFormat: 'dd/mm/yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['fr']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-he.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-he.js
new file mode 100644 (file)
index 0000000..38e0a03
--- /dev/null
@@ -0,0 +1,19 @@
+/* Hebrew initialisation for the UI Datepicker extension. */
+/* Written by Amir Hardon (ahardon at gmail dot com). */
+jQuery(function($){
+       $.datepicker.regional['he'] = {
+               closeText: 'סגור',
+               prevText: '&#x3c;הקודם',
+               nextText: 'הבא&#x3e;',
+               currentText: 'היום',
+               monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני',
+               'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'],
+               monthNamesShort: ['1','2','3','4','5','6',
+               '7','8','9','10','11','12'],
+               dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'],
+               dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'],
+               dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: true};
+       $.datepicker.setDefaults($.datepicker.regional['he']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hr.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hr.js
new file mode 100644 (file)
index 0000000..78e4006
--- /dev/null
@@ -0,0 +1,19 @@
+/* Croatian i18n for the jQuery UI date picker plugin. */
+/* Written by Vjekoslav Nesek. */
+jQuery(function($){
+       $.datepicker.regional['hr'] = {
+               closeText: 'Zatvori',
+               prevText: '&#x3c;',
+               nextText: '&#x3e;',
+               currentText: 'Danas',
+               monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipani',
+               'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'],
+               monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip',
+               'Srp','Kol','Ruj','Lis','Stu','Pro'],
+               dayNames: ['Nedjalja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'],
+               dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'],
+               dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'],
+               dateFormat: 'dd.mm.yy.', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['hr']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hu.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hu.js
new file mode 100644 (file)
index 0000000..ee102ac
--- /dev/null
@@ -0,0 +1,19 @@
+/* Hungarian initialisation for the jQuery UI date picker plugin. */
+/* Written by Istvan Karaszi (jquerycalendar@spam.raszi.hu). */
+jQuery(function($){
+       $.datepicker.regional['hu'] = {
+               closeText: 'bezárás',
+               prevText: '&laquo;&nbsp;vissza',
+               nextText: 'előre&nbsp;&raquo;',
+               currentText: 'ma',
+               monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június',
+               'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'],
+               monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún',
+               'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'],
+               dayNames: ['Vasámap', 'Hétfö', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'],
+               dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'],
+               dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'],
+               dateFormat: 'yy-mm-dd', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['hu']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hy.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-hy.js
new file mode 100644 (file)
index 0000000..1ffbeaa
--- /dev/null
@@ -0,0 +1,19 @@
+/* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */
+/* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/
+jQuery(function($){
+       $.datepicker.regional['hy'] = {
+               closeText: 'Փակել',
+               prevText: '&#x3c;Նախ.',
+               nextText: 'Հաջ.&#x3e;',
+               currentText: 'Այսօր',
+               monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս',
+               'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'],
+               monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս',
+               'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Դեկ'],
+               dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','հինգշաբթի','ուրբաթ','շաբաթ'],
+               dayNamesShort: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'],
+               dayNamesMin: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['hy']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-id.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-id.js
new file mode 100644 (file)
index 0000000..e5246c8
--- /dev/null
@@ -0,0 +1,19 @@
+/* Indonesian initialisation for the jQuery UI date picker plugin. */
+/* Written by Deden Fathurahman (dedenf@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['id'] = {
+               closeText: 'Tutup',
+               prevText: '&#x3c;mundur',
+               nextText: 'maju&#x3e;',
+               currentText: 'hari ini',
+               monthNames: ['Januari','Februari','Maret','April','Mei','Juni',
+               'Juli','Agustus','September','Oktober','Nopember','Desember'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun',
+               'Jul','Agus','Sep','Okt','Nop','Des'],
+               dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'],
+               dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'],
+               dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['id']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-is.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-is.js
new file mode 100644 (file)
index 0000000..68c1a07
--- /dev/null
@@ -0,0 +1,19 @@
+/* Icelandic initialisation for the jQuery UI date picker plugin. */
+/* Written by Haukur H. Thorsson (haukur@eskill.is). */
+jQuery(function($){
+       $.datepicker.regional['is'] = {
+               closeText: 'Loka',
+               prevText: '&#x3c; Fyrri',
+               nextText: 'N&aelig;sti &#x3e;',
+               currentText: '&Iacute; dag',
+               monthNames: ['Jan&uacute;ar','Febr&uacute;ar','Mars','Apr&iacute;l','Ma&iacute','J&uacute;n&iacute;',
+               'J&uacute;l&iacute;','&Aacute;g&uacute;st','September','Okt&oacute;ber','N&oacute;vember','Desember'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Ma&iacute;','J&uacute;n',
+               'J&uacute;l','&Aacute;g&uacute;','Sep','Okt','N&oacute;v','Des'],
+               dayNames: ['Sunnudagur','M&aacute;nudagur','&THORN;ri&eth;judagur','Mi&eth;vikudagur','Fimmtudagur','F&ouml;studagur','Laugardagur'],
+               dayNamesShort: ['Sun','M&aacute;n','&THORN;ri','Mi&eth;','Fim','F&ouml;s','Lau'],
+               dayNamesMin: ['Su','M&aacute;','&THORN;r','Mi','Fi','F&ouml;','La'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['is']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-it.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-it.js
new file mode 100644 (file)
index 0000000..f3e691e
--- /dev/null
@@ -0,0 +1,19 @@
+/* Italian initialisation for the jQuery UI date picker plugin. */
+/* Written by Apaella (apaella@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['it'] = {
+               closeText: 'Chiudi',
+               prevText: '&#x3c;Prec',
+               nextText: 'Succ&#x3e;',
+               currentText: 'Oggi',
+               monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno',
+               'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'],
+               monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu',
+               'Lug','Ago','Set','Ott','Nov','Dic'],
+               dayNames: ['Domenica','Luned&#236','Marted&#236','Mercoled&#236','Gioved&#236','Venerd&#236','Sabato'],
+               dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'],
+               dayNamesMin: ['Do','Lu','Ma','Me','Gio','Ve','Sa'],
+               dateFormat: 'dd/mm/yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['it']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ja.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ja.js
new file mode 100644 (file)
index 0000000..a6a5f45
--- /dev/null
@@ -0,0 +1,20 @@
+/* Japanese initialisation for the jQuery UI date picker plugin. */
+/* Written by Kentaro SATO (kentaro@ranvis.com). */
+jQuery(function($){
+       $.datepicker.regional['ja'] = {
+               closeText: '閉じる',
+               prevText: '&#x3c;前',
+               nextText: '次&#x3e;',
+               currentText: '今日',
+               monthNames: ['1月','2月','3月','4月','5月','6月',
+               '7月','8月','9月','10月','11月','12月'],
+               monthNamesShort: ['1月','2月','3月','4月','5月','6月',
+               '7月','8月','9月','10月','11月','12月'],
+               dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'],
+               dayNamesShort: ['日','月','火','水','木','金','土'],
+               dayNamesMin: ['日','月','火','水','木','金','土'],
+               dateFormat: 'yy/mm/dd', firstDay: 0,
+               isRTL: false,
+               showMonthAfterYear: true};
+       $.datepicker.setDefaults($.datepicker.regional['ja']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ko.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ko.js
new file mode 100644 (file)
index 0000000..53ede91
--- /dev/null
@@ -0,0 +1,19 @@
+/* Korean initialisation for the jQuery calendar extension. */
+/* Written by DaeKwon Kang (ncrash.dk@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['ko'] = {
+               closeText: '닫기',
+               prevText: '이전달',
+               nextText: '다음달',
+               currentText: '오늘',
+               monthNames: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)',
+               '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'],
+               monthNamesShort: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)',
+               '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'],
+               dayNames: ['일','월','화','수','목','금','토'],
+               dayNamesShort: ['일','월','화','수','목','금','토'],
+               dayNamesMin: ['일','월','화','수','목','금','토'],
+               dateFormat: 'yy-mm-dd', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['ko']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-lt.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-lt.js
new file mode 100644 (file)
index 0000000..a8a6aa1
--- /dev/null
@@ -0,0 +1,19 @@
+/* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */
+/* @author Arturas Paleicikas <arturas@avalon.lt> */
+jQuery(function($){
+       $.datepicker.regional['lt'] = {
+               closeText: 'Uždaryti',
+               prevText: '&#x3c;Atgal',
+               nextText: 'Pirmyn&#x3e;',
+               currentText: 'Šiandien',
+               monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis',
+               'Liepa','Rugpjūtis','Rugsėjis','Spalis','Lapkritis','Gruodis'],
+               monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir',
+               'Lie','Rugp','Rugs','Spa','Lap','Gru'],
+               dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'],
+               dayNamesShort: ['sek','pir','ant','tre','ket','pen','šeš'],
+               dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Še'],
+               dateFormat: 'yy-mm-dd', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['lt']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-lv.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-lv.js
new file mode 100644 (file)
index 0000000..12c32f8
--- /dev/null
@@ -0,0 +1,19 @@
+/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */
+/* @author Arturas Paleicikas <arturas.paleicikas@metasite.net> */
+jQuery(function($){
+       $.datepicker.regional['lv'] = {
+               closeText: 'Aizvērt',
+               prevText: 'Iepr',
+               nextText: 'Nāka',
+               currentText: 'Šodien',
+               monthNames: ['Janvāris','Februāris','Marts','Aprīlis','Maijs','Jūnijs',
+               'Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jūn',
+               'Jūl','Aug','Sep','Okt','Nov','Dec'],
+               dayNames: ['svētdiena','pirmdiena','otrdiena','trešdiena','ceturtdiena','piektdiena','sestdiena'],
+               dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'],
+               dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'],
+               dateFormat: 'dd-mm-yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['lv']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ms.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ms.js
new file mode 100644 (file)
index 0000000..fa25305
--- /dev/null
@@ -0,0 +1,19 @@
+/* Malaysian initialisation for the jQuery UI date picker plugin. */
+/* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */
+jQuery(function($){
+       $.datepicker.regional['ms'] = {
+               closeText: 'Tutup',
+               prevText: '&#x3c;Sebelum',
+               nextText: 'Selepas&#x3e;',
+               currentText: 'hari ini',
+               monthNames: ['Januari','Februari','Mac','April','Mei','Jun',
+               'Julai','Ogos','September','Oktober','November','Disember'],
+               monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun',
+               'Jul','Ogo','Sep','Okt','Nov','Dis'],
+               dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'],
+               dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'],
+               dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['ms']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-nl.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-nl.js
new file mode 100644 (file)
index 0000000..938dc5e
--- /dev/null
@@ -0,0 +1,19 @@
+/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */
+/* Written by Mathias Bynens <http://mathiasbynens.be/> */
+jQuery(function($){
+       $.datepicker.regional.nl = {
+               closeText: 'Sluiten',
+               prevText: '←',
+               nextText: '→',
+               currentText: 'Vandaag',
+               monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni',
+               'juli', 'augustus', 'september', 'oktober', 'november', 'december'],
+               monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun',
+               'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],
+               dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],
+               dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'],
+               dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],
+               dateFormat: 'dd/mm/yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional.nl);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-no.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-no.js
new file mode 100644 (file)
index 0000000..efe5b0d
--- /dev/null
@@ -0,0 +1,19 @@
+/* Norwegian initialisation for the jQuery UI date picker plugin. */
+/* Written by Naimdjon Takhirov (naimdjon@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['no'] = {
+               closeText: 'Lukk',
+               prevText: '&laquo;Forrige',
+               nextText: 'Neste&raquo;',
+               currentText: 'I dag',
+               monthNames: ['Januar','Februar','Mars','April','Mai','Juni',
+               'Juli','August','September','Oktober','November','Desember'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jun',
+               'Jul','Aug','Sep','Okt','Nov','Des'],
+               dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'],
+               dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'],
+               dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],
+               dateFormat: 'yy-mm-dd', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['no']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-pl.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-pl.js
new file mode 100644 (file)
index 0000000..0ce38be
--- /dev/null
@@ -0,0 +1,19 @@
+/* Polish initialisation for the jQuery UI date picker plugin. */
+/* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['pl'] = {
+               closeText: 'Zamknij',
+               prevText: '&#x3c;Poprzedni',
+               nextText: 'Następny&#x3e;',
+               currentText: 'Dziś',
+               monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec',
+               'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'],
+               monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze',
+               'Lip','Sie','Wrz','Pa','Lis','Gru'],
+               dayNames: ['Niedziela','Poniedzialek','Wtorek','Środa','Czwartek','Piątek','Sobota'],
+               dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'],
+               dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'],
+               dateFormat: 'yy-mm-dd', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['pl']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-pt-BR.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-pt-BR.js
new file mode 100644 (file)
index 0000000..e3ac652
--- /dev/null
@@ -0,0 +1,19 @@
+/* Brazilian initialisation for the jQuery UI date picker plugin. */
+/* Written by Leonildo Costa Silva (leocsilva@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['pt-BR'] = {
+               closeText: 'Fechar',
+               prevText: '&#x3c;Anterior',
+               nextText: 'Pr&oacute;ximo&#x3e;',
+               currentText: 'Hoje',
+               monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho',
+               'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
+               monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun',
+               'Jul','Ago','Set','Out','Nov','Dez'],
+               dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sabado'],
+               dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'],
+               dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['pt-BR']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ro.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ro.js
new file mode 100644 (file)
index 0000000..ec4033c
--- /dev/null
@@ -0,0 +1,22 @@
+/* Romanian initialisation for the jQuery UI date picker plugin.
+ *
+ * Written by Edmond L. (ll_edmond@walla.com)
+ * and Ionut G. Stan (ionut.g.stan@gmail.com)
+ */
+jQuery(function($){
+       $.datepicker.regional['ro'] = {
+               closeText: 'Închide',
+               prevText: '&laquo; Luna precedentă',
+               nextText: 'Luna următoare &raquo;',
+               currentText: 'Azi',
+               monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie',
+               'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'],
+               monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun',
+               'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+               dayNames: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'],
+               dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'],
+               dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'],
+               dateFormat: 'dd MM yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['ro']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ru.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-ru.js
new file mode 100644 (file)
index 0000000..62752c7
--- /dev/null
@@ -0,0 +1,19 @@
+/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */
+/* Written by Andrew Stromnov (stromnov@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['ru'] = {
+               closeText: 'Закрыть',
+               prevText: '&#x3c;Пред',
+               nextText: 'След&#x3e;',
+               currentText: 'Сегодня',
+               monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь',
+               'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
+               monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн',
+               'Июл','Авг','Сен','Окт','Ноя','Дек'],
+               dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'],
+               dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'],
+               dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['ru']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sk.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sk.js
new file mode 100644 (file)
index 0000000..a023ffa
--- /dev/null
@@ -0,0 +1,19 @@
+/* Slovak initialisation for the jQuery UI date picker plugin. */
+/* Written by Vojtech Rinik (vojto@hmm.sk). */
+jQuery(function($){
+       $.datepicker.regional['sk'] = {
+               closeText: 'Zavrieť',
+               prevText: '&#x3c;Predchádzajúci',
+               nextText: 'Nasledujúci&#x3e;',
+               currentText: 'Dnes',
+               monthNames: ['Január','Február','Marec','Apríl','Máj','Jún',
+               'Júl','August','September','Október','November','December'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún',
+               'Júl','Aug','Sep','Okt','Nov','Dec'],
+               dayNames: ['Nedel\'a','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota'],
+               dayNamesShort: ['Ned','Pon','Uto','Str','Štv','Pia','Sob'],
+               dayNamesMin: ['Ne','Po','Ut','St','Št','Pia','So'],
+               dateFormat: 'dd.mm.yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['sk']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sl.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sl.js
new file mode 100644 (file)
index 0000000..480a4d8
--- /dev/null
@@ -0,0 +1,20 @@
+/* Slovenian initialisation for the jQuery UI date picker plugin. */
+/* Written by Jaka Jancar (jaka@kubje.org). */
+/* c = &#x10D;, s = &#x161; z = &#x17E; C = &#x10C; S = &#x160; Z = &#x17D; */
+jQuery(function($){
+       $.datepicker.regional['sl'] = {
+               closeText: 'Zapri',
+               prevText: '&lt;Prej&#x161;nji',
+               nextText: 'Naslednji&gt;',
+               currentText: 'Trenutni',
+               monthNames: ['Januar','Februar','Marec','April','Maj','Junij',
+               'Julij','Avgust','September','Oktober','November','December'],
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',
+               'Jul','Avg','Sep','Okt','Nov','Dec'],
+               dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','&#x10C;etrtek','Petek','Sobota'],
+               dayNamesShort: ['Ned','Pon','Tor','Sre','&#x10C;et','Pet','Sob'],
+               dayNamesMin: ['Ne','Po','To','Sr','&#x10C;e','Pe','So'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['sl']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sq.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sq.js
new file mode 100644 (file)
index 0000000..ac67e68
--- /dev/null
@@ -0,0 +1,19 @@
+/* Albanian initialisation for the jQuery UI date picker plugin. */
+/* Written by Flakron Bytyqi (flakron@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['sq'] = {
+               closeText: 'mbylle',
+               prevText: '&#x3c;mbrapa',
+               nextText: 'Përpara&#x3e;',
+               currentText: 'sot',
+               monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor',
+               'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'],
+               monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer',
+               'Kor','Gus','Sht','Tet','Nën','Dhj'],
+               dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'],
+               dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'],
+               dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['sq']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sr-SR.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sr-SR.js
new file mode 100644 (file)
index 0000000..059fc38
--- /dev/null
@@ -0,0 +1,19 @@
+/* Serbian i18n for the jQuery UI date picker plugin. */\r
+/* Written by Dejan Dimić. */\r
+jQuery(function($){\r
+       $.datepicker.regional['sr-SR'] = {\r
+               closeText: 'Zatvori',\r
+               prevText: '&#x3c;',\r
+               nextText: '&#x3e;',\r
+               currentText: 'Danas',\r
+               monthNames: ['Januar','Februar','Mart','April','Maj','Jun',\r
+               'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'],\r
+               monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',\r
+               'Jul','Avg','Sep','Okt','Nov','Dec'],\r
+               dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'],\r
+               dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'],\r
+               dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sr-SR']);\r
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sr.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sr.js
new file mode 100644 (file)
index 0000000..179458b
--- /dev/null
@@ -0,0 +1,19 @@
+/* Serbian i18n for the jQuery UI date picker plugin. */\r
+/* Written by Dejan Dimić. */\r
+jQuery(function($){\r
+       $.datepicker.regional['sr'] = {\r
+               closeText: 'Затвори',\r
+               prevText: '&#x3c;',\r
+               nextText: '&#x3e;',\r
+               currentText: 'Данас',\r
+               monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун',\r
+               'Јул','Август','Септембар','Октобар','Новембар','Децембар'],\r
+               monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун',\r
+               'Јул','Авг','Сеп','Окт','Нов','Дец'],\r
+               dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'],\r
+               dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'],\r
+               dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'],\r
+               dateFormat: 'dd/mm/yy', firstDay: 1,\r
+               isRTL: false};\r
+       $.datepicker.setDefaults($.datepicker.regional['sr']);\r
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sv.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-sv.js
new file mode 100644 (file)
index 0000000..47c4b24
--- /dev/null
@@ -0,0 +1,19 @@
+/* Swedish initialisation for the jQuery UI date picker plugin. */
+/* Written by Anders Ekdahl ( anders@nomadiz.se). */
+jQuery(function($){
+    $.datepicker.regional['sv'] = {
+               closeText: 'Stäng',
+        prevText: '&laquo;Förra',
+               nextText: 'Nästa&raquo;',
+               currentText: 'Idag',
+        monthNames: ['Januari','Februari','Mars','April','Maj','Juni',
+        'Juli','Augusti','September','Oktober','November','December'],
+        monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',
+        'Jul','Aug','Sep','Okt','Nov','Dec'],
+               dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'],
+               dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'],
+               dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'],
+        dateFormat: 'yy-mm-dd', firstDay: 1,
+               isRTL: false};
+    $.datepicker.setDefaults($.datepicker.regional['sv']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-th.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-th.js
new file mode 100644 (file)
index 0000000..3c2a02b
--- /dev/null
@@ -0,0 +1,19 @@
+/* Thai initialisation for the jQuery UI date picker plugin. */
+/* Written by pipo (pipo@sixhead.com). */
+jQuery(function($){
+       $.datepicker.regional['th'] = {
+               closeText: 'ปิด',
+               prevText: '&laquo;&nbsp;ย้อน',
+               nextText: 'ถัดไป&nbsp;&raquo;',
+               currentText: 'วันนี้',
+               monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน',
+               'กรกฏาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'],
+               monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.',
+               'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'],
+               dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'],
+               dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'],
+               dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'],
+               dateFormat: 'dd/mm/yy', firstDay: 0,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['th']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-tr.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-tr.js
new file mode 100644 (file)
index 0000000..5817b2a
--- /dev/null
@@ -0,0 +1,19 @@
+/* Turkish initialisation for the jQuery UI date picker plugin. */
+/* Written by Izzet Emre Erkan (kara@karalamalar.net). */
+jQuery(function($){
+       $.datepicker.regional['tr'] = {
+               closeText: 'kapat',
+               prevText: '&#x3c;geri',
+               nextText: 'ileri&#x3e',
+               currentText: 'bugün',
+               monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran',
+               'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'],
+               monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz',
+               'Tem','Ağu','Eyl','Eki','Kas','Ara'],
+               dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'],
+               dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'],
+               dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'],
+               dateFormat: 'dd.mm.yy', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['tr']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-uk.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-uk.js
new file mode 100644 (file)
index 0000000..1043d7c
--- /dev/null
@@ -0,0 +1,25 @@
+/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */
+/* Written by Maxim Drogobitskiy (maxdao@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['uk'] = {
+               clearText: 'Очистити', clearStatus: '',
+               closeText: 'Закрити', closeStatus: '',
+               prevText: '&#x3c;',  prevStatus: '',
+               prevBigText: '&#x3c;&#x3c;', prevBigStatus: '',
+               nextText: '&#x3e;', nextStatus: '',
+               nextBigText: '&#x3e;&#x3e;', nextBigStatus: '',
+               currentText: 'Сьогодні', currentStatus: '',
+               monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень',
+               'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'],
+               monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер',
+               'Лип','Сер','Вер','Жов','Лис','Гру'],
+               monthStatus: '', yearStatus: '',
+               weekHeader: 'Не', weekStatus: '',
+               dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'],
+               dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'],
+               dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'],
+               dayStatus: 'DD', dateStatus: 'D, M d',
+               dateFormat: 'dd/mm/yy', firstDay: 1,
+               initStatus: '', isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['uk']);
+});
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-zh-CN.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-zh-CN.js
new file mode 100644 (file)
index 0000000..e3a69dc
--- /dev/null
@@ -0,0 +1,19 @@
+/* Chinese initialisation for the jQuery UI date picker plugin. */
+/* Written by Cloudream (cloudream@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['zh-CN'] = {
+               closeText: '关闭',
+               prevText: '&#x3c;上月',
+               nextText: '下月&#x3e;',
+               currentText: '今天',
+               monthNames: ['一月','二月','三月','四月','五月','六月',
+               '七月','八月','九月','十月','十一月','十二月'],
+               monthNamesShort: ['一','二','三','四','五','六',
+               '七','八','九','十','十一','十二'],
+               dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],
+               dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'],
+               dayNamesMin: ['日','一','二','三','四','五','六'],
+               dateFormat: 'yy-mm-dd', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['zh-CN']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-zh-TW.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/i18n/ui.datepicker-zh-TW.js
new file mode 100644 (file)
index 0000000..9cb49b7
--- /dev/null
@@ -0,0 +1,19 @@
+/* Chinese initialisation for the jQuery UI date picker plugin. */
+/* Written by Ressol (ressol@gmail.com). */
+jQuery(function($){
+       $.datepicker.regional['zh-TW'] = {
+               closeText: '關閉',
+               prevText: '&#x3c;上月',
+               nextText: '下月&#x3e;',
+               currentText: '今天',
+               monthNames: ['一月','二月','三月','四月','五月','六月',
+               '七月','八月','九月','十月','十一月','十二月'],
+               monthNamesShort: ['一','二','三','四','五','六',
+               '七','八','九','十','十一','十二'],
+               dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],
+               dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'],
+               dayNamesMin: ['日','一','二','三','四','五','六'],
+               dateFormat: 'yy/mm/dd', firstDay: 1,
+               isRTL: false};
+       $.datepicker.setDefaults($.datepicker.regional['zh-TW']);
+});
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/jquery-ui-1.7.1.custom.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/jquery-ui-1.7.1.custom.js
new file mode 100644 (file)
index 0000000..eac07e6
--- /dev/null
@@ -0,0 +1,9074 @@
+/*
+ * jQuery UI 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+;jQuery.ui || (function($) {
+
+var _remove = $.fn.remove,
+       isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);
+
+//Helper functions and ui object
+$.ui = {
+       version: "1.7.1",
+
+       // $.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);
+                               }
+                       }
+               }
+       },
+
+       contains: function(a, b) {
+               return document.compareDocumentPosition
+                       ? a.compareDocumentPosition(b) & 16
+                       : a !== b && a.contains(b);
+       },
+
+       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;
+       },
+
+       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);
+       },
+
+       keyCode: {
+               BACKSPACE: 8,
+               CAPS_LOCK: 20,
+               COMMA: 188,
+               CONTROL: 17,
+               DELETE: 46,
+               DOWN: 40,
+               END: 35,
+               ENTER: 13,
+               ESCAPE: 27,
+               HOME: 36,
+               INSERT: 45,
+               LEFT: 37,
+               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
+       }
+};
+
+// WAI-ARIA normalization
+if (isFF2) {
+       var attr = $.attr,
+               removeAttr = $.fn.removeAttr,
+               ariaNS = "http://www.w3.org/2005/07/aaa",
+               ariaState = /^aria-/,
+               ariaRole = /^wairole:/;
+
+       $.attr = function(elem, name, value) {
+               var set = value !== undefined;
+
+               return (name == 'role'
+                       ? (set
+                               ? attr.call(this, elem, name, "wairole:" + value)
+                               : (attr.apply(this, arguments) || "").replace(ariaRole, ""))
+                       : (ariaState.test(name)
+                               ? (set
+                                       ? elem.setAttributeNS(ariaNS,
+                                               name.replace(ariaState, "aaa:"), value)
+                                       : attr.call(this, elem, name.replace(ariaState, "aaa:")))
+                               : attr.apply(this, arguments)));
+       };
+
+       $.fn.removeAttr = function(name) {
+               return (ariaState.test(name)
+                       ? this.each(function() {
+                               this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
+                       }) : removeAttr.call(this, name));
+       };
+}
+
+//jQuery plugins
+$.fn.extend({
+       remove: function() {
+               // Safari has a native remove event which actually removes DOM elements,
+               // so we have to use triggerHandler instead of trigger (#3037).
+               $("*", this).add(this).each(function() {
+                       $(this).triggerHandler("remove");
+               });
+               return _remove.apply(this, arguments );
+       },
+
+       enableSelection: function() {
+               return this
+                       .attr('unselectable', 'off')
+                       .css('MozUserSelect', '')
+                       .unbind('selectstart.ui');
+       },
+
+       disableSelection: function() {
+               return this
+                       .attr('unselectable', 'on')
+                       .css('MozUserSelect', 'none')
+                       .bind('selectstart.ui', function() { return false; });
+       },
+
+       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;
+       }
+});
+
+
+//Additional selectors
+$.extend($.expr[':'], {
+       data: function(elem, i, match) {
+               return !!$.data(elem, match[3]);
+       },
+
+       focusable: function(element) {
+               var nodeName = element.nodeName.toLowerCase(),
+                       tabIndex = $.attr(element, 'tabindex');
+               return (/input|select|textarea|button|object/.test(nodeName)
+                       ? !element.disabled
+                       : 'a' == nodeName || 'area' == nodeName
+                               ? element.href || !isNaN(tabIndex)
+                               : !isNaN(tabIndex))
+                       // the element and all of its ancestors must be visible
+                       // the browser may report that the area is hidden
+                       && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;
+       },
+
+       tabbable: function(element) {
+               var tabIndex = $.attr(element, 'tabindex');
+               return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');
+       }
+});
+
+
+// $.widget is a factory to create jQuery plugins
+// taking some boilerplate code out of the plugin code
+function getter(namespace, plugin, method, args) {
+       function getMethods(type) {
+               var methods = $[namespace][plugin][type] || [];
+               return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
+       }
+
+       var methods = getMethods('getter');
+       if (args.length == 1 && typeof args[0] == 'string') {
+               methods = methods.concat(getMethods('getterSetter'));
+       }
+       return ($.inArray(method, methods) != -1);
+}
+
+$.widget = function(name, prototype) {
+       var namespace = name.split(".")[0];
+       name = name.split(".")[1];
+
+       // create plugin method
+       $.fn[name] = function(options) {
+               var isMethodCall = (typeof options == 'string'),
+                       args = Array.prototype.slice.call(arguments, 1);
+
+               // prevent calls to internal methods
+               if (isMethodCall && options.substring(0, 1) == '_') {
+                       return this;
+               }
+
+               // handle getter methods
+               if (isMethodCall && getter(namespace, name, options, args)) {
+                       var instance = $.data(this[0], name);
+                       return (instance ? instance[options].apply(instance, args)
+                               : undefined);
+               }
+
+               // handle initialization and non-getter methods
+               return this.each(function() {
+                       var instance = $.data(this, name);
+
+                       // constructor
+                       (!instance && !isMethodCall &&
+                               $.data(this, name, new $[namespace][name](this, options))._init());
+
+                       // method call
+                       (instance && isMethodCall && $.isFunction(instance[options]) &&
+                               instance[options].apply(instance, args));
+               });
+       };
+
+       // create widget constructor
+       $[namespace] = $[namespace] || {};
+       $[namespace][name] = function(element, options) {
+               var self = this;
+
+               this.namespace = namespace;
+               this.widgetName = name;
+               this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
+               this.widgetBaseClass = namespace + '-' + name;
+
+               this.options = $.extend({},
+                       $.widget.defaults,
+                       $[namespace][name].defaults,
+                       $.metadata && $.metadata.get(element)[name],
+                       options);
+
+               this.element = $(element)
+                       .bind('setData.' + name, function(event, key, value) {
+                               if (event.target == element) {
+                                       return self._setData(key, value);
+                               }
+                       })
+                       .bind('getData.' + name, function(event, key) {
+                               if (event.target == element) {
+                                       return self._getData(key);
+                               }
+                       })
+                       .bind('remove', function() {
+                               return self.destroy();
+                       });
+       };
+
+       // add widget prototype
+       $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
+
+       // TODO: merge getter and getterSetter properties from widget prototype
+       // and plugin prototype
+       $[namespace][name].getterSetter = 'option';
+};
+
+$.widget.prototype = {
+       _init: function() {},
+       destroy: function() {
+               this.element.removeData(this.widgetName)
+                       .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')
+                       .removeAttr('aria-disabled');
+       },
+
+       option: function(key, value) {
+               var options = key,
+                       self = this;
+
+               if (typeof key == "string") {
+                       if (value === undefined) {
+                               return this._getData(key);
+                       }
+                       options = {};
+                       options[key] = value;
+               }
+
+               $.each(options, function(key, value) {
+                       self._setData(key, value);
+               });
+       },
+       _getData: function(key) {
+               return this.options[key];
+       },
+       _setData: function(key, value) {
+               this.options[key] = value;
+
+               if (key == 'disabled') {
+                       this.element
+                               [value ? 'addClass' : 'removeClass'](
+                                       this.widgetBaseClass + '-disabled' + ' ' +
+                                       this.namespace + '-state-disabled')
+                               .attr("aria-disabled", value);
+               }
+       },
+
+       enable: function() {
+               this._setData('disabled', false);
+       },
+       disable: function() {
+               this._setData('disabled', true);
+       },
+
+       _trigger: function(type, event, data) {
+               var callback = this.options[type],
+                       eventName = (type == this.widgetEventPrefix
+                               ? type : this.widgetEventPrefix + type);
+
+               event = $.Event(event);
+               event.type = eventName;
+
+               // 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());
+       }
+};
+
+$.widget.defaults = {
+       disabled: false
+};
+
+
+/** Mouse Interaction Plugin **/
+
+$.ui.mouse = {
+       _mouseInit: function() {
+               var self = this;
+
+               this.element
+                       .bind('mousedown.'+this.widgetName, function(event) {
+                               return self._mouseDown(event);
+                       })
+                       .bind('click.'+this.widgetName, function(event) {
+                               if(self._preventClickEvent) {
+                                       self._preventClickEvent = false;
+                                       event.stopImmediatePropagation();
+                                       return false;
+                               }
+                       });
+
+               // Prevent text selection in IE
+               if ($.browser.msie) {
+                       this._mouseUnselectable = this.element.attr('unselectable');
+                       this.element.attr('unselectable', 'on');
+               }
+
+               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);
+
+               // Restore text selection in IE
+               ($.browser.msie
+                       && this.element.attr('unselectable', this._mouseUnselectable));
+       },
+
+       _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;
+                       }
+               }
+
+               // 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);
+
+               // preventDefault() is used to prevent the selection of text here -
+               // however, in Safari, this causes select boxes not to be selectable
+               // anymore, so this fix is needed
+               ($.browser.safari || 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 && !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;
+                       this._preventClickEvent = (event.target == this._mouseDownEvent.target);
+                       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; }
+};
+
+$.ui.mouse.defaults = {
+       cancel: null,
+       distance: 1,
+       delay: 0
+};
+
+})(jQuery);
+/*
+ * jQuery UI Draggable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.draggable", $.extend({}, $.ui.mouse, {
+
+       _init: 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();
+       },
+
+       _mouseCapture: function(event) {
+
+               var o = this.options;
+
+               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.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._generatePosition(event);
+               this.originalPageX = event.pageX;
+               this.originalPageY = event.pageY;
+
+               //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+               if(o.cursorAt)
+                       this._adjustOffsetFromHelper(o.cursorAt);
+
+               //Set a containment if given in the options
+               if(o.containment)
+                       this._setContainment();
+
+               //Call plugins and callbacks
+               this._trigger("start", event);
+
+               //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();
+                       this._trigger('drag', event, ui);
+                       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((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() {
+                               self._trigger("stop", event);
+                               self._clear();
+                       });
+               } else {
+                       this._trigger("stop", event);
+                       this._clear();
+               }
+
+               return false;
+       },
+
+       _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(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+               if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+               if(obj.bottom != undefined) 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)
+               };
+       },
+
+       _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) && 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) - 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
+                       ];
+               } 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 && 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() ))
+                       )
+               };
+
+       },
+
+       _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,
+                       absolutePosition: this.positionAbs, //deprecated
+                       offset: this.positionAbs
+               };
+       }
+
+}));
+
+$.extend($.ui.draggable, {
+       version: "1.7.1",
+       eventPrefix: "drag",
+       defaults: {
+               addClasses: true,
+               appendTo: "parent",
+               axis: false,
+               cancel: ":input,option",
+               connectToSortable: false,
+               containment: false,
+               cursor: "auto",
+               cursorAt: false,
+               delay: 0,
+               distance: 1,
+               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
+       }
+});
+
+$.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._refreshItems();       //Do a one-time refresh at start to refresh the containerCache
+                               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.group)).sort(function(a,b) {
+                       return (parseInt($(a).css("zIndex"),10) || o.stack.min) - (parseInt($(b).css("zIndex"),10) || o.stack.min);
+               });
+
+               $(group).each(function(i) {
+                       this.style.zIndex = o.stack.min + i;
+               });
+
+               this[0].style.zIndex = o.stack.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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Droppables
+ *
+ * Depends:
+ *     ui.core.js
+ *     ui.draggable.js
+ */
+(function($) {
+
+$.widget("ui.droppable", {
+
+       _init: function() {
+
+               var o = this.options, accept = o.accept;
+               this.isover = 0; this.isout = 1;
+
+               this.options.accept = this.options.accept && $.isFunction(this.options.accept) ? this.options.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[this.options.scope] = $.ui.ddmanager.droppables[this.options.scope] || [];
+               $.ui.ddmanager.droppables[this.options.scope].push(this);
+
+               (this.options.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");
+       },
+
+       _setData: function(key, value) {
+
+               if(key == 'accept') {
+                       this.options.accept = value && $.isFunction(value) ? value : function(d) {
+                               return d.is(value);
+                       };
+               } else {
+                       $.widget.prototype._setData.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.options.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.options.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 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)) {
+                               childrenIntersection = true; return false;
+                       }
+               });
+               if(childrenIntersection) return false;
+
+               if(this.options.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,
+                       absolutePosition: c.positionAbs, //deprecated
+                       offset: c.positionAbs
+               };
+       }
+
+});
+
+$.extend($.ui.droppable, {
+       version: "1.7.1",
+       eventPrefix: 'drop',
+       defaults: {
+               accept: '*',
+               activeClass: false,
+               addClasses: true,
+               greedy: false,
+               hoverClass: false,
+               scope: 'default',
+               tolerance: 'intersect'
+       }
+});
+
+$.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].options.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
+
+                       m[i].offset = m[i].element.offset();
+                       m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
+
+                       if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
+
+               }
+
+       },
+       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 = this._drop.call(this, event);
+
+                       if (!this.options.disabled && this.visible && this.options.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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.resizable", $.extend({}, $.ui.mouse, {
+
+       _init: 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.parent().append(
+                               this.originalElement.css({
+                                       position: wrapper.css('position'),
+                                       width: wrapper.outerWidth(),
+                                       height: wrapper.outerHeight(),
+                                       top: wrapper.css('top'),
+                                       left: wrapper.css('left')
+                               })
+                       ).end().remove();
+               }
+
+               this.originalElement.css('resize', this.originalResizeStyle);
+               _destroy(this.originalElement);
+
+       },
+
+       _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.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;
+
+                       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.7.1",
+       eventPrefix: "resize",
+       defaults: {
+               alsoResize: false,
+               animate: false,
+               animateDuration: "slow",
+               animateEasing: "swing",
+               aspectRatio: false,
+               autoHide: false,
+               cancel: ":input,option",
+               containment: false,
+               delay: 0,
+               distance: 1,
+               ghost: false,
+               grid: false,
+               handles: "e,s,se",
+               helper: false,
+               maxHeight: null,
+               maxWidth: null,
+               minHeight: 10,
+               minWidth: 10,
+               zIndex: 1000
+       }
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+       start: function(event, ui) {
+
+               var self = $(this).data("resizable"), o = self.options;
+
+               _store = function(exp) {
+                       $(exp).each(function() {
+                               $(this).data("resizable-alsoresize", {
+                                       width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
+                                       left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10)
+                               });
+                       });
+               };
+
+               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, c) { _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 : ['width', 'height', 'top', 'left'];
+
+                               $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) {
+                                       var sum = (start[prop]||0) + (delta[prop]||0);
+                                       if (sum && sum >= 0)
+                                               style[prop] = sum || null;
+                               });
+
+                               //Opera fixing relative position
+                               if (/relative/.test(el.css('position')) && $.browser.opera) {
+                                       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");
+
+               //Opera fixing relative position
+               if (self._revertToRelativePosition && $.browser.opera) {
+                       self._revertToRelativePosition = false;
+                       el.css({ position: 'relative' });
+               }
+
+               $(this).removeData("resizable-alsoresize-start");
+       }
+});
+
+$.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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Selectables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.selectable", $.extend({}, $.ui.mouse, {
+
+       _init: 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 = $(document.createElement('div'))
+                       .css({border:'1px dotted black'})
+                       .addClass("ui-selectable-helper");
+       },
+
+       destroy: function() {
+               this.element
+                       .removeClass("ui-selectable ui-selectable-disabled")
+                       .removeData("selectable")
+                       .unbind(".selectable");
+               this._mouseDestroy();
+       },
+
+       _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({
+                       "z-index": 100,
+                       "position": "absolute",
+                       "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) {
+                               selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting');
+                               selectee.unselecting = false;
+                               selectee.selecting = true;
+                               selectee.selected = true;
+                               // selectable SELECTING callback
+                               self._trigger("selecting", event, {
+                                       selecting: 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.7.1",
+       defaults: {
+               appendTo: 'body',
+               autoRefresh: true,
+               cancel: ":input,option",
+               delay: 0,
+               distance: 0,
+               filter: '*',
+               tolerance: 'touch'
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Sortable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Sortables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.sortable", $.extend({}, $.ui.mouse, {
+       _init: function() {
+
+               var o = this.options;
+               this.containerCache = {};
+               this.element.addClass("ui-sortable");
+
+               //Get the items
+               this.refresh();
+
+               //Let's determine if the items are floating
+               this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : 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");
+       },
+
+       _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
+               if(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)
+                       ) {
+
+                               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();
+
+                       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;
+                               }
+                       }
+
+               }
+
+               //$(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 true;
+
+       },
+
+       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]));
+               });
+
+               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();
+       },
+
+       _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"), 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"), 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();
+                       };
+               }
+
+       },
+
+       _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) {
+               for (var i = this.containers.length - 1; i >= 0; i--){
+
+                       if(this._intersectsWith(this.containers[i].containerCache)) {
+                               if(!this.containers[i].containerCache.over) {
+
+                                       if(this.currentContainer != this.containers[i]) {
+
+                                               //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[i].floating ? 'left' : 'top'];
+                                               for (var j = this.items.length - 1; j >= 0; j--) {
+                                                       if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue;
+                                                       var cur = this.items[j][this.containers[i].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
+                                                       continue;
+
+                                               this.currentContainer = this.containers[i];
+                                               itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[i].element, true);
+                                               this._trigger("change", event, this._uiHash());
+                                               this.containers[i]._trigger("change", event, this._uiHash(this));
+
+                                               //Update the placeholder
+                                               this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+                                       }
+
+                                       this.containers[i]._trigger("over", event, this._uiHash(this));
+                                       this.containers[i].containerCache.over = 1;
+                               }
+                       } else {
+                               if(this.containers[i].containerCache.over) {
+                                       this.containers[i]._trigger("out", event, this._uiHash(this));
+                                       this.containers[i].containerCache.over = 0;
+                               }
+                       }
+
+               };
+       },
+
+       _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(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+               if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+               if(obj.bottom != undefined) 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 cursor
+               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,
+                       absolutePosition: self.positionAbs, //deprecated
+                       offset: self.positionAbs,
+                       item: self.currentItem,
+                       sender: inst ? inst.element : null
+               };
+       }
+
+}));
+
+$.extend($.ui.sortable, {
+       getter: "serialize toArray",
+       version: "1.7.1",
+       eventPrefix: "sort",
+       defaults: {
+               appendTo: "parent",
+               axis: false,
+               cancel: ":input,option",
+               connectWith: false,
+               containment: false,
+               cursor: 'auto',
+               cursorAt: false,
+               delay: 0,
+               distance: 1,
+               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
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Accordion 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Accordion
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.accordion", {
+
+       _init: function() {
+
+               var o = this.options, self = this;
+               this.running = 0;
+
+               // if the user set the alwaysOpen option on init
+               // then we need to set the collapsible option
+               // if they set both on init, collapsible will take priority
+               if (o.collapsible == $.ui.accordion.defaults.collapsible &&
+                       o.alwaysOpen != $.ui.accordion.defaults.alwaysOpen) {
+                       o.collapsible = !o.alwaysOpen;
+               }
+
+               if ( o.navigation ) {
+                       var current = this.element.find("a").filter(o.navigationFilter);
+                       if ( current.length ) {
+                               if ( current.filter(o.header).length ) {
+                                       this.active = current;
+                               } else {
+                                       this.active = current.parent().parent().prev();
+                                       current.addClass("ui-accordion-content-active");
+                               }
+                       }
+               }
+
+               this.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
+               if (this.element[0].nodeName == "UL") {
+                       this.element.children("li").addClass("ui-accordion-li-fix");
+               }
+
+               this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all")
+                       .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); })
+                       .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); })
+                       .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); })
+                       .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); });
+
+               this.headers
+                       .next()
+                               .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
+
+               this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");
+               this.active.next().addClass('ui-accordion-content-active');
+
+               //Append icon elements
+               $("<span/>").addClass("ui-icon " + o.icons.header).prependTo(this.headers);
+               this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected);
+
+               // IE7-/Win - Extra vertical space in lists fixed
+               if ($.browser.msie) {
+                       this.element.find('a').css('zoom', '1');
+               }
+
+               this.resize();
+
+               //ARIA
+               this.element.attr('role','tablist');
+
+               this.headers
+                       .attr('role','tab')
+                       .bind('keydown', function(event) { return self._keydown(event); })
+                       .next()
+                       .attr('role','tabpanel');
+
+               this.headers
+                       .not(this.active || "")
+                       .attr('aria-expanded','false')
+                       .attr("tabIndex", "-1")
+                       .next()
+                       .hide();
+
+               // make sure at least one header is in the tab order
+               if (!this.active.length) {
+                       this.headers.eq(0).attr('tabIndex','0');
+               } else {
+                       this.active
+                               .attr('aria-expanded','true')
+                               .attr('tabIndex', '0');
+               }
+
+               // only need links in taborder for Safari
+               if (!$.browser.safari)
+                       this.headers.find('a').attr('tabIndex','-1');
+
+               if (o.event) {
+                       this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); });
+               }
+
+       },
+
+       destroy: function() {
+               var o = this.options;
+
+               this.element
+                       .removeClass("ui-accordion ui-widget ui-helper-reset")
+                       .removeAttr("role")
+                       .unbind('.accordion')
+                       .removeData('accordion');
+
+               this.headers
+                       .unbind(".accordion")
+                       .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top")
+                       .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");
+
+               this.headers.find("a").removeAttr("tabindex");
+               this.headers.children(".ui-icon").remove();
+               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");
+               if (o.autoHeight || o.fillHeight) {
+                       contents.css("height", "");
+               }
+       },
+       
+       _setData: function(key, value) {
+               if(key == 'alwaysOpen') { key = 'collapsible'; value = !value; }
+               $.widget.prototype._setData.apply(this, arguments);     
+       },
+
+       _keydown: function(event) {
+
+               var o = this.options, keyCode = $.ui.keyCode;
+
+               if (o.disabled || event.altKey || event.ctrlKey)
+                       return;
+
+               var length = this.headers.length;
+               var currentIndex = this.headers.index(event.target);
+               var 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:
+                               return this._clickHandler({ target: event.target }, event.target);
+               }
+
+               if (toFocus) {
+                       $(event.target).attr('tabIndex','-1');
+                       $(toFocus).attr('tabIndex','0');
+                       toFocus.focus();
+                       return false;
+               }
+
+               return true;
+
+       },
+
+       resize: function() {
+
+               var o = this.options, maxHeight;
+
+               if (o.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();
+                       });
+
+                       var maxPadding = 0;
+                       this.headers.next().each(function() {
+                               maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
+                       }).height(Math.max(0, maxHeight - maxPadding))
+                       .css('overflow', 'auto');
+
+               } else if ( o.autoHeight ) {
+                       maxHeight = 0;
+                       this.headers.next().each(function() {
+                               maxHeight = Math.max(maxHeight, $(this).outerHeight());
+                       }).height(maxHeight);
+               }
+
+       },
+
+       activate: function(index) {
+               // call clickHandler with custom event
+               var active = this._findActive(index)[0];
+               this._clickHandler({ target: active }, active);
+       },
+
+       _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)");
+       },
+
+       _clickHandler: function(event, target) {
+
+               var o = this.options;
+               if (o.disabled) return false;
+
+               // called only when using activate(false) to close all parts programmatically
+               if (!event.target && o.collapsible) {
+                       this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
+                               .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
+                       this.active.next().addClass('ui-accordion-content-active');
+                       var toHide = this.active.next(),
+                               data = {
+                                       options: o,
+                                       newHeader: $([]),
+                                       oldHeader: o.active,
+                                       newContent: $([]),
+                                       oldContent: toHide
+                               },
+                               toShow = (this.active = $([]));
+                       this._toggle(toShow, toHide, data);
+                       return false;
+               }
+
+               // get the click target
+               var clicked = $(event.currentTarget || target);
+               var clickedIsActive = clicked[0] == this.active[0];
+
+               // if animations are still active, or the active header is the target, ignore click
+               if (this.running || (!o.collapsible && clickedIsActive)) {
+                       return false;
+               }
+
+               // switch classes
+               this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
+                       .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
+               this.active.next().addClass('ui-accordion-content-active');
+               if (!clickedIsActive) {
+                       clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top")
+                               .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected);
+                       clicked.next().addClass('ui-accordion-content-active');
+               }
+
+               // find elements to show and hide
+               var toShow = clicked.next(),
+                       toHide = this.active.next(),
+                       data = {
+                               options: o,
+                               newHeader: clickedIsActive && o.collapsible ? $([]) : clicked,
+                               oldHeader: this.active,
+                               newContent: clickedIsActive && o.collapsible ? $([]) : toShow.find('> *'),
+                               oldContent: toHide.find('> *')
+                       },
+                       down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );
+
+               this.active = clickedIsActive ? $([]) : clicked;
+               this._toggle(toShow, toHide, data, clickedIsActive, down);
+
+               return false;
+
+       },
+
+       _toggle: function(toShow, toHide, data, clickedIsActive, down) {
+
+               var o = this.options, self = this;
+
+               this.toShow = toShow;
+               this.toHide = toHide;
+               this.data = data;
+
+               var complete = function() { if(!self) return; return self._completed.apply(self, arguments); };
+
+               // trigger changestart event
+               this._trigger("changestart", null, this.data);
+
+               // count elements to animate
+               this.running = toHide.size() === 0 ? toShow.size() : toHide.size();
+
+               if (o.animated) {
+
+                       var animOptions = {};
+
+                       if ( o.collapsible && clickedIsActive ) {
+                               animOptions = {
+                                       toShow: $([]),
+                                       toHide: toHide,
+                                       complete: complete,
+                                       down: down,
+                                       autoHeight: o.autoHeight || o.fillSpace
+                               };
+                       } else {
+                               animOptions = {
+                                       toShow: toShow,
+                                       toHide: toHide,
+                                       complete: complete,
+                                       down: down,
+                                       autoHeight: o.autoHeight || o.fillSpace
+                               };
+                       }
+
+                       if (!o.proxied) {
+                               o.proxied = o.animated;
+                       }
+
+                       if (!o.proxiedDuration) {
+                               o.proxiedDuration = o.duration;
+                       }
+
+                       o.animated = $.isFunction(o.proxied) ?
+                               o.proxied(animOptions) : o.proxied;
+
+                       o.duration = $.isFunction(o.proxiedDuration) ?
+                               o.proxiedDuration(animOptions) : o.proxiedDuration;
+
+                       var animations = $.ui.accordion.animations,
+                               duration = o.duration,
+                               easing = o.animated;
+
+                       if (!animations[easing]) {
+                               animations[easing] = function(options) {
+                                       this.slide(options, {
+                                               easing: easing,
+                                               duration: duration || 700
+                                       });
+                               };
+                       }
+
+                       animations[easing](animOptions);
+
+               } else {
+
+                       if (o.collapsible && clickedIsActive) {
+                               toShow.toggle();
+                       } else {
+                               toHide.hide();
+                               toShow.show();
+                       }
+
+                       complete(true);
+
+               }
+
+               toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur();
+               toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus();
+
+       },
+
+       _completed: function(cancel) {
+
+               var o = this.options;
+
+               this.running = cancel ? 0 : --this.running;
+               if (this.running) return;
+
+               if (o.clearStyle) {
+                       this.toShow.add(this.toHide).css({
+                               height: "",
+                               overflow: ""
+                       });
+               }
+
+               this._trigger('change', null, this.data);
+       }
+
+});
+
+
+$.extend($.ui.accordion, {
+       version: "1.7.1",
+       defaults: {
+               active: null,
+               alwaysOpen: true, //deprecated, use collapsible
+               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();
+               }
+       },
+       animations: {
+               slide: function(options, additions) {
+                       options = $.extend({
+                               easing: "swing",
+                               duration: 300
+                       }, options, additions);
+                       if ( !options.toHide.size() ) {
+                               options.toShow.animate({height: "show"}, options);
+                               return;
+                       }
+                       if ( !options.toShow.size() ) {
+                               options.toHide.animate({height: "hide"}, options);
+                               return;
+                       }
+                       var overflow = options.toShow.css('overflow'),
+                               percentDone,
+                               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.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);
+                                       options.toShow.css({overflow: overflow});
+                                       options.complete();
+                               }
+                       });
+               },
+               bounceslide: function(options) {
+                       this.slide(options, {
+                               easing: options.down ? "easeOutBounce" : "swing",
+                               duration: options.down ? 1000 : 200
+                       });
+               },
+               easeslide: function(options) {
+                       this.slide(options, {
+                               easing: "easeinout",
+                               duration: 700
+                       });
+               }
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Dialog 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ *     ui.core.js
+ *     ui.draggable.js
+ *     ui.resizable.js
+ */
+(function($) {
+
+var setDataSwitch = {
+               dragStart: "start.draggable",
+               drag: "drag.draggable",
+               dragStop: "stop.draggable",
+               maxHeight: "maxHeight.resizable",
+               minHeight: "minHeight.resizable",
+               maxWidth: "maxWidth.resizable",
+               minWidth: "minWidth.resizable",
+               resizeStart: "start.resizable",
+               resize: "drag.resizable",
+               resizeStop: "stop.resizable"
+       },
+       
+       uiDialogClasses =
+               'ui-dialog ' +
+               'ui-widget ' +
+               'ui-widget-content ' +
+               'ui-corner-all ';
+
+$.widget("ui.dialog", {
+
+       _init: function() {
+               this.originalTitle = this.element.attr('title');
+
+               var self = this,
+                       options = this.options,
+
+                       title = options.title || this.originalTitle || '&nbsp;',
+                       titleId = $.ui.dialog.getTitleId(this.element),
+
+                       uiDialog = (this.uiDialog = $('<div/>'))
+                               .appendTo(document.body)
+                               .hide()
+                               .addClass(uiDialogClasses + options.dialogClass)
+                               .css({
+                                       position: 'absolute',
+                                       overflow: 'hidden',
+                                       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) {
+                                       (options.closeOnEscape && event.keyCode
+                                               && event.keyCode == $.ui.keyCode.ESCAPE && self.close(event));
+                               })
+                               .attr({
+                                       role: 'dialog',
+                                       'aria-labelledby': titleId
+                               })
+                               .mousedown(function(event) {
+                                       self.moveToTop(false, event);
+                               }),
+
+                       uiDialogContent = this.element
+                               .show()
+                               .removeAttr('title')
+                               .addClass(
+                                       'ui-dialog-content ' +
+                                       'ui-widget-content')
+                               .appendTo(uiDialog),
+
+                       uiDialogTitlebar = (this.uiDialogTitlebar = $('<div></div>'))
+                               .addClass(
+                                       'ui-dialog-titlebar ' +
+                                       'ui-widget-header ' +
+                                       'ui-corner-all ' +
+                                       'ui-helper-clearfix'
+                               )
+                               .prependTo(uiDialog),
+
+                       uiDialogTitlebarClose = $('<a href="#"/>')
+                               .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');
+                               })
+                               .mousedown(function(ev) {
+                                       ev.stopPropagation();
+                               })
+                               .click(function(event) {
+                                       self.close(event);
+                                       return false;
+                               })
+                               .appendTo(uiDialogTitlebar),
+
+                       uiDialogTitlebarCloseText = (this.uiDialogTitlebarCloseText = $('<span/>'))
+                               .addClass(
+                                       'ui-icon ' +
+                                       'ui-icon-closethick'
+                               )
+                               .text(options.closeText)
+                               .appendTo(uiDialogTitlebarClose),
+
+                       uiDialogTitle = $('<span/>')
+                               .addClass('ui-dialog-title')
+                               .attr('id', titleId)
+                               .html(title)
+                               .prependTo(uiDialogTitlebar);
+
+               uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();
+
+               (options.draggable && $.fn.draggable && this._makeDraggable());
+               (options.resizable && $.fn.resizable && this._makeResizable());
+
+               this._createButtons(options.buttons);
+               this._isOpen = false;
+
+               (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe());
+               (options.autoOpen && this.open());
+               
+       },
+
+       destroy: function() {
+               (this.overlay && this.overlay.destroy());
+               this.uiDialog.hide();
+               this.element
+                       .unbind('.dialog')
+                       .removeData('dialog')
+                       .removeClass('ui-dialog-content ui-widget-content')
+                       .hide().appendTo('body');
+               this.uiDialog.remove();
+
+               (this.originalTitle && this.element.attr('title', this.originalTitle));
+       },
+
+       close: function(event) {
+               var self = this;
+               
+               if (false === self._trigger('beforeclose', event)) {
+                       return;
+               }
+
+               (self.overlay && self.overlay.destroy());
+               self.uiDialog.unbind('keypress.ui-dialog');
+
+               (self.options.hide
+                       ? self.uiDialog.hide(self.options.hide, function() {
+                               self._trigger('close', event);
+                       })
+                       : self.uiDialog.hide() && self._trigger('close', event));
+
+               $.ui.dialog.overlay.resize();
+
+               self._isOpen = false;
+       },
+
+       isOpen: function() {
+               return this._isOpen;
+       },
+
+       // the force parameter allows us to move modal dialogs to their correct
+       // position on open
+       moveToTop: function(force, event) {
+
+               if ((this.options.modal && !force)
+                       || (!this.options.stack && !this.options.modal)) {
+                       return this._trigger('focus', event);
+               }
+               
+               if (this.options.zIndex > $.ui.dialog.maxZ) {
+                       $.ui.dialog.maxZ = this.options.zIndex;
+               }
+               (this.overlay && this.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
+               var saveScroll = { scrollTop: this.element.attr('scrollTop'), scrollLeft: this.element.attr('scrollLeft') };
+               this.uiDialog.css('z-index', ++$.ui.dialog.maxZ);
+               this.element.attr(saveScroll);
+               this._trigger('focus', event);
+       },
+
+       open: function() {
+               if (this._isOpen) { return; }
+
+               var options = this.options,
+                       uiDialog = this.uiDialog;
+
+               this.overlay = options.modal ? new $.ui.dialog.overlay(this) : null;
+               (uiDialog.next().length && uiDialog.appendTo('body'));
+               this._size();
+               this._position(options.position);
+               uiDialog.show(options.show);
+               this.moveToTop(true);
+
+               // prevent tabbing out of modal dialogs
+               (options.modal && uiDialog.bind('keypress.ui-dialog', function(event) {
+                       if (event.keyCode != $.ui.keyCode.TAB) {
+                               return;
+                       }
+
+                       var tabbables = $(':tabbable', this),
+                               first = tabbables.filter(':first')[0],
+                               last  = tabbables.filter(':last')[0];
+
+                       if (event.target == last && !event.shiftKey) {
+                               setTimeout(function() {
+                                       first.focus();
+                               }, 1);
+                       } else if (event.target == first && event.shiftKey) {
+                               setTimeout(function() {
+                                       last.focus();
+                               }, 1);
+                       }
+               }));
+
+               // 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
+               $([])
+                       .add(uiDialog.find('.ui-dialog-content :tabbable:first'))
+                       .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first'))
+                       .add(uiDialog)
+                       .filter(':first')
+                       .focus();
+
+               this._trigger('open');
+               this._isOpen = true;
+       },
+
+       _createButtons: function(buttons) {
+               var self = this,
+                       hasButtons = false,
+                       uiDialogButtonPane = $('<div></div>')
+                               .addClass(
+                                       'ui-dialog-buttonpane ' +
+                                       'ui-widget-content ' +
+                                       'ui-helper-clearfix'
+                               );
+
+               // if we already have a button pane, remove it
+               this.uiDialog.find('.ui-dialog-buttonpane').remove();
+
+               (typeof buttons == 'object' && buttons !== null &&
+                       $.each(buttons, function() { return !(hasButtons = true); }));
+               if (hasButtons) {
+                       $.each(buttons, function(name, fn) {
+                               $('<button type="button"></button>')
+                                       .addClass(
+                                               'ui-state-default ' +
+                                               'ui-corner-all'
+                                       )
+                                       .text(name)
+                                       .click(function() { fn.apply(self.element[0], arguments); })
+                                       .hover(
+                                               function() {
+                                                       $(this).addClass('ui-state-hover');
+                                               },
+                                               function() {
+                                                       $(this).removeClass('ui-state-hover');
+                                               }
+                                       )
+                                       .focus(function() {
+                                               $(this).addClass('ui-state-focus');
+                                       })
+                                       .blur(function() {
+                                               $(this).removeClass('ui-state-focus');
+                                       })
+                                       .appendTo(uiDialogButtonPane);
+                       });
+                       uiDialogButtonPane.appendTo(this.uiDialog);
+               }
+       },
+
+       _makeDraggable: function() {
+               var self = this,
+                       options = this.options,
+                       heightBeforeDrag;
+
+               this.uiDialog.draggable({
+                       cancel: '.ui-dialog-content',
+                       handle: '.ui-dialog-titlebar',
+                       containment: 'document',
+                       start: function() {
+                               heightBeforeDrag = options.height;
+                               $(this).height($(this).height()).addClass("ui-dialog-dragging");
+                               (options.dragStart && options.dragStart.apply(self.element[0], arguments));
+                       },
+                       drag: function() {
+                               (options.drag && options.drag.apply(self.element[0], arguments));
+                       },
+                       stop: function() {
+                               $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
+                               (options.dragStop && options.dragStop.apply(self.element[0], arguments));
+                               $.ui.dialog.overlay.resize();
+                       }
+               });
+       },
+
+       _makeResizable: function(handles) {
+               handles = (handles === undefined ? this.options.resizable : handles);
+               var self = this,
+                       options = this.options,
+                       resizeHandles = typeof handles == 'string'
+                               ? handles
+                               : 'n,e,s,w,se,sw,ne,nw';
+
+               this.uiDialog.resizable({
+                       cancel: '.ui-dialog-content',
+                       alsoResize: this.element,
+                       maxWidth: options.maxWidth,
+                       maxHeight: options.maxHeight,
+                       minWidth: options.minWidth,
+                       minHeight: options.minHeight,
+                       start: function() {
+                               $(this).addClass("ui-dialog-resizing");
+                               (options.resizeStart && options.resizeStart.apply(self.element[0], arguments));
+                       },
+                       resize: function() {
+                               (options.resize && options.resize.apply(self.element[0], arguments));
+                       },
+                       handles: resizeHandles,
+                       stop: function() {
+                               $(this).removeClass("ui-dialog-resizing");
+                               options.height = $(this).height();
+                               options.width = $(this).width();
+                               (options.resizeStop && options.resizeStop.apply(self.element[0], arguments));
+                               $.ui.dialog.overlay.resize();
+                       }
+               })
+               .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
+       },
+
+       _position: function(pos) {
+               var wnd = $(window), doc = $(document),
+                       pTop = doc.scrollTop(), pLeft = doc.scrollLeft(),
+                       minTop = pTop;
+
+               if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) {
+                       pos = [
+                               pos == 'right' || pos == 'left' ? pos : 'center',
+                               pos == 'top' || pos == 'bottom' ? pos : 'middle'
+                       ];
+               }
+               if (pos.constructor != Array) {
+                       pos = ['center', 'middle'];
+               }
+               if (pos[0].constructor == Number) {
+                       pLeft += pos[0];
+               } else {
+                       switch (pos[0]) {
+                               case 'left':
+                                       pLeft += 0;
+                                       break;
+                               case 'right':
+                                       pLeft += wnd.width() - this.uiDialog.outerWidth();
+                                       break;
+                               default:
+                               case 'center':
+                                       pLeft += (wnd.width() - this.uiDialog.outerWidth()) / 2;
+                       }
+               }
+               if (pos[1].constructor == Number) {
+                       pTop += pos[1];
+               } else {
+                       switch (pos[1]) {
+                               case 'top':
+                                       pTop += 0;
+                                       break;
+                               case 'bottom':
+                                       pTop += wnd.height() - this.uiDialog.outerHeight();
+                                       break;
+                               default:
+                               case 'middle':
+                                       pTop += (wnd.height() - this.uiDialog.outerHeight()) / 2;
+                       }
+               }
+
+               // prevent the dialog from being too high (make sure the titlebar
+               // is accessible)
+               pTop = Math.max(pTop, minTop);
+               this.uiDialog.css({top: pTop, left: pLeft});
+       },
+
+       _setData: function(key, value){
+               (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value));
+               switch (key) {
+                       case "buttons":
+                               this._createButtons(value);
+                               break;
+                       case "closeText":
+                               this.uiDialogTitlebarCloseText.text(value);
+                               break;
+                       case "dialogClass":
+                               this.uiDialog
+                                       .removeClass(this.options.dialogClass)
+                                       .addClass(uiDialogClasses + value);
+                               break;
+                       case "draggable":
+                               (value
+                                       ? this._makeDraggable()
+                                       : this.uiDialog.draggable('destroy'));
+                               break;
+                       case "height":
+                               this.uiDialog.height(value);
+                               break;
+                       case "position":
+                               this._position(value);
+                               break;
+                       case "resizable":
+                               var uiDialog = this.uiDialog,
+                                       isResizable = this.uiDialog.is(':data(resizable)');
+
+                               // currently resizable, becoming non-resizable
+                               (isResizable && !value && uiDialog.resizable('destroy'));
+
+                               // currently resizable, changing handles
+                               (isResizable && typeof value == 'string' &&
+                                       uiDialog.resizable('option', 'handles', value));
+
+                               // currently non-resizable, becoming resizable
+                               (isResizable || this._makeResizable(value));
+                               break;
+                       case "title":
+                               $(".ui-dialog-title", this.uiDialogTitlebar).html(value || '&nbsp;');
+                               break;
+                       case "width":
+                               this.uiDialog.width(value);
+                               break;
+               }
+
+               $.widget.prototype._setData.apply(this, 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;
+
+               // reset content sizing
+               this.element.css({
+                       height: 0,
+                       minHeight: 0,
+                       width: 'auto'
+               });
+
+               // reset wrapper sizing
+               // determine the height of all the non-content elements
+               var nonContentHeight = this.uiDialog.css({
+                               height: 'auto',
+                               width: options.width
+                       })
+                       .height();
+
+               this.element
+                       .css({
+                               minHeight: Math.max(options.minHeight - nonContentHeight, 0),
+                               height: options.height == 'auto'
+                                       ? 'auto'
+                                       : Math.max(options.height - nonContentHeight, 0)
+                       });
+       }
+});
+
+$.extend($.ui.dialog, {
+       version: "1.7.1",
+       defaults: {
+               autoOpen: true,
+               bgiframe: false,
+               buttons: {},
+               closeOnEscape: true,
+               closeText: 'close',
+               dialogClass: '',
+               draggable: true,
+               hide: null,
+               height: 'auto',
+               maxHeight: false,
+               maxWidth: false,
+               minHeight: 150,
+               minWidth: 150,
+               modal: false,
+               position: 'center',
+               resizable: true,
+               show: null,
+               stack: true,
+               title: '',
+               width: 300,
+               zIndex: 1000
+       },
+
+       getter: 'isOpen',
+
+       uuid: 0,
+       maxZ: 0,
+
+       getTitleId: function($el) {
+               return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid);
+       },
+
+       overlay: function(dialog) {
+               this.$el = $.ui.dialog.overlay.create(dialog);
+       }
+});
+
+$.extend($.ui.dialog.overlay, {
+       instances: [],
+       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() {
+                               $(document).bind($.ui.dialog.overlay.events, function(event) {
+                                       var dialogZ = $(event.target).parents('.ui-dialog').css('zIndex') || 0;
+                                       return (dialogZ > $.ui.dialog.overlay.maxZ);
+                               });
+                       }, 1);
+
+                       // allow closing by pressing the escape key
+                       $(document).bind('keydown.dialog-overlay', function(event) {
+                               (dialog.options.closeOnEscape && event.keyCode
+                                               && event.keyCode == $.ui.keyCode.ESCAPE && dialog.close(event));
+                       });
+
+                       // handle window resize
+                       $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
+               }
+
+               var $el = $('<div></div>').appendTo(document.body)
+                       .addClass('ui-widget-overlay').css({
+                               width: this.width(),
+                               height: this.height()
+                       });
+
+               (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe());
+
+               this.instances.push($el);
+               return $el;
+       },
+
+       destroy: function($el) {
+               this.instances.splice($.inArray(this.instances, $el), 1);
+
+               if (this.instances.length === 0) {
+                       $([document, window]).unbind('.dialog-overlay');
+               }
+
+               $el.remove();
+       },
+
+       height: function() {
+               // handle IE 6
+               if ($.browser.msie && $.browser.version < 7) {
+                       var scrollHeight = Math.max(
+                               document.documentElement.scrollHeight,
+                               document.body.scrollHeight
+                       );
+                       var 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() {
+               // handle IE 6
+               if ($.browser.msie && $.browser.version < 7) {
+                       var scrollWidth = Math.max(
+                               document.documentElement.scrollWidth,
+                               document.body.scrollWidth
+                       );
+                       var 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 Slider 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ *     ui.core.js
+ */
+
+(function($) {
+
+$.widget("ui.slider", $.extend({}, $.ui.mouse, {
+
+       _init: function() {
+
+               var self = this, o = this.options;
+               this._keySliding = false;
+               this._handleIndex = null;
+               this._detectOrientation();
+               this._mouseInit();
+
+               this.element
+                       .addClass("ui-slider"
+                               + " ui-slider-" + this.orientation
+                               + " ui-widget"
+                               + " ui-widget-content"
+                               + " ui-corner-all");
+
+               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() { $(this).addClass('ui-state-hover'); }, function() { $(this).removeClass('ui-state-hover'); })
+                       .focus(function() { $(".ui-slider .ui-state-focus").removeClass('ui-state-focus'); $(this).addClass('ui-state-focus'); })
+                       .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;
+
+                       var index = $(this).data("index.ui-slider-handle");
+
+                       if (self.options.disabled)
+                               return;
+
+                       switch (event.keyCode) {
+                               case $.ui.keyCode.HOME:
+                               case $.ui.keyCode.END:
+                               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");
+                                               self._start(event, index);
+                                       }
+                                       break;
+                       }
+
+                       var curVal, newVal, step = self._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.UP:
+                               case $.ui.keyCode.RIGHT:
+                                       if(curVal == self._valueMax()) return;
+                                       newVal = curVal + step;
+                                       break;
+                               case $.ui.keyCode.DOWN:
+                               case $.ui.keyCode.LEFT:
+                                       if(curVal == self._valueMin()) return;
+                                       newVal = 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._stop(event, index);
+                               self._change(event, index);
+                               self._keySliding = false;
+                               $(this).removeClass("ui-state-active");
+                       }
+
+               });
+
+               this._refreshValue();
+
+       },
+
+       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();
+
+       },
+
+       _mouseCapture: function(event) {
+
+               var o = this.options;
+
+               if (o.disabled)
+                       return false;
+
+               this.elementSize = {
+                       width: this.element.outerWidth(),
+                       height: this.element.outerHeight()
+               };
+               this.elementOffset = this.element.offset();
+
+               var position = { x: event.pageX, y: event.pageY };
+               var normValue = this._normValueFromMouse(position);
+
+               var distance = this._valueMax() - this._valueMin() + 1, closestHandle;
+               var self = this, index;
+               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) {
+                       closestHandle = $(this.handles[++index]);
+               }
+
+               this._start(event, index);
+
+               self._handleIndex = index;
+
+               closestHandle
+                       .addClass("ui-state-active")
+                       .focus();
+               
+               var offset = closestHandle.offset();
+               var 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)
+               };
+
+               normValue = this._normValueFromMouse(position);
+               this._slide(event, index, normValue);
+               return true;
+
+       },
+
+       _mouseStart: function(event) {
+               return true;
+       },
+
+       _mouseDrag: function(event) {
+
+               var position = { x: event.pageX, y: event.pageY };
+               var normValue = this._normValueFromMouse(position);
+               
+               this._slide(event, this._handleIndex, normValue);
+
+               return false;
+
+       },
+
+       _mouseStop: function(event) {
+
+               this.handles.removeClass("ui-state-active");
+               this._stop(event, this._handleIndex);
+               this._change(event, this._handleIndex);
+               this._handleIndex = null;
+               this._clickOffset = null;
+
+               return false;
+
+       },
+       
+       _detectOrientation: function() {
+               this.orientation = this.options.orientation == 'vertical' ? 'vertical' : 'horizontal';
+       },
+
+       _normValueFromMouse: function(position) {
+
+               var pixelTotal, pixelMouse;
+               if ('horizontal' == this.orientation) {
+                       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);
+               }
+
+               var percentMouse = (pixelMouse / pixelTotal);
+               if (percentMouse > 1) percentMouse = 1;
+               if (percentMouse < 0) percentMouse = 0;
+               if ('vertical' == this.orientation)
+                       percentMouse = 1 - percentMouse;
+
+               var valueTotal = this._valueMax() - this._valueMin(),
+                       valueMouse = percentMouse * valueTotal,
+                       valueMouseModStep = valueMouse % this.options.step,
+                       normValue = this._valueMin() + valueMouse - valueMouseModStep;
+
+               if (valueMouseModStep > (this.options.step / 2))
+                       normValue += this.options.step;
+
+               // Since JavaScript has problems with large floats, round
+               // the final value to 5 digits after the decimal point (see #4124)
+               return parseFloat(normValue.toFixed(5));
+
+       },
+
+       _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()
+               }
+               this._trigger("start", event, uiHash);
+       },
+
+       _slide: function(event, index, newVal) {
+
+               var handle = this.handles[index];
+
+               if (this.options.values && this.options.values.length) {
+
+                       var otherVal = this.values(index ? 0 : 1);
+
+                       if ((index == 0 && newVal >= otherVal) || (index == 1 && newVal <= otherVal))
+                               newVal = otherVal;
+
+                       if (newVal != this.values(index)) {
+                               var newValues = this.values();
+                               newValues[index] = newVal;
+                               // A slide can be canceled by returning false from the slide callback
+                               var allowed = this._trigger("slide", event, {
+                                       handle: this.handles[index],
+                                       value: newVal,
+                                       values: newValues
+                               });
+                               var otherVal = this.values(index ? 0 : 1);
+                               if (allowed !== false) {
+                                       this.values(index, newVal, ( event.type == 'mousedown' && this.options.animate ), true);
+                               }
+                       }
+
+               } else {
+
+                       if (newVal != this.value()) {
+                               // A slide can be canceled by returning false from the slide callback
+                               var allowed = this._trigger("slide", event, {
+                                       handle: this.handles[index],
+                                       value: newVal
+                               });
+                               if (allowed !== false) {
+                                       this._setData('value', newVal, ( event.type == 'mousedown' && this.options.animate ));
+                               }
+                                       
+                       }
+
+               }
+
+       },
+
+       _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) {
+               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._setData("value", newValue);
+                       this._change(null, 0);
+               }
+
+               return this._value();
+
+       },
+
+       values: function(index, newValue, animated, noPropagation) {
+
+               if (arguments.length > 1) {
+                       this.options.values[index] = newValue;
+                       this._refreshValue(animated);
+                       if(!noPropagation) this._change(null, index);
+               }
+
+               if (arguments.length) {
+                       if (this.options.values && this.options.values.length) {
+                               return this._values(index);
+                       } else {
+                               return this.value();
+                       }
+               } else {
+                       return this._values();
+               }
+
+       },
+
+       _setData: function(key, value, animated) {
+
+               $.widget.prototype._setData.apply(this, arguments);
+
+               switch (key) {
+                       case 'orientation':
+
+                               this._detectOrientation();
+                               
+                               this.element
+                                       .removeClass("ui-slider-horizontal ui-slider-vertical")
+                                       .addClass("ui-slider-" + this.orientation);
+                               this._refreshValue(animated);
+                               break;
+                       case 'value':
+                               this._refreshValue(animated);
+                               break;
+               }
+
+       },
+
+       _step: function() {
+               var step = this.options.step;
+               return step;
+       },
+
+       _value: function() {
+
+               var val = this.options.value;
+               if (val < this._valueMin()) val = this._valueMin();
+               if (val > this._valueMax()) val = this._valueMax();
+
+               return val;
+
+       },
+
+       _values: function(index) {
+
+               if (arguments.length) {
+                       var val = this.options.values[index];
+                       if (val < this._valueMin()) val = this._valueMin();
+                       if (val > this._valueMax()) val = this._valueMax();
+
+                       return val;
+               } else {
+                       return this.options.values;
+               }
+
+       },
+
+       _valueMin: function() {
+               var valueMin = this.options.min;
+               return valueMin;
+       },
+
+       _valueMax: function() {
+               var valueMax = this.options.max;
+               return valueMax;
+       },
+
+       _refreshValue: function(animate) {
+
+               var oRange = this.options.range, o = this.options, self = this;
+
+               if (this.options.values && this.options.values.length) {
+                       var vp0, vp1;
+                       this.handles.each(function(i, j) {
+                               var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100;
+                               var _set = {}; _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') {
+                                               (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ left: valPercent + '%' }, o.animate);
+                                               (i == 1) && self.range[animate ? 'animate' : 'css']({ width: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });
+                                       } else {
+                                               (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ bottom: (valPercent) + '%' }, o.animate);
+                                               (i == 1) && self.range[animate ? 'animate' : 'css']({ height: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });
+                                       }
+                               }
+                               lastValPercent = valPercent;
+                       });
+               } else {
+                       var value = this.value(),
+                               valueMin = this._valueMin(),
+                               valueMax = this._valueMax(),
+                               valPercent = valueMax != valueMin
+                                       ? (value - valueMin) / (valueMax - valueMin) * 100
+                                       : 0;
+                       var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%';
+                       this.handle.stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate);
+
+                       (oRange == "min") && (this.orientation == "horizontal") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ width: valPercent + '%' }, o.animate);
+                       (oRange == "max") && (this.orientation == "horizontal") && this.range[animate ? 'animate' : 'css']({ width: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });
+                       (oRange == "min") && (this.orientation == "vertical") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ height: valPercent + '%' }, o.animate);
+                       (oRange == "max") && (this.orientation == "vertical") && this.range[animate ? 'animate' : 'css']({ height: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });
+               }
+
+       }
+       
+}));
+
+$.extend($.ui.slider, {
+       getter: "value values",
+       version: "1.7.1",
+       eventPrefix: "slide",
+       defaults: {
+               animate: false,
+               delay: 0,
+               distance: 0,
+               max: 100,
+               min: 0,
+               orientation: 'horizontal',
+               range: false,
+               step: 1,
+               value: 0,
+               values: null
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Tabs 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.tabs", {
+
+       _init: function() {
+               if (this.options.deselectable !== undefined) {
+                       this.options.collapsible = this.options.deselectable;
+               }
+               this._tabify(true);
+       },
+
+       _setData: function(key, value) {
+               if (key == 'selected') {
+                       if (this.options.collapsible && value == this.options.selected) {
+                               return;
+                       }
+                       this.select(value);
+               }
+               else {
+                       this.options[key] = value;
+                       if (key == 'deselectable') {
+                               this.options.collapsible = value;
+                       }
+                       this._tabify();
+               }
+       },
+
+       _tabId: function(a) {
+               return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
+                       this.options.idPrefix + $.data(a);
+       },
+
+       _sanitizeSelector: function(hash) {
+               return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
+       },
+
+       _cookie: function() {
+               var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0]));
+               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) {
+
+               this.list = this.element.children('ul:first');
+               this.lis = $('li:has(a[href])', this.list);
+               this.anchors = this.lis.map(function() { return $('a', this)[0]; });
+               this.panels = $([]);
+
+               var self = this, o = this.options;
+
+               var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
+               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._sanitizeSelector(href));
+                       }
+
+                       // remote tab
+                       else if (href != '#') { // prevent loading the page itself if href is just "#"
+                               $.data(a, 'href.tabs', href); // required for restore on destroy
+
+                               // TODO until #3808 is fixed strip fragment identifier from url
+                               // (IE fails to load from such url)
+                               $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data
+
+                               var id = self._tabId(a);
+                               a.href = '#' + id;
+                               var $panel = $('#' + 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; // break
+                                               }
+                                       });
+                               }
+                               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 || 0;
+                       }
+                       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');
+                       if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
+                               this.panels.eq(o.selected).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.panels[o.selected]));
+                               });
+                               
+                               this.load(o.selected);
+                       }
+
+                       // clean up to avoid memory leaks in certain versions of IE 6
+                       $(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
+               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 &&
+                               !$(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 ($.browser.msie && fx.opacity) {
+                               $el[0].style.removeAttribute('filter');
+                       }
+               }
+
+               // Show a tab...
+               var showTab = showFx ?
+                       function(clicked, $show) {
+                               $(clicked).closest('li').removeClass('ui-state-default').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').removeClass('ui-state-default').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').addClass('ui-state-default');
+                                       $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').addClass('ui-state-default');
+                               $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 = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
+                                       $show = $(self._sanitizeSelector(this.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._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);
+                                       });
+
+                                       self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
+                                       
+                                       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;});
+
+       },
+
+       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);
+               }
+       },
+
+       add: function(url, label, index) {
+               if (index === undefined) {
+                       index = this.anchors.length; // append by default
+               }
+
+               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 = $('#' + 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) { // after tabify
+                       $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);
+               }
+
+               // callback
+               this._trigger('add', null, this._ui(this.anchors[index], this.panels[index]));
+       },
+
+       remove: function(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();
+
+               // callback
+               this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0]));
+       },
+
+       enable: function(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; });
+
+               // callback
+               this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index]));
+       },
+
+       disable: function(index) {
+               var self = this, o = this.options;
+               if (index != o.selected) { // cannot disable already selected tab
+                       this.lis.eq(index).addClass('ui-state-disabled');
+
+                       o.disabled.push(index);
+                       o.disabled.sort();
+
+                       // callback
+                       this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index]));
+               }
+       },
+
+       select: function(index) {
+               if (typeof index == 'string') {
+                       index = this.anchors.index(this.anchors.filter('[href$=' + index + ']'));
+               }
+               else if (index === null) { // usage of null is deprecated, TODO remove in next release
+                       index = -1;
+               }
+               if (index == -1 && this.options.collapsible) {
+                       index = this.options.selected;
+               }
+
+               this.anchors.eq(index).trigger(this.options.event + '.tabs');
+       },
+
+       load: function(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._sanitizeSelector(a.hash)).html(r);
+
+                               // take care of tab labels
+                               self._cleanup();
+
+                               if (o.cache) {
+                                       $.data(a, 'cache.tabs', true); // if loaded once do not load them again
+                               }
+
+                               // callbacks
+                               self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
+                               try {
+                                       o.ajaxOptions.success(r, s);
+                               }
+                               catch (e) {}
+
+                               // last, so that load event is fired before show...
+                               self.element.dequeue("tabs");
+                       }
+               }));
+       },
+
+       abort: function() {
+               // stop possibly running animations
+               this.element.queue([]);
+               this.panels.stop(false, true);
+
+               // terminate pending requests from other tabs
+               if (this.xhr) {
+                       this.xhr.abort();
+                       delete this.xhr;
+               }
+
+               // take care of tab labels
+               this._cleanup();
+
+       },
+
+       url: function(index, url) {
+               this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url);
+       },
+
+       length: function() {
+               return this.anchors.length;
+       }
+
+});
+
+$.extend($.ui.tabs, {
+       version: '1.7.1',
+       getter: 'length',
+       defaults: {
+               ajaxOptions: null,
+               cache: false,
+               cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
+               collapsible: false,
+               disabled: [],
+               event: 'click',
+               fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
+               idPrefix: 'ui-tabs-',
+               panelTemplate: '<div></div>',
+               spinner: '<em>Loading&#8230;</em>',
+               tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
+       }
+});
+
+/*
+ * 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;
+               }
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Datepicker 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Datepicker
+ *
+ * Depends:
+ *     ui.core.js
+ */
+
+(function($) { // hide the namespace
+
+$.extend($.ui, { datepicker: { version: "1.7.1" } });
+
+var PROP_NAME = 'datepicker';
+
+/* 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
+               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
+       };
+       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: 'show', // 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
+               showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+               yearRange: '-10:+10', // Range of years to display in drop-down,
+                       // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
+               showOtherMonths: false, // True to show dates in other months, false to leave blank
+               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: 'normal', // 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
+       };
+       $.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 ui-helper-hidden-accessible"></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);
+       },
+
+       /* 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)
+                       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(/([:\[\]\.])/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.trigger = $([]);
+               if (input.hasClass(this.markerClassName))
+                       return;
+               var appendText = this._get(inst, 'appendText');
+               var isRTL = this._get(inst, 'isRTL');
+               if (appendText)
+                       input[isRTL ? 'before' : 'after']('<span class="' + this._appendClass + '">' + appendText + '</span>');
+               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 == target)
+                                       $.datepicker._hideDatepicker();
+                               else
+                                       $.datepicker._showDatepicker(target);
+                               return false;
+                       });
+               }
+               input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
+                       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);
+       },
+
+       /* 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));
+               this._updateDatepicker(inst);
+               this._updateAlternate(inst);
+       },
+
+       /* Pop-up the date picker in a "dialog" box.
+          @param  input     element - ignored
+          @param  dateText  string - the initial date to display (in the current format)
+          @param  onSelect  function - the function(dateText) 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, dateText, onSelect, settings, pos) {
+               var inst = this._dialogInst; // internal instance
+               if (!inst) {
+                       var id = 'dp' + (++this.uuid);
+                       this._dialogInput = $('<input type="text" id="' + id +
+                               '" size="1" style="position: absolute; top: -100px;"/>');
+                       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 || {});
+               this._dialogInput.val(dateText);
+
+               this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+               if (!this._pos) {
+                       var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
+                       var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.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] + '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.trigger.remove();
+                       $target.siblings('.' + this._appendClass).remove().end().
+                               removeClass(this.markerClassName).
+                               unbind('focus', this._showDatepicker).
+                               unbind('keydown', this._doKeyDown).
+                               unbind('keypress', this._doKeyPress);
+               } 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 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
+          @param  value   any - the new value for the setting (omit if above is an object) */
+       _optionDatepicker: function(target, name, value) {
+               var settings = name || {};
+               if (typeof name == 'string') {
+                       settings = {};
+                       settings[name] = value;
+               }
+               var inst = this._getInst(target);
+               if (inst) {
+                       if (this._curInst == inst) {
+                               this._hideDatepicker(null);
+                       }
+                       extendRemove(inst.settings, settings);
+                       var date = new Date();
+                       extendRemove(inst, {rangeStart: null, // start of range
+                               endDay: null, endMonth: null, endYear: null, // end of range
+                               selectedDay: date.getDate(), selectedMonth: date.getMonth(),
+                               selectedYear: date.getFullYear(), // starting point
+                               currentDay: date.getDate(), currentMonth: date.getMonth(),
+                               currentYear: date.getFullYear(), // current selection
+                               drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn
+                       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
+          @param  endDate  Date - the new end date for a range (optional) */
+       _setDateDatepicker: function(target, date, endDate) {
+               var inst = this._getInst(target);
+               if (inst) {
+                       this._setDate(inst, date, endDate);
+                       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
+          @return Date - the current date or
+                  Date[2] - the current dates for a range */
+       _getDateDatepicker: function(target) {
+               var inst = this._getInst(target);
+               if (inst && !inst.inline)
+                       this._setDateFromField(inst);
+               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(null, '');
+                                               break; // hide on tab out
+                               case 13: var sel = $('td.' + $.datepicker._dayOverClass +
+                                                       ', td.' + $.datepicker._currentClass, inst.dpDiv);
+                                               if (sel[0])
+                                                       $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+                                               else
+                                                       $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
+                                               return false; // don't submit the form
+                                               break; // select the value on enter
+                               case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
+                                               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 || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
+               }
+       },
+
+       /* 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);
+               var beforeShow = $.datepicker._get(inst, 'beforeShow');
+               extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
+               $.datepicker._hideDatepicker(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;
+               inst.rangeStart = null;
+               // 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') || 'show';
+                       var duration = $.datepicker._get(inst, 'duration');
+                       var postProcess = function() {
+                               $.datepicker._datepickerShowing = true;
+                               if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems
+                                       $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
+                                               height: inst.dpDiv.height() + 4});
+                       };
+                       if ($.effects && $.effects[showAnim])
+                               inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
+                       else
+                               inst.dpDiv[showAnim](duration, postProcess);
+                       if (duration == '')
+                               postProcess();
+                       if (inst.input[0].type != 'hidden')
+                               inst.input[0].focus();
+                       $.datepicker._curInst = inst;
+               }
+       },
+
+       /* Generate the date picker content. */
+       _updateDatepicker: function(inst) {
+               var dims = {width: inst.dpDiv.width() + 4,
+                       height: inst.dpDiv.height() + 4};
+               var self = this;
+               inst.dpDiv.empty().append(this._generateHTML(inst))
+                       .find('iframe.ui-datepicker-cover').
+                               css({width: dims.width, height: dims.height})
+                       .end()
+                       .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.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst)
+                       $(inst.input[0]).focus();
+       },
+
+       /* 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 = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft();
+               var viewHeight = (window.innerHeight || document.documentElement.clientHeight || document.body.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 -= (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0;
+               offset.top -= (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(offset.top + dpHeight + inputHeight*2 - viewHeight) : 0;
+
+               return offset;
+       },
+
+       /* Find an object's position on the screen. */
+       _findPos: function(obj) {
+        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
+            obj = obj.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
+          @param  duration  string - the duration over which to close the date picker */
+       _hideDatepicker: function(input, duration) {
+               var inst = this._curInst;
+               if (!inst || (input && inst != $.data(input, PROP_NAME)))
+                       return;
+               if (inst.stayOpen)
+                       this._selectDate('#' + inst.id, this._formatDate(inst,
+                               inst.currentDay, inst.currentMonth, inst.currentYear));
+               inst.stayOpen = false;
+               if (this._datepickerShowing) {
+                       duration = (duration != null ? duration : this._get(inst, 'duration'));
+                       var showAnim = this._get(inst, 'showAnim');
+                       var postProcess = function() {
+                               $.datepicker._tidyDialog(inst);
+                       };
+                       if (duration != '' && $.effects && $.effects[showAnim])
+                               inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
+                                       duration, postProcess);
+                       else
+                               inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
+                                       (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
+                       if (duration == '')
+                               this._tidyDialog(inst);
+                       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;
+               }
+               this._curInst = null;
+       },
+
+       /* 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.parents('#' + $.datepicker._mainDivId).length == 0) &&
+                               !$target.hasClass($.datepicker.markerClassName) &&
+                               !$target.hasClass($.datepicker._triggerClass) &&
+                               $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
+                       $.datepicker._hideDatepicker(null, '');
+       },
+
+       /* 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 && !$.browser.msie)
+                       inst.input[0].focus();
+               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;
+               if (inst.stayOpen) {
+                       inst.endDay = inst.endMonth = inst.endYear = null;
+               }
+               this._selectDate(id, this._formatDate(inst,
+                       inst.currentDay, inst.currentMonth, inst.currentYear));
+               if (inst.stayOpen) {
+                       inst.rangeStart = this._daylightSavingAdjust(
+                               new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
+                       this._updateDatepicker(inst);
+               }
+       },
+
+       /* Erase the input field and hide the date picker. */
+       _clearDate: function(id) {
+               var target = $(id);
+               var inst = this._getInst(target[0]);
+               inst.stayOpen = false;
+               inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
+               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 if (!inst.stayOpen) {
+                       this._hideDatepicker(null, this._get(inst, 'duration'));
+                       this._lastInput = inst.input[0];
+                       if (typeof(inst.input[0]) != 'object')
+                               inst.input[0].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);
+                       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.getFullYear(), date.getMonth(), date.getDate());
+               var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
+               var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
+               firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
+               if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
+                       checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
+                       return $.datepicker.iso8601Week(checkDate);
+               } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
+                       firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
+                       if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
+                               return 1;
+                       }
+               }
+               return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
+       },
+
+       /* 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;
+               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) {
+                       lookAhead(match);
+                       var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2)));
+                       var size = origSize;
+                       var num = 0;
+                       while (size > 0 && iValue < value.length &&
+                                       value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
+                               num = num * 10 + parseInt(value.charAt(iValue++),10);
+                               size--;
+                       }
+                       if (size == origSize)
+                               throw 'Missing number at position ' + iValue;
+                       return num;
+               };
+               // Extract a name from the string value and convert to an index
+               var getName = function(match, shortNames, longNames) {
+                       var names = (lookAhead(match) ? longNames : shortNames);
+                       var size = 0;
+                       for (var j = 0; j < names.length; j++)
+                               size = Math.max(size, names[j].length);
+                       var name = '';
+                       var iInit = iValue;
+                       while (size > 0 && iValue < value.length) {
+                               name += value.charAt(iValue++);
+                               for (var i = 0; i < names.length; i++)
+                                       if (name == names[i])
+                                               return i + 1;
+                               size--;
+                       }
+                       throw 'Unknown name at position ' + iInit;
+               };
+               // 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 "'":
+                                               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/*
+               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
+       TIMESTAMP: '@',
+       W3C: 'yy-mm-dd', // ISO 8601
+
+       /* 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)
+          '...' - 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':
+                                                       var doy = date.getDate();
+                                                       for (var m = date.getMonth() - 1; m >= 0; m--)
+                                                               doy += this._getDaysInMonth(date.getFullYear(), m);
+                                                       output += formatNumber('o', doy, 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 "'":
+                                                       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;
+               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) {
+               var dateFormat = this._get(inst, 'dateFormat');
+               var dates = inst.input ? inst.input.val() : null;
+               inst.endDay = inst.endMonth = inst.endYear = null;
+               var date = defaultDate = this._getDefaultDate(inst);
+               var settings = this._getFormatConfig(inst);
+               try {
+                       date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+               } catch (event) {
+                       this.log(event);
+                       date = defaultDate;
+               }
+               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) {
+               var date = this._determineDate(this._get(inst, 'defaultDate'), new Date());
+               var minDate = this._getMinMaxDate(inst, 'min', true);
+               var maxDate = this._getMinMaxDate(inst, 'max');
+               date = (minDate && date < minDate ? minDate : date);
+               date = (maxDate && date > maxDate ? maxDate : date);
+               return date;
+       },
+
+       /* A date may be specified as an exact value or a relative one. */
+       _determineDate: function(date, defaultDate) {
+               var offsetNumeric = function(offset) {
+                       var date = new Date();
+                       date.setDate(date.getDate() + offset);
+                       return date;
+               };
+               var offsetString = function(offset, getDaysInMonth) {
+                       var date = 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, getDaysInMonth(year, month));
+                                               break;
+                                       case 'y': case 'Y' :
+                                               year += parseInt(matches[1],10);
+                                               day = Math.min(day, getDaysInMonth(year, month));
+                                               break;
+                               }
+                               matches = pattern.exec(offset);
+                       }
+                       return new Date(year, month, day);
+               };
+               date = (date == null ? defaultDate :
+                       (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
+                       (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
+               date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
+               if (date) {
+                       date.setHours(0);
+                       date.setMinutes(0);
+                       date.setSeconds(0);
+                       date.setMilliseconds(0);
+               }
+               return this._daylightSavingAdjust(date);
+       },
+
+       /* 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, endDate) {
+               var clear = !(date);
+               var origMonth = inst.selectedMonth;
+               var origYear = inst.selectedYear;
+               date = this._determineDate(date, new Date());
+               inst.selectedDay = inst.currentDay = date.getDate();
+               inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
+               inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
+               if (origMonth != inst.selectedMonth || origYear != inst.selectedYear)
+                       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 stepBigMonths = this._get(inst, 'stepBigMonths');
+               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', true);
+               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[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.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.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.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.datepicker._gotoToday(\'#' + inst.id + '\');"' +
+                       '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
+               var firstDay = parseInt(this._get(inst, 'firstDay'),10);
+               firstDay = (isNaN(firstDay) ? 0 : firstDay);
+               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 calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
+               var endDate = inst.endDay ? this._daylightSavingAdjust(
+                       new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate;
+               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 ui-datepicker-group-';
+                                       switch (col) {
+                                               case 0: calender += 'first'; cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
+                                               case numMonths[1]-1: calender += 'last'; cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
+                                               default: calender += '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,
+                                       selectedDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+                                       '</div><table class="ui-datepicker-calendar"><thead>' +
+                                       '<tr>';
+                               var thead = '';
+                               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 = '';
+                                       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 || !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() && printDate.getTime() <= endDate.getTime() ? // in current range
+                                                       ' ' + 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.datepicker._selectDay(\'#' +
+                                                       inst.id + '\',' + drawMonth + ',' + drawYear + ', this);return false;"') + '>' + // actions
+                                                       (otherMonth ? (showOtherMonths ? printDate.getDate() : '&#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() && printDate.getTime() <= endDate.getTime() ? // in current range
+                                                       ' ui-state-active' : '') + // highlight selected day
+                                                       '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
+                                               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,
+                       selectedDate, secondary, monthNames, monthNamesShort) {
+               minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
+               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.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
+                               'onclick="DP_jQuery.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) && (!(changeMonth && changeYear)) ? '&#xa0;' : '');
+               // year selection
+               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 year = 0;
+                       var endYear = 0;
+                       if (years.length != 2) {
+                               year = drawYear - 10;
+                               endYear = drawYear + 10;
+                       } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
+                               year = drawYear + parseInt(years[0], 10);
+                               endYear = drawYear + parseInt(years[1], 10);
+                       } else {
+                               year = parseInt(years[0], 10);
+                               endYear = parseInt(years[1], 10);
+                       }
+                       year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+                       endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+                       html += '<select class="ui-datepicker-year" ' +
+                               'onchange="DP_jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
+                               'onclick="DP_jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
+                               '>';
+                       for (; year <= endYear; year++) {
+                               html += '<option value="' + year + '"' +
+                                       (year == drawYear ? ' selected="selected"' : '') +
+                                       '>' + year + '</option>';
+                       }
+                       html += '</select>';
+               }
+               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._daylightSavingAdjust(new Date(year, month, day));
+               // ensure it is within the bounds set
+               var minDate = this._getMinMaxDate(inst, 'min', true);
+               var maxDate = this._getMinMaxDate(inst, 'max');
+               date = (minDate && date < minDate ? minDate : date);
+               date = (maxDate && date > maxDate ? maxDate : date);
+               inst.selectedDay = date.getDate();
+               inst.drawMonth = inst.selectedMonth = date.getMonth();
+               inst.drawYear = inst.selectedYear = date.getFullYear();
+               if (period == 'M' || period == 'Y')
+                       this._notifyChange(inst);
+       },
+
+       /* 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 - may be overridden for a range. */
+       _getMinMaxDate: function(inst, minMax, checkRange) {
+               var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
+               return (!checkRange || !inst.rangeStart ? date :
+                       (!date || inst.rangeStart > date ? inst.rangeStart : date));
+       },
+
+       /* Find the number of days in a given month. */
+       _getDaysInMonth: function(year, month) {
+               return 32 - 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[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) {
+               // during range selection, use minimum of selected date and range start
+               var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust(
+                       new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)));
+               newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
+               var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
+               var maxDate = this._getMinMaxDate(inst, 'max');
+               return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
+       },
+
+       /* 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){
+
+       /* 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'))
+               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.7.1";
+
+// Workaround for #4055
+// Add another global to avoid noConflict issues with inline event handlers
+window.DP_jQuery = $;
+
+})(jQuery);
+/*
+ * jQuery UI Progressbar 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Progressbar
+ *
+ * Depends:
+ *   ui.core.js
+ */
+(function($) {
+
+$.widget("ui.progressbar", {
+
+       _init: function() {
+
+               this.element
+                       .addClass("ui-progressbar"
+                               + " ui-widget"
+                               + " ui-widget-content"
+                               + " ui-corner-all")
+                       .attr({
+                               role: "progressbar",
+                               "aria-valuemin": this._valueMin(),
+                               "aria-valuemax": this._valueMax(),
+                               "aria-valuenow": this._value()
+                       });
+
+               this.valueDiv = $('<div class="ui-progressbar-value ui-widget-header ui-corner-left"></div>').appendTo(this.element);
+
+               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")
+                       .removeData("progressbar")
+                       .unbind(".progressbar");
+
+               this.valueDiv.remove();
+
+               $.widget.prototype.destroy.apply(this, arguments);
+
+       },
+
+       value: function(newValue) {
+               arguments.length && this._setData("value", newValue);
+               return this._value();
+       },
+
+       _setData: function(key, value) {
+
+               switch (key) {
+                       case 'value':
+                               this.options.value = value;
+                               this._refreshValue();
+                               this._trigger('change', null, {});
+                               break;
+               }
+
+               $.widget.prototype._setData.apply(this, arguments);
+
+       },
+
+       _value: function() {
+
+               var val = this.options.value;
+               if (val < this._valueMin()) val = this._valueMin();
+               if (val > this._valueMax()) val = this._valueMax();
+
+               return val;
+
+       },
+
+       _valueMin: function() {
+               var valueMin = 0;
+               return valueMin;
+       },
+
+       _valueMax: function() {
+               var valueMax = 100;
+               return valueMax;
+       },
+
+       _refreshValue: function() {
+               var value = this.value();
+               this.valueDiv[value == this._valueMax() ? 'addClass' : 'removeClass']("ui-corner-right");
+               this.valueDiv.width(value + '%');
+               this.element.attr("aria-valuenow", value);
+       }
+
+});
+
+$.extend($.ui.progressbar, {
+       version: "1.7.1",
+       defaults: {
+               value: 0
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Effects 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/
+ */
+;jQuery.effects || (function($) {
+
+$.effects = {
+       version: "1.7.1",
+
+       // 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();
+
+               //Cache width,height and float properties of the element, and create a wrapper around it
+               var props = { width: element.outerWidth(true), height: element.outerHeight(true), 'float': element.css('float') };
+               element.wrap('<div class="ui-effects-wrapper" style="font-size:100%;background:transparent;border:none;margin:0;padding:0"></div>');
+               var wrapper = element.parent();
+
+               //Transfer the positioning of the element to the wrapper
+               if (element.css('position') == 'static') {
+                       wrapper.css({ position: 'relative' });
+                       element.css({ position: 'relative'} );
+               } else {
+                       var top = element.css('top'); if(isNaN(parseInt(top,10))) top = 'auto';
+                       var left = element.css('left'); if(isNaN(parseInt(left,10))) left = 'auto';
+                       wrapper.css({ position: element.css('position'), top: top, left: left, zIndex: element.css('z-index') }).show();
+                       element.css({position: 'relative', top: 0, left: 0 });
+               }
+
+               wrapper.css(props);
+               return wrapper;
+       },
+
+       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;
+       },
+
+       //Base function to animate from one class to another in a seamless transition
+       animateClass: function(value, duration, easing, callback) {
+
+               var cb = (typeof easing == "function" ? easing : (callback ? callback : null));
+               var ea = (typeof easing == "string" ? easing : null);
+
+               return this.each(function() {
+
+                       var offset = {}; var that = $(this); var oldStyleAttr = that.attr("style") || '';
+                       if(typeof oldStyleAttr == 'object') oldStyleAttr = oldStyleAttr["cssText"]; /* Stupidly in IE, style is a object.. */
+                       if(value.toggle) { that.hasClass(value.toggle) ? value.remove = value.toggle : value.add = value.toggle; }
+
+                       //Let's get a style offset
+                       var oldStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle));
+                       if(value.add) that.addClass(value.add); if(value.remove) that.removeClass(value.remove);
+                       var newStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle));
+                       if(value.add) that.removeClass(value.add); if(value.remove) that.addClass(value.remove);
+
+                       // The main function to form the object for animation
+                       for(var n in newStyle) {
+                               if( typeof newStyle[n] != "function" && newStyle[n] /* No functions and null properties */
+                               && n.indexOf("Moz") == -1 && n.indexOf("length") == -1 /* No mozilla spezific render properties. */
+                               && newStyle[n] != oldStyle[n] /* Only values that have changed are used for the animation */
+                               && (n.match(/color/i) || (!n.match(/color/i) && !isNaN(parseInt(newStyle[n],10)))) /* Only things that can be parsed to integers or colors */
+                               && (oldStyle.position != "static" || (oldStyle.position == "static" && !n.match(/left|top|bottom|right/))) /* No need for positions when dealing with static positions */
+                               ) offset[n] = newStyle[n];
+                       }
+
+                       that.animate(offset, duration, ea, function() { // Animate the newly constructed offset object
+                               // Change style attribute back to original. For stupid IE, we need to clear the damn object.
+                               if(typeof $(this).attr("style") == 'object') { $(this).attr("style")["cssText"] = ""; $(this).attr("style")["cssText"] = oldStyleAttr; } else $(this).attr("style", oldStyleAttr);
+                               if(value.add) $(this).addClass(value.add); if(value.remove) $(this).removeClass(value.remove);
+                               if(cb) cb.apply(this, arguments);
+                       });
+
+               });
+       }
+};
+
+
+function _normalizeArguments(a, m) {
+
+       var o = a[1] && a[1].constructor == Object ? a[1] : {}; if(m) o.mode = m;
+       var speed = a[1] && a[1].constructor != Object ? a[1] : (o.duration ? o.duration : a[2]); //either comes from options.duration or the secon/third argument
+               speed = $.fx.off ? 0 : typeof speed === "number" ? speed : $.fx.speeds[speed] || $.fx.speeds._default;
+       var callback = o.callback || ( $.isFunction(a[1]) && a[1] ) || ( $.isFunction(a[2]) && a[2] ) || ( $.isFunction(a[3]) && a[3] );
+
+       return [a[0], o, speed, callback];
+       
+}
+
+//Extend the methods of jQuery
+$.fn.extend({
+
+       //Save old methods
+       _show: $.fn.show,
+       _hide: $.fn.hide,
+       __toggle: $.fn.toggle,
+       _addClass: $.fn.addClass,
+       _removeClass: $.fn.removeClass,
+       _toggleClass: $.fn.toggleClass,
+
+       // New effect methods
+       effect: function(fx, options, speed, callback) {
+               return $.effects[fx] ? $.effects[fx].call(this, {method: fx, options: options || {}, duration: speed, callback: callback }) : null;
+       },
+
+       show: function() {
+               if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])))
+                       return this._show.apply(this, arguments);
+               else {
+                       return this.effect.apply(this, _normalizeArguments(arguments, 'show'));
+               }
+       },
+
+       hide: function() {
+               if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])))
+                       return this._hide.apply(this, arguments);
+               else {
+                       return this.effect.apply(this, _normalizeArguments(arguments, 'hide'));
+               }
+       },
+
+       toggle: function(){
+               if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])) || (arguments[0].constructor == Function))
+                       return this.__toggle.apply(this, arguments);
+               else {
+                       return this.effect.apply(this, _normalizeArguments(arguments, 'toggle'));
+               }
+       },
+
+       addClass: function(classNames, speed, easing, callback) {
+               return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);
+       },
+       removeClass: function(classNames,speed,easing,callback) {
+               return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);
+       },
+       toggleClass: function(classNames,speed,easing,callback) {
+               return ( (typeof speed !== "boolean") && speed ) ? $.effects.animateClass.apply(this, [{ toggle: classNames },speed,easing,callback]) : this._toggleClass(classNames, speed);
+       },
+       morph: function(remove,add,speed,easing,callback) {
+               return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);
+       },
+       switchClass: function() {
+               return this.morph.apply(this, arguments);
+       },
+
+       // 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;
+       }
+});
+
+/*
+ * jQuery Color Animations
+ * Copyright 2007 John Resig
+ * Released under the MIT and GPL licenses.
+ */
+
+// We override the animation for all of these color styles
+$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
+               $.fx.step[attr] = function(fx) {
+                               if ( fx.state == 0 ) {
+                                               fx.start = getColor( fx.elem, attr );
+                                               fx.end = getRGB( fx.end );
+                               }
+
+                               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)
+                               ].join(",") + ")";
+                       };
+});
+
+// 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]
+};
+
+/*
+ * 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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Blind
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.blind = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Bounce
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.bounce = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Clip
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.clip = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left','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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Drop
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.drop = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left','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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Explode
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.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 Fold 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Fold
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.fold = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Highlight
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.highlight = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['backgroundImage','backgroundColor','opacity'];
+
+               // Set options
+               var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
+               var color = o.options.color || "#ffff99"; // Default highlight color
+               var oldColor = el.css("backgroundColor");
+
+               // Adjust
+               $.effects.save(el, props); el.show(); // Save & Show
+               el.css({backgroundImage: 'none', backgroundColor: color}); // Shift
+
+               // Animation
+               var animation = {backgroundColor: oldColor };
+               if (mode == "hide") animation['opacity'] = 0;
+
+               // Animate
+               el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
+                       if(mode == "hide") el.hide();
+                       $.effects.restore(el, props);
+               if (mode == "show" && $.browser.msie) this.style.removeAttribute('filter');
+                       if(o.callback) o.callback.apply(this, arguments);
+                       el.dequeue();
+               }});
+
+       });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Pulsate 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Pulsate
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.pulsate = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this);
+
+               // Set options
+               var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
+               var times = o.options.times || 5; // Default # of times
+               var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;
+
+               // Adjust
+               if (mode == 'hide') times--;
+               if (el.is(':hidden')) { // Show fadeIn
+                       el.css('opacity', 0);
+                       el.show(); // Show
+                       el.animate({opacity: 1}, duration, o.options.easing);
+                       times = times-2;
+               }
+
+               // Animate
+               for (var i = 0; i < times; i++) { // Pulsate
+                       el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing);
+               };
+               if (mode == 'hide') { // Last Pulse
+                       el.animate({opacity: 0}, duration, o.options.easing, function(){
+                               el.hide(); // Hide
+                               if(o.callback) o.callback.apply(this, arguments); // Callback
+                       });
+               } else {
+                       el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing, function(){
+                               if(o.callback) o.callback.apply(this, arguments); // Callback
+                       });
+               };
+               el.queue('fx', function() { el.dequeue(); });
+               el.dequeue();
+       });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Scale 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Scale
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.puff = 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 || 'hide'); // Set Mode
+               var percent = parseInt(o.options.percent,10) || 150; // Set default puff percent
+               options.fade = true; // It's not a puff if it doesn't fade! :)
+               var original = {height: el.height(), width: el.width()}; // Save original
+
+               // Adjust
+               var factor = percent / 100;
+               el.from = (mode == 'hide') ? original : {height: original.height * factor, width: original.width * factor};
+
+               // Animation
+               options.from = el.from;
+               options.percent = (mode == 'hide') ? percent : 100;
+               options.mode = mode;
+
+               // Animate
+               el.effect('scale', options, o.duration, o.callback);
+               el.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','left','width','height','overflow','opacity'];
+               var props1 = ['position','top','left','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(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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Shake
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.shake = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Slide
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.effects.slide = function(o) {
+
+       return this.queue(function() {
+
+               // Create element
+               var el = $(this), props = ['position','top','left'];
+
+               // 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' ? -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.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Effects/Transfer
+ *
+ * Depends:
+ *     effects.core.js
+ */
+(function($) {
+
+$.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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.accordion.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.accordion.js
new file mode 100644 (file)
index 0000000..0e94df1
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * jQuery UI Accordion 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Accordion
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.accordion", {
+
+       _init: function() {
+
+               var o = this.options, self = this;
+               this.running = 0;
+
+               // if the user set the alwaysOpen option on init
+               // then we need to set the collapsible option
+               // if they set both on init, collapsible will take priority
+               if (o.collapsible == $.ui.accordion.defaults.collapsible &&
+                       o.alwaysOpen != $.ui.accordion.defaults.alwaysOpen) {
+                       o.collapsible = !o.alwaysOpen;
+               }
+
+               if ( o.navigation ) {
+                       var current = this.element.find("a").filter(o.navigationFilter);
+                       if ( current.length ) {
+                               if ( current.filter(o.header).length ) {
+                                       this.active = current;
+                               } else {
+                                       this.active = current.parent().parent().prev();
+                                       current.addClass("ui-accordion-content-active");
+                               }
+                       }
+               }
+
+               this.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
+               if (this.element[0].nodeName == "UL") {
+                       this.element.children("li").addClass("ui-accordion-li-fix");
+               }
+
+               this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all")
+                       .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); })
+                       .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); })
+                       .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); })
+                       .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); });
+
+               this.headers
+                       .next()
+                               .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
+
+               this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");
+               this.active.next().addClass('ui-accordion-content-active');
+
+               //Append icon elements
+               $("<span/>").addClass("ui-icon " + o.icons.header).prependTo(this.headers);
+               this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected);
+
+               // IE7-/Win - Extra vertical space in lists fixed
+               if ($.browser.msie) {
+                       this.element.find('a').css('zoom', '1');
+               }
+
+               this.resize();
+
+               //ARIA
+               this.element.attr('role','tablist');
+
+               this.headers
+                       .attr('role','tab')
+                       .bind('keydown', function(event) { return self._keydown(event); })
+                       .next()
+                       .attr('role','tabpanel');
+
+               this.headers
+                       .not(this.active || "")
+                       .attr('aria-expanded','false')
+                       .attr("tabIndex", "-1")
+                       .next()
+                       .hide();
+
+               // make sure at least one header is in the tab order
+               if (!this.active.length) {
+                       this.headers.eq(0).attr('tabIndex','0');
+               } else {
+                       this.active
+                               .attr('aria-expanded','true')
+                               .attr('tabIndex', '0');
+               }
+
+               // only need links in taborder for Safari
+               if (!$.browser.safari)
+                       this.headers.find('a').attr('tabIndex','-1');
+
+               if (o.event) {
+                       this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); });
+               }
+
+       },
+
+       destroy: function() {
+               var o = this.options;
+
+               this.element
+                       .removeClass("ui-accordion ui-widget ui-helper-reset")
+                       .removeAttr("role")
+                       .unbind('.accordion')
+                       .removeData('accordion');
+
+               this.headers
+                       .unbind(".accordion")
+                       .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top")
+                       .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");
+
+               this.headers.find("a").removeAttr("tabindex");
+               this.headers.children(".ui-icon").remove();
+               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");
+               if (o.autoHeight || o.fillHeight) {
+                       contents.css("height", "");
+               }
+       },
+       
+       _setData: function(key, value) {
+               if(key == 'alwaysOpen') { key = 'collapsible'; value = !value; }
+               $.widget.prototype._setData.apply(this, arguments);     
+       },
+
+       _keydown: function(event) {
+
+               var o = this.options, keyCode = $.ui.keyCode;
+
+               if (o.disabled || event.altKey || event.ctrlKey)
+                       return;
+
+               var length = this.headers.length;
+               var currentIndex = this.headers.index(event.target);
+               var 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:
+                               return this._clickHandler({ target: event.target }, event.target);
+               }
+
+               if (toFocus) {
+                       $(event.target).attr('tabIndex','-1');
+                       $(toFocus).attr('tabIndex','0');
+                       toFocus.focus();
+                       return false;
+               }
+
+               return true;
+
+       },
+
+       resize: function() {
+
+               var o = this.options, maxHeight;
+
+               if (o.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();
+                       });
+
+                       var maxPadding = 0;
+                       this.headers.next().each(function() {
+                               maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
+                       }).height(Math.max(0, maxHeight - maxPadding))
+                       .css('overflow', 'auto');
+
+               } else if ( o.autoHeight ) {
+                       maxHeight = 0;
+                       this.headers.next().each(function() {
+                               maxHeight = Math.max(maxHeight, $(this).outerHeight());
+                       }).height(maxHeight);
+               }
+
+       },
+
+       activate: function(index) {
+               // call clickHandler with custom event
+               var active = this._findActive(index)[0];
+               this._clickHandler({ target: active }, active);
+       },
+
+       _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)");
+       },
+
+       _clickHandler: function(event, target) {
+
+               var o = this.options;
+               if (o.disabled) return false;
+
+               // called only when using activate(false) to close all parts programmatically
+               if (!event.target && o.collapsible) {
+                       this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
+                               .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
+                       this.active.next().addClass('ui-accordion-content-active');
+                       var toHide = this.active.next(),
+                               data = {
+                                       options: o,
+                                       newHeader: $([]),
+                                       oldHeader: o.active,
+                                       newContent: $([]),
+                                       oldContent: toHide
+                               },
+                               toShow = (this.active = $([]));
+                       this._toggle(toShow, toHide, data);
+                       return false;
+               }
+
+               // get the click target
+               var clicked = $(event.currentTarget || target);
+               var clickedIsActive = clicked[0] == this.active[0];
+
+               // if animations are still active, or the active header is the target, ignore click
+               if (this.running || (!o.collapsible && clickedIsActive)) {
+                       return false;
+               }
+
+               // switch classes
+               this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
+                       .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
+               this.active.next().addClass('ui-accordion-content-active');
+               if (!clickedIsActive) {
+                       clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top")
+                               .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected);
+                       clicked.next().addClass('ui-accordion-content-active');
+               }
+
+               // find elements to show and hide
+               var toShow = clicked.next(),
+                       toHide = this.active.next(),
+                       data = {
+                               options: o,
+                               newHeader: clickedIsActive && o.collapsible ? $([]) : clicked,
+                               oldHeader: this.active,
+                               newContent: clickedIsActive && o.collapsible ? $([]) : toShow.find('> *'),
+                               oldContent: toHide.find('> *')
+                       },
+                       down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );
+
+               this.active = clickedIsActive ? $([]) : clicked;
+               this._toggle(toShow, toHide, data, clickedIsActive, down);
+
+               return false;
+
+       },
+
+       _toggle: function(toShow, toHide, data, clickedIsActive, down) {
+
+               var o = this.options, self = this;
+
+               this.toShow = toShow;
+               this.toHide = toHide;
+               this.data = data;
+
+               var complete = function() { if(!self) return; return self._completed.apply(self, arguments); };
+
+               // trigger changestart event
+               this._trigger("changestart", null, this.data);
+
+               // count elements to animate
+               this.running = toHide.size() === 0 ? toShow.size() : toHide.size();
+
+               if (o.animated) {
+
+                       var animOptions = {};
+
+                       if ( o.collapsible && clickedIsActive ) {
+                               animOptions = {
+                                       toShow: $([]),
+                                       toHide: toHide,
+                                       complete: complete,
+                                       down: down,
+                                       autoHeight: o.autoHeight || o.fillSpace
+                               };
+                       } else {
+                               animOptions = {
+                                       toShow: toShow,
+                                       toHide: toHide,
+                                       complete: complete,
+                                       down: down,
+                                       autoHeight: o.autoHeight || o.fillSpace
+                               };
+                       }
+
+                       if (!o.proxied) {
+                               o.proxied = o.animated;
+                       }
+
+                       if (!o.proxiedDuration) {
+                               o.proxiedDuration = o.duration;
+                       }
+
+                       o.animated = $.isFunction(o.proxied) ?
+                               o.proxied(animOptions) : o.proxied;
+
+                       o.duration = $.isFunction(o.proxiedDuration) ?
+                               o.proxiedDuration(animOptions) : o.proxiedDuration;
+
+                       var animations = $.ui.accordion.animations,
+                               duration = o.duration,
+                               easing = o.animated;
+
+                       if (!animations[easing]) {
+                               animations[easing] = function(options) {
+                                       this.slide(options, {
+                                               easing: easing,
+                                               duration: duration || 700
+                                       });
+                               };
+                       }
+
+                       animations[easing](animOptions);
+
+               } else {
+
+                       if (o.collapsible && clickedIsActive) {
+                               toShow.toggle();
+                       } else {
+                               toHide.hide();
+                               toShow.show();
+                       }
+
+                       complete(true);
+
+               }
+
+               toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur();
+               toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus();
+
+       },
+
+       _completed: function(cancel) {
+
+               var o = this.options;
+
+               this.running = cancel ? 0 : --this.running;
+               if (this.running) return;
+
+               if (o.clearStyle) {
+                       this.toShow.add(this.toHide).css({
+                               height: "",
+                               overflow: ""
+                       });
+               }
+
+               this._trigger('change', null, this.data);
+       }
+
+});
+
+
+$.extend($.ui.accordion, {
+       version: "1.7.1",
+       defaults: {
+               active: null,
+               alwaysOpen: true, //deprecated, use collapsible
+               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();
+               }
+       },
+       animations: {
+               slide: function(options, additions) {
+                       options = $.extend({
+                               easing: "swing",
+                               duration: 300
+                       }, options, additions);
+                       if ( !options.toHide.size() ) {
+                               options.toShow.animate({height: "show"}, options);
+                               return;
+                       }
+                       if ( !options.toShow.size() ) {
+                               options.toHide.animate({height: "hide"}, options);
+                               return;
+                       }
+                       var overflow = options.toShow.css('overflow'),
+                               percentDone,
+                               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.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);
+                                       options.toShow.css({overflow: overflow});
+                                       options.complete();
+                               }
+                       });
+               },
+               bounceslide: function(options) {
+                       this.slide(options, {
+                               easing: options.down ? "easeOutBounce" : "swing",
+                               duration: options.down ? 1000 : 200
+                       });
+               },
+               easeslide: function(options) {
+                       this.slide(options, {
+                               easing: "easeinout",
+                               duration: 700
+                       });
+               }
+       }
+});
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.core.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.core.js
new file mode 100644 (file)
index 0000000..6be9993
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * jQuery UI 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+;jQuery.ui || (function($) {
+
+var _remove = $.fn.remove,
+       isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);
+
+//Helper functions and ui object
+$.ui = {
+       version: "1.7.1",
+
+       // $.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);
+                               }
+                       }
+               }
+       },
+
+       contains: function(a, b) {
+               return document.compareDocumentPosition
+                       ? a.compareDocumentPosition(b) & 16
+                       : a !== b && a.contains(b);
+       },
+
+       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;
+       },
+
+       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);
+       },
+
+       keyCode: {
+               BACKSPACE: 8,
+               CAPS_LOCK: 20,
+               COMMA: 188,
+               CONTROL: 17,
+               DELETE: 46,
+               DOWN: 40,
+               END: 35,
+               ENTER: 13,
+               ESCAPE: 27,
+               HOME: 36,
+               INSERT: 45,
+               LEFT: 37,
+               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
+       }
+};
+
+// WAI-ARIA normalization
+if (isFF2) {
+       var attr = $.attr,
+               removeAttr = $.fn.removeAttr,
+               ariaNS = "http://www.w3.org/2005/07/aaa",
+               ariaState = /^aria-/,
+               ariaRole = /^wairole:/;
+
+       $.attr = function(elem, name, value) {
+               var set = value !== undefined;
+
+               return (name == 'role'
+                       ? (set
+                               ? attr.call(this, elem, name, "wairole:" + value)
+                               : (attr.apply(this, arguments) || "").replace(ariaRole, ""))
+                       : (ariaState.test(name)
+                               ? (set
+                                       ? elem.setAttributeNS(ariaNS,
+                                               name.replace(ariaState, "aaa:"), value)
+                                       : attr.call(this, elem, name.replace(ariaState, "aaa:")))
+                               : attr.apply(this, arguments)));
+       };
+
+       $.fn.removeAttr = function(name) {
+               return (ariaState.test(name)
+                       ? this.each(function() {
+                               this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
+                       }) : removeAttr.call(this, name));
+       };
+}
+
+//jQuery plugins
+$.fn.extend({
+       remove: function() {
+               // Safari has a native remove event which actually removes DOM elements,
+               // so we have to use triggerHandler instead of trigger (#3037).
+               $("*", this).add(this).each(function() {
+                       $(this).triggerHandler("remove");
+               });
+               return _remove.apply(this, arguments );
+       },
+
+       enableSelection: function() {
+               return this
+                       .attr('unselectable', 'off')
+                       .css('MozUserSelect', '')
+                       .unbind('selectstart.ui');
+       },
+
+       disableSelection: function() {
+               return this
+                       .attr('unselectable', 'on')
+                       .css('MozUserSelect', 'none')
+                       .bind('selectstart.ui', function() { return false; });
+       },
+
+       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;
+       }
+});
+
+
+//Additional selectors
+$.extend($.expr[':'], {
+       data: function(elem, i, match) {
+               return !!$.data(elem, match[3]);
+       },
+
+       focusable: function(element) {
+               var nodeName = element.nodeName.toLowerCase(),
+                       tabIndex = $.attr(element, 'tabindex');
+               return (/input|select|textarea|button|object/.test(nodeName)
+                       ? !element.disabled
+                       : 'a' == nodeName || 'area' == nodeName
+                               ? element.href || !isNaN(tabIndex)
+                               : !isNaN(tabIndex))
+                       // the element and all of its ancestors must be visible
+                       // the browser may report that the area is hidden
+                       && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;
+       },
+
+       tabbable: function(element) {
+               var tabIndex = $.attr(element, 'tabindex');
+               return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');
+       }
+});
+
+
+// $.widget is a factory to create jQuery plugins
+// taking some boilerplate code out of the plugin code
+function getter(namespace, plugin, method, args) {
+       function getMethods(type) {
+               var methods = $[namespace][plugin][type] || [];
+               return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
+       }
+
+       var methods = getMethods('getter');
+       if (args.length == 1 && typeof args[0] == 'string') {
+               methods = methods.concat(getMethods('getterSetter'));
+       }
+       return ($.inArray(method, methods) != -1);
+}
+
+$.widget = function(name, prototype) {
+       var namespace = name.split(".")[0];
+       name = name.split(".")[1];
+
+       // create plugin method
+       $.fn[name] = function(options) {
+               var isMethodCall = (typeof options == 'string'),
+                       args = Array.prototype.slice.call(arguments, 1);
+
+               // prevent calls to internal methods
+               if (isMethodCall && options.substring(0, 1) == '_') {
+                       return this;
+               }
+
+               // handle getter methods
+               if (isMethodCall && getter(namespace, name, options, args)) {
+                       var instance = $.data(this[0], name);
+                       return (instance ? instance[options].apply(instance, args)
+                               : undefined);
+               }
+
+               // handle initialization and non-getter methods
+               return this.each(function() {
+                       var instance = $.data(this, name);
+
+                       // constructor
+                       (!instance && !isMethodCall &&
+                               $.data(this, name, new $[namespace][name](this, options))._init());
+
+                       // method call
+                       (instance && isMethodCall && $.isFunction(instance[options]) &&
+                               instance[options].apply(instance, args));
+               });
+       };
+
+       // create widget constructor
+       $[namespace] = $[namespace] || {};
+       $[namespace][name] = function(element, options) {
+               var self = this;
+
+               this.namespace = namespace;
+               this.widgetName = name;
+               this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
+               this.widgetBaseClass = namespace + '-' + name;
+
+               this.options = $.extend({},
+                       $.widget.defaults,
+                       $[namespace][name].defaults,
+                       $.metadata && $.metadata.get(element)[name],
+                       options);
+
+               this.element = $(element)
+                       .bind('setData.' + name, function(event, key, value) {
+                               if (event.target == element) {
+                                       return self._setData(key, value);
+                               }
+                       })
+                       .bind('getData.' + name, function(event, key) {
+                               if (event.target == element) {
+                                       return self._getData(key);
+                               }
+                       })
+                       .bind('remove', function() {
+                               return self.destroy();
+                       });
+       };
+
+       // add widget prototype
+       $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
+
+       // TODO: merge getter and getterSetter properties from widget prototype
+       // and plugin prototype
+       $[namespace][name].getterSetter = 'option';
+};
+
+$.widget.prototype = {
+       _init: function() {},
+       destroy: function() {
+               this.element.removeData(this.widgetName)
+                       .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')
+                       .removeAttr('aria-disabled');
+       },
+
+       option: function(key, value) {
+               var options = key,
+                       self = this;
+
+               if (typeof key == "string") {
+                       if (value === undefined) {
+                               return this._getData(key);
+                       }
+                       options = {};
+                       options[key] = value;
+               }
+
+               $.each(options, function(key, value) {
+                       self._setData(key, value);
+               });
+       },
+       _getData: function(key) {
+               return this.options[key];
+       },
+       _setData: function(key, value) {
+               this.options[key] = value;
+
+               if (key == 'disabled') {
+                       this.element
+                               [value ? 'addClass' : 'removeClass'](
+                                       this.widgetBaseClass + '-disabled' + ' ' +
+                                       this.namespace + '-state-disabled')
+                               .attr("aria-disabled", value);
+               }
+       },
+
+       enable: function() {
+               this._setData('disabled', false);
+       },
+       disable: function() {
+               this._setData('disabled', true);
+       },
+
+       _trigger: function(type, event, data) {
+               var callback = this.options[type],
+                       eventName = (type == this.widgetEventPrefix
+                               ? type : this.widgetEventPrefix + type);
+
+               event = $.Event(event);
+               event.type = eventName;
+
+               // 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());
+       }
+};
+
+$.widget.defaults = {
+       disabled: false
+};
+
+
+/** Mouse Interaction Plugin **/
+
+$.ui.mouse = {
+       _mouseInit: function() {
+               var self = this;
+
+               this.element
+                       .bind('mousedown.'+this.widgetName, function(event) {
+                               return self._mouseDown(event);
+                       })
+                       .bind('click.'+this.widgetName, function(event) {
+                               if(self._preventClickEvent) {
+                                       self._preventClickEvent = false;
+                                       event.stopImmediatePropagation();
+                                       return false;
+                               }
+                       });
+
+               // Prevent text selection in IE
+               if ($.browser.msie) {
+                       this._mouseUnselectable = this.element.attr('unselectable');
+                       this.element.attr('unselectable', 'on');
+               }
+
+               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);
+
+               // Restore text selection in IE
+               ($.browser.msie
+                       && this.element.attr('unselectable', this._mouseUnselectable));
+       },
+
+       _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;
+                       }
+               }
+
+               // 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);
+
+               // preventDefault() is used to prevent the selection of text here -
+               // however, in Safari, this causes select boxes not to be selectable
+               // anymore, so this fix is needed
+               ($.browser.safari || 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 && !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;
+                       this._preventClickEvent = (event.target == this._mouseDownEvent.target);
+                       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; }
+};
+
+$.ui.mouse.defaults = {
+       cancel: null,
+       distance: 1,
+       delay: 0
+};
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.datepicker.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.datepicker.js
new file mode 100644 (file)
index 0000000..d3aa5c2
--- /dev/null
@@ -0,0 +1,1630 @@
+/*
+ * jQuery UI Datepicker 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Datepicker
+ *
+ * Depends:
+ *     ui.core.js
+ */
+
+(function($) { // hide the namespace
+
+$.extend($.ui, { datepicker: { version: "1.7.1" } });
+
+var PROP_NAME = 'datepicker';
+
+/* 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
+               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
+       };
+       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: 'show', // 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
+               showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+               yearRange: '-10:+10', // Range of years to display in drop-down,
+                       // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
+               showOtherMonths: false, // True to show dates in other months, false to leave blank
+               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: 'normal', // 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
+       };
+       $.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 ui-helper-hidden-accessible"></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);
+       },
+
+       /* 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)
+                       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(/([:\[\]\.])/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.trigger = $([]);
+               if (input.hasClass(this.markerClassName))
+                       return;
+               var appendText = this._get(inst, 'appendText');
+               var isRTL = this._get(inst, 'isRTL');
+               if (appendText)
+                       input[isRTL ? 'before' : 'after']('<span class="' + this._appendClass + '">' + appendText + '</span>');
+               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 == target)
+                                       $.datepicker._hideDatepicker();
+                               else
+                                       $.datepicker._showDatepicker(target);
+                               return false;
+                       });
+               }
+               input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
+                       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);
+       },
+
+       /* 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));
+               this._updateDatepicker(inst);
+               this._updateAlternate(inst);
+       },
+
+       /* Pop-up the date picker in a "dialog" box.
+          @param  input     element - ignored
+          @param  dateText  string - the initial date to display (in the current format)
+          @param  onSelect  function - the function(dateText) 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, dateText, onSelect, settings, pos) {
+               var inst = this._dialogInst; // internal instance
+               if (!inst) {
+                       var id = 'dp' + (++this.uuid);
+                       this._dialogInput = $('<input type="text" id="' + id +
+                               '" size="1" style="position: absolute; top: -100px;"/>');
+                       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 || {});
+               this._dialogInput.val(dateText);
+
+               this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+               if (!this._pos) {
+                       var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
+                       var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.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] + '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.trigger.remove();
+                       $target.siblings('.' + this._appendClass).remove().end().
+                               removeClass(this.markerClassName).
+                               unbind('focus', this._showDatepicker).
+                               unbind('keydown', this._doKeyDown).
+                               unbind('keypress', this._doKeyPress);
+               } 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 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
+          @param  value   any - the new value for the setting (omit if above is an object) */
+       _optionDatepicker: function(target, name, value) {
+               var settings = name || {};
+               if (typeof name == 'string') {
+                       settings = {};
+                       settings[name] = value;
+               }
+               var inst = this._getInst(target);
+               if (inst) {
+                       if (this._curInst == inst) {
+                               this._hideDatepicker(null);
+                       }
+                       extendRemove(inst.settings, settings);
+                       var date = new Date();
+                       extendRemove(inst, {rangeStart: null, // start of range
+                               endDay: null, endMonth: null, endYear: null, // end of range
+                               selectedDay: date.getDate(), selectedMonth: date.getMonth(),
+                               selectedYear: date.getFullYear(), // starting point
+                               currentDay: date.getDate(), currentMonth: date.getMonth(),
+                               currentYear: date.getFullYear(), // current selection
+                               drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn
+                       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
+          @param  endDate  Date - the new end date for a range (optional) */
+       _setDateDatepicker: function(target, date, endDate) {
+               var inst = this._getInst(target);
+               if (inst) {
+                       this._setDate(inst, date, endDate);
+                       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
+          @return Date - the current date or
+                  Date[2] - the current dates for a range */
+       _getDateDatepicker: function(target) {
+               var inst = this._getInst(target);
+               if (inst && !inst.inline)
+                       this._setDateFromField(inst);
+               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(null, '');
+                                               break; // hide on tab out
+                               case 13: var sel = $('td.' + $.datepicker._dayOverClass +
+                                                       ', td.' + $.datepicker._currentClass, inst.dpDiv);
+                                               if (sel[0])
+                                                       $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+                                               else
+                                                       $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
+                                               return false; // don't submit the form
+                                               break; // select the value on enter
+                               case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
+                                               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 || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
+               }
+       },
+
+       /* 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);
+               var beforeShow = $.datepicker._get(inst, 'beforeShow');
+               extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
+               $.datepicker._hideDatepicker(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;
+               inst.rangeStart = null;
+               // 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') || 'show';
+                       var duration = $.datepicker._get(inst, 'duration');
+                       var postProcess = function() {
+                               $.datepicker._datepickerShowing = true;
+                               if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems
+                                       $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
+                                               height: inst.dpDiv.height() + 4});
+                       };
+                       if ($.effects && $.effects[showAnim])
+                               inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
+                       else
+                               inst.dpDiv[showAnim](duration, postProcess);
+                       if (duration == '')
+                               postProcess();
+                       if (inst.input[0].type != 'hidden')
+                               inst.input[0].focus();
+                       $.datepicker._curInst = inst;
+               }
+       },
+
+       /* Generate the date picker content. */
+       _updateDatepicker: function(inst) {
+               var dims = {width: inst.dpDiv.width() + 4,
+                       height: inst.dpDiv.height() + 4};
+               var self = this;
+               inst.dpDiv.empty().append(this._generateHTML(inst))
+                       .find('iframe.ui-datepicker-cover').
+                               css({width: dims.width, height: dims.height})
+                       .end()
+                       .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.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst)
+                       $(inst.input[0]).focus();
+       },
+
+       /* 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 = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft();
+               var viewHeight = (window.innerHeight || document.documentElement.clientHeight || document.body.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 -= (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0;
+               offset.top -= (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(offset.top + dpHeight + inputHeight*2 - viewHeight) : 0;
+
+               return offset;
+       },
+
+       /* Find an object's position on the screen. */
+       _findPos: function(obj) {
+        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
+            obj = obj.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
+          @param  duration  string - the duration over which to close the date picker */
+       _hideDatepicker: function(input, duration) {
+               var inst = this._curInst;
+               if (!inst || (input && inst != $.data(input, PROP_NAME)))
+                       return;
+               if (inst.stayOpen)
+                       this._selectDate('#' + inst.id, this._formatDate(inst,
+                               inst.currentDay, inst.currentMonth, inst.currentYear));
+               inst.stayOpen = false;
+               if (this._datepickerShowing) {
+                       duration = (duration != null ? duration : this._get(inst, 'duration'));
+                       var showAnim = this._get(inst, 'showAnim');
+                       var postProcess = function() {
+                               $.datepicker._tidyDialog(inst);
+                       };
+                       if (duration != '' && $.effects && $.effects[showAnim])
+                               inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
+                                       duration, postProcess);
+                       else
+                               inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
+                                       (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
+                       if (duration == '')
+                               this._tidyDialog(inst);
+                       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;
+               }
+               this._curInst = null;
+       },
+
+       /* 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.parents('#' + $.datepicker._mainDivId).length == 0) &&
+                               !$target.hasClass($.datepicker.markerClassName) &&
+                               !$target.hasClass($.datepicker._triggerClass) &&
+                               $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
+                       $.datepicker._hideDatepicker(null, '');
+       },
+
+       /* 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 && !$.browser.msie)
+                       inst.input[0].focus();
+               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;
+               if (inst.stayOpen) {
+                       inst.endDay = inst.endMonth = inst.endYear = null;
+               }
+               this._selectDate(id, this._formatDate(inst,
+                       inst.currentDay, inst.currentMonth, inst.currentYear));
+               if (inst.stayOpen) {
+                       inst.rangeStart = this._daylightSavingAdjust(
+                               new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
+                       this._updateDatepicker(inst);
+               }
+       },
+
+       /* Erase the input field and hide the date picker. */
+       _clearDate: function(id) {
+               var target = $(id);
+               var inst = this._getInst(target[0]);
+               inst.stayOpen = false;
+               inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
+               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 if (!inst.stayOpen) {
+                       this._hideDatepicker(null, this._get(inst, 'duration'));
+                       this._lastInput = inst.input[0];
+                       if (typeof(inst.input[0]) != 'object')
+                               inst.input[0].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);
+                       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.getFullYear(), date.getMonth(), date.getDate());
+               var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
+               var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
+               firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
+               if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
+                       checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
+                       return $.datepicker.iso8601Week(checkDate);
+               } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
+                       firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
+                       if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
+                               return 1;
+                       }
+               }
+               return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
+       },
+
+       /* 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;
+               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) {
+                       lookAhead(match);
+                       var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2)));
+                       var size = origSize;
+                       var num = 0;
+                       while (size > 0 && iValue < value.length &&
+                                       value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
+                               num = num * 10 + parseInt(value.charAt(iValue++),10);
+                               size--;
+                       }
+                       if (size == origSize)
+                               throw 'Missing number at position ' + iValue;
+                       return num;
+               };
+               // Extract a name from the string value and convert to an index
+               var getName = function(match, shortNames, longNames) {
+                       var names = (lookAhead(match) ? longNames : shortNames);
+                       var size = 0;
+                       for (var j = 0; j < names.length; j++)
+                               size = Math.max(size, names[j].length);
+                       var name = '';
+                       var iInit = iValue;
+                       while (size > 0 && iValue < value.length) {
+                               name += value.charAt(iValue++);
+                               for (var i = 0; i < names.length; i++)
+                                       if (name == names[i])
+                                               return i + 1;
+                               size--;
+                       }
+                       throw 'Unknown name at position ' + iInit;
+               };
+               // 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 "'":
+                                               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/*
+               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
+       TIMESTAMP: '@',
+       W3C: 'yy-mm-dd', // ISO 8601
+
+       /* 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)
+          '...' - 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':
+                                                       var doy = date.getDate();
+                                                       for (var m = date.getMonth() - 1; m >= 0; m--)
+                                                               doy += this._getDaysInMonth(date.getFullYear(), m);
+                                                       output += formatNumber('o', doy, 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 "'":
+                                                       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;
+               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) {
+               var dateFormat = this._get(inst, 'dateFormat');
+               var dates = inst.input ? inst.input.val() : null;
+               inst.endDay = inst.endMonth = inst.endYear = null;
+               var date = defaultDate = this._getDefaultDate(inst);
+               var settings = this._getFormatConfig(inst);
+               try {
+                       date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+               } catch (event) {
+                       this.log(event);
+                       date = defaultDate;
+               }
+               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) {
+               var date = this._determineDate(this._get(inst, 'defaultDate'), new Date());
+               var minDate = this._getMinMaxDate(inst, 'min', true);
+               var maxDate = this._getMinMaxDate(inst, 'max');
+               date = (minDate && date < minDate ? minDate : date);
+               date = (maxDate && date > maxDate ? maxDate : date);
+               return date;
+       },
+
+       /* A date may be specified as an exact value or a relative one. */
+       _determineDate: function(date, defaultDate) {
+               var offsetNumeric = function(offset) {
+                       var date = new Date();
+                       date.setDate(date.getDate() + offset);
+                       return date;
+               };
+               var offsetString = function(offset, getDaysInMonth) {
+                       var date = 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, getDaysInMonth(year, month));
+                                               break;
+                                       case 'y': case 'Y' :
+                                               year += parseInt(matches[1],10);
+                                               day = Math.min(day, getDaysInMonth(year, month));
+                                               break;
+                               }
+                               matches = pattern.exec(offset);
+                       }
+                       return new Date(year, month, day);
+               };
+               date = (date == null ? defaultDate :
+                       (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
+                       (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
+               date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
+               if (date) {
+                       date.setHours(0);
+                       date.setMinutes(0);
+                       date.setSeconds(0);
+                       date.setMilliseconds(0);
+               }
+               return this._daylightSavingAdjust(date);
+       },
+
+       /* 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, endDate) {
+               var clear = !(date);
+               var origMonth = inst.selectedMonth;
+               var origYear = inst.selectedYear;
+               date = this._determineDate(date, new Date());
+               inst.selectedDay = inst.currentDay = date.getDate();
+               inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
+               inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
+               if (origMonth != inst.selectedMonth || origYear != inst.selectedYear)
+                       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 stepBigMonths = this._get(inst, 'stepBigMonths');
+               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', true);
+               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[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.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.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.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.datepicker._gotoToday(\'#' + inst.id + '\');"' +
+                       '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
+               var firstDay = parseInt(this._get(inst, 'firstDay'),10);
+               firstDay = (isNaN(firstDay) ? 0 : firstDay);
+               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 calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
+               var endDate = inst.endDay ? this._daylightSavingAdjust(
+                       new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate;
+               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 ui-datepicker-group-';
+                                       switch (col) {
+                                               case 0: calender += 'first'; cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
+                                               case numMonths[1]-1: calender += 'last'; cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
+                                               default: calender += '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,
+                                       selectedDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+                                       '</div><table class="ui-datepicker-calendar"><thead>' +
+                                       '<tr>';
+                               var thead = '';
+                               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 = '';
+                                       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 || !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() && printDate.getTime() <= endDate.getTime() ? // in current range
+                                                       ' ' + 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.datepicker._selectDay(\'#' +
+                                                       inst.id + '\',' + drawMonth + ',' + drawYear + ', this);return false;"') + '>' + // actions
+                                                       (otherMonth ? (showOtherMonths ? printDate.getDate() : '&#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() && printDate.getTime() <= endDate.getTime() ? // in current range
+                                                       ' ui-state-active' : '') + // highlight selected day
+                                                       '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
+                                               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,
+                       selectedDate, secondary, monthNames, monthNamesShort) {
+               minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
+               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.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
+                               'onclick="DP_jQuery.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) && (!(changeMonth && changeYear)) ? '&#xa0;' : '');
+               // year selection
+               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 year = 0;
+                       var endYear = 0;
+                       if (years.length != 2) {
+                               year = drawYear - 10;
+                               endYear = drawYear + 10;
+                       } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
+                               year = drawYear + parseInt(years[0], 10);
+                               endYear = drawYear + parseInt(years[1], 10);
+                       } else {
+                               year = parseInt(years[0], 10);
+                               endYear = parseInt(years[1], 10);
+                       }
+                       year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+                       endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+                       html += '<select class="ui-datepicker-year" ' +
+                               'onchange="DP_jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
+                               'onclick="DP_jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
+                               '>';
+                       for (; year <= endYear; year++) {
+                               html += '<option value="' + year + '"' +
+                                       (year == drawYear ? ' selected="selected"' : '') +
+                                       '>' + year + '</option>';
+                       }
+                       html += '</select>';
+               }
+               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._daylightSavingAdjust(new Date(year, month, day));
+               // ensure it is within the bounds set
+               var minDate = this._getMinMaxDate(inst, 'min', true);
+               var maxDate = this._getMinMaxDate(inst, 'max');
+               date = (minDate && date < minDate ? minDate : date);
+               date = (maxDate && date > maxDate ? maxDate : date);
+               inst.selectedDay = date.getDate();
+               inst.drawMonth = inst.selectedMonth = date.getMonth();
+               inst.drawYear = inst.selectedYear = date.getFullYear();
+               if (period == 'M' || period == 'Y')
+                       this._notifyChange(inst);
+       },
+
+       /* 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 - may be overridden for a range. */
+       _getMinMaxDate: function(inst, minMax, checkRange) {
+               var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
+               return (!checkRange || !inst.rangeStart ? date :
+                       (!date || inst.rangeStart > date ? inst.rangeStart : date));
+       },
+
+       /* Find the number of days in a given month. */
+       _getDaysInMonth: function(year, month) {
+               return 32 - 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[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) {
+               // during range selection, use minimum of selected date and range start
+               var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust(
+                       new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)));
+               newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
+               var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
+               var maxDate = this._getMinMaxDate(inst, 'max');
+               return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
+       },
+
+       /* 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){
+
+       /* 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'))
+               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.7.1";
+
+// Workaround for #4055
+// Add another global to avoid noConflict issues with inline event handlers
+window.DP_jQuery = $;
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.dialog.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.dialog.js
new file mode 100644 (file)
index 0000000..e59d519
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * jQuery UI Dialog 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ *     ui.core.js
+ *     ui.draggable.js
+ *     ui.resizable.js
+ */
+(function($) {
+
+var setDataSwitch = {
+               dragStart: "start.draggable",
+               drag: "drag.draggable",
+               dragStop: "stop.draggable",
+               maxHeight: "maxHeight.resizable",
+               minHeight: "minHeight.resizable",
+               maxWidth: "maxWidth.resizable",
+               minWidth: "minWidth.resizable",
+               resizeStart: "start.resizable",
+               resize: "drag.resizable",
+               resizeStop: "stop.resizable"
+       },
+       
+       uiDialogClasses =
+               'ui-dialog ' +
+               'ui-widget ' +
+               'ui-widget-content ' +
+               'ui-corner-all ';
+
+$.widget("ui.dialog", {
+
+       _init: function() {
+               this.originalTitle = this.element.attr('title');
+
+               var self = this,
+                       options = this.options,
+
+                       title = options.title || this.originalTitle || '&nbsp;',
+                       titleId = $.ui.dialog.getTitleId(this.element),
+
+                       uiDialog = (this.uiDialog = $('<div/>'))
+                               .appendTo(document.body)
+                               .hide()
+                               .addClass(uiDialogClasses + options.dialogClass)
+                               .css({
+                                       position: 'absolute',
+                                       overflow: 'hidden',
+                                       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) {
+                                       (options.closeOnEscape && event.keyCode
+                                               && event.keyCode == $.ui.keyCode.ESCAPE && self.close(event));
+                               })
+                               .attr({
+                                       role: 'dialog',
+                                       'aria-labelledby': titleId
+                               })
+                               .mousedown(function(event) {
+                                       self.moveToTop(false, event);
+                               }),
+
+                       uiDialogContent = this.element
+                               .show()
+                               .removeAttr('title')
+                               .addClass(
+                                       'ui-dialog-content ' +
+                                       'ui-widget-content')
+                               .appendTo(uiDialog),
+
+                       uiDialogTitlebar = (this.uiDialogTitlebar = $('<div></div>'))
+                               .addClass(
+                                       'ui-dialog-titlebar ' +
+                                       'ui-widget-header ' +
+                                       'ui-corner-all ' +
+                                       'ui-helper-clearfix'
+                               )
+                               .prependTo(uiDialog),
+
+                       uiDialogTitlebarClose = $('<a href="#"/>')
+                               .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');
+                               })
+                               .mousedown(function(ev) {
+                                       ev.stopPropagation();
+                               })
+                               .click(function(event) {
+                                       self.close(event);
+                                       return false;
+                               })
+                               .appendTo(uiDialogTitlebar),
+
+                       uiDialogTitlebarCloseText = (this.uiDialogTitlebarCloseText = $('<span/>'))
+                               .addClass(
+                                       'ui-icon ' +
+                                       'ui-icon-closethick'
+                               )
+                               .text(options.closeText)
+                               .appendTo(uiDialogTitlebarClose),
+
+                       uiDialogTitle = $('<span/>')
+                               .addClass('ui-dialog-title')
+                               .attr('id', titleId)
+                               .html(title)
+                               .prependTo(uiDialogTitlebar);
+
+               uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();
+
+               (options.draggable && $.fn.draggable && this._makeDraggable());
+               (options.resizable && $.fn.resizable && this._makeResizable());
+
+               this._createButtons(options.buttons);
+               this._isOpen = false;
+
+               (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe());
+               (options.autoOpen && this.open());
+               
+       },
+
+       destroy: function() {
+               (this.overlay && this.overlay.destroy());
+               this.uiDialog.hide();
+               this.element
+                       .unbind('.dialog')
+                       .removeData('dialog')
+                       .removeClass('ui-dialog-content ui-widget-content')
+                       .hide().appendTo('body');
+               this.uiDialog.remove();
+
+               (this.originalTitle && this.element.attr('title', this.originalTitle));
+       },
+
+       close: function(event) {
+               var self = this;
+               
+               if (false === self._trigger('beforeclose', event)) {
+                       return;
+               }
+
+               (self.overlay && self.overlay.destroy());
+               self.uiDialog.unbind('keypress.ui-dialog');
+
+               (self.options.hide
+                       ? self.uiDialog.hide(self.options.hide, function() {
+                               self._trigger('close', event);
+                       })
+                       : self.uiDialog.hide() && self._trigger('close', event));
+
+               $.ui.dialog.overlay.resize();
+
+               self._isOpen = false;
+       },
+
+       isOpen: function() {
+               return this._isOpen;
+       },
+
+       // the force parameter allows us to move modal dialogs to their correct
+       // position on open
+       moveToTop: function(force, event) {
+
+               if ((this.options.modal && !force)
+                       || (!this.options.stack && !this.options.modal)) {
+                       return this._trigger('focus', event);
+               }
+               
+               if (this.options.zIndex > $.ui.dialog.maxZ) {
+                       $.ui.dialog.maxZ = this.options.zIndex;
+               }
+               (this.overlay && this.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
+               var saveScroll = { scrollTop: this.element.attr('scrollTop'), scrollLeft: this.element.attr('scrollLeft') };
+               this.uiDialog.css('z-index', ++$.ui.dialog.maxZ);
+               this.element.attr(saveScroll);
+               this._trigger('focus', event);
+       },
+
+       open: function() {
+               if (this._isOpen) { return; }
+
+               var options = this.options,
+                       uiDialog = this.uiDialog;
+
+               this.overlay = options.modal ? new $.ui.dialog.overlay(this) : null;
+               (uiDialog.next().length && uiDialog.appendTo('body'));
+               this._size();
+               this._position(options.position);
+               uiDialog.show(options.show);
+               this.moveToTop(true);
+
+               // prevent tabbing out of modal dialogs
+               (options.modal && uiDialog.bind('keypress.ui-dialog', function(event) {
+                       if (event.keyCode != $.ui.keyCode.TAB) {
+                               return;
+                       }
+
+                       var tabbables = $(':tabbable', this),
+                               first = tabbables.filter(':first')[0],
+                               last  = tabbables.filter(':last')[0];
+
+                       if (event.target == last && !event.shiftKey) {
+                               setTimeout(function() {
+                                       first.focus();
+                               }, 1);
+                       } else if (event.target == first && event.shiftKey) {
+                               setTimeout(function() {
+                                       last.focus();
+                               }, 1);
+                       }
+               }));
+
+               // 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
+               $([])
+                       .add(uiDialog.find('.ui-dialog-content :tabbable:first'))
+                       .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first'))
+                       .add(uiDialog)
+                       .filter(':first')
+                       .focus();
+
+               this._trigger('open');
+               this._isOpen = true;
+       },
+
+       _createButtons: function(buttons) {
+               var self = this,
+                       hasButtons = false,
+                       uiDialogButtonPane = $('<div></div>')
+                               .addClass(
+                                       'ui-dialog-buttonpane ' +
+                                       'ui-widget-content ' +
+                                       'ui-helper-clearfix'
+                               );
+
+               // if we already have a button pane, remove it
+               this.uiDialog.find('.ui-dialog-buttonpane').remove();
+
+               (typeof buttons == 'object' && buttons !== null &&
+                       $.each(buttons, function() { return !(hasButtons = true); }));
+               if (hasButtons) {
+                       $.each(buttons, function(name, fn) {
+                               $('<button type="button"></button>')
+                                       .addClass(
+                                               'ui-state-default ' +
+                                               'ui-corner-all'
+                                       )
+                                       .text(name)
+                                       .click(function() { fn.apply(self.element[0], arguments); })
+                                       .hover(
+                                               function() {
+                                                       $(this).addClass('ui-state-hover');
+                                               },
+                                               function() {
+                                                       $(this).removeClass('ui-state-hover');
+                                               }
+                                       )
+                                       .focus(function() {
+                                               $(this).addClass('ui-state-focus');
+                                       })
+                                       .blur(function() {
+                                               $(this).removeClass('ui-state-focus');
+                                       })
+                                       .appendTo(uiDialogButtonPane);
+                       });
+                       uiDialogButtonPane.appendTo(this.uiDialog);
+               }
+       },
+
+       _makeDraggable: function() {
+               var self = this,
+                       options = this.options,
+                       heightBeforeDrag;
+
+               this.uiDialog.draggable({
+                       cancel: '.ui-dialog-content',
+                       handle: '.ui-dialog-titlebar',
+                       containment: 'document',
+                       start: function() {
+                               heightBeforeDrag = options.height;
+                               $(this).height($(this).height()).addClass("ui-dialog-dragging");
+                               (options.dragStart && options.dragStart.apply(self.element[0], arguments));
+                       },
+                       drag: function() {
+                               (options.drag && options.drag.apply(self.element[0], arguments));
+                       },
+                       stop: function() {
+                               $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
+                               (options.dragStop && options.dragStop.apply(self.element[0], arguments));
+                               $.ui.dialog.overlay.resize();
+                       }
+               });
+       },
+
+       _makeResizable: function(handles) {
+               handles = (handles === undefined ? this.options.resizable : handles);
+               var self = this,
+                       options = this.options,
+                       resizeHandles = typeof handles == 'string'
+                               ? handles
+                               : 'n,e,s,w,se,sw,ne,nw';
+
+               this.uiDialog.resizable({
+                       cancel: '.ui-dialog-content',
+                       alsoResize: this.element,
+                       maxWidth: options.maxWidth,
+                       maxHeight: options.maxHeight,
+                       minWidth: options.minWidth,
+                       minHeight: options.minHeight,
+                       start: function() {
+                               $(this).addClass("ui-dialog-resizing");
+                               (options.resizeStart && options.resizeStart.apply(self.element[0], arguments));
+                       },
+                       resize: function() {
+                               (options.resize && options.resize.apply(self.element[0], arguments));
+                       },
+                       handles: resizeHandles,
+                       stop: function() {
+                               $(this).removeClass("ui-dialog-resizing");
+                               options.height = $(this).height();
+                               options.width = $(this).width();
+                               (options.resizeStop && options.resizeStop.apply(self.element[0], arguments));
+                               $.ui.dialog.overlay.resize();
+                       }
+               })
+               .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
+       },
+
+       _position: function(pos) {
+               var wnd = $(window), doc = $(document),
+                       pTop = doc.scrollTop(), pLeft = doc.scrollLeft(),
+                       minTop = pTop;
+
+               if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) {
+                       pos = [
+                               pos == 'right' || pos == 'left' ? pos : 'center',
+                               pos == 'top' || pos == 'bottom' ? pos : 'middle'
+                       ];
+               }
+               if (pos.constructor != Array) {
+                       pos = ['center', 'middle'];
+               }
+               if (pos[0].constructor == Number) {
+                       pLeft += pos[0];
+               } else {
+                       switch (pos[0]) {
+                               case 'left':
+                                       pLeft += 0;
+                                       break;
+                               case 'right':
+                                       pLeft += wnd.width() - this.uiDialog.outerWidth();
+                                       break;
+                               default:
+                               case 'center':
+                                       pLeft += (wnd.width() - this.uiDialog.outerWidth()) / 2;
+                       }
+               }
+               if (pos[1].constructor == Number) {
+                       pTop += pos[1];
+               } else {
+                       switch (pos[1]) {
+                               case 'top':
+                                       pTop += 0;
+                                       break;
+                               case 'bottom':
+                                       pTop += wnd.height() - this.uiDialog.outerHeight();
+                                       break;
+                               default:
+                               case 'middle':
+                                       pTop += (wnd.height() - this.uiDialog.outerHeight()) / 2;
+                       }
+               }
+
+               // prevent the dialog from being too high (make sure the titlebar
+               // is accessible)
+               pTop = Math.max(pTop, minTop);
+               this.uiDialog.css({top: pTop, left: pLeft});
+       },
+
+       _setData: function(key, value){
+               (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value));
+               switch (key) {
+                       case "buttons":
+                               this._createButtons(value);
+                               break;
+                       case "closeText":
+                               this.uiDialogTitlebarCloseText.text(value);
+                               break;
+                       case "dialogClass":
+                               this.uiDialog
+                                       .removeClass(this.options.dialogClass)
+                                       .addClass(uiDialogClasses + value);
+                               break;
+                       case "draggable":
+                               (value
+                                       ? this._makeDraggable()
+                                       : this.uiDialog.draggable('destroy'));
+                               break;
+                       case "height":
+                               this.uiDialog.height(value);
+                               break;
+                       case "position":
+                               this._position(value);
+                               break;
+                       case "resizable":
+                               var uiDialog = this.uiDialog,
+                                       isResizable = this.uiDialog.is(':data(resizable)');
+
+                               // currently resizable, becoming non-resizable
+                               (isResizable && !value && uiDialog.resizable('destroy'));
+
+                               // currently resizable, changing handles
+                               (isResizable && typeof value == 'string' &&
+                                       uiDialog.resizable('option', 'handles', value));
+
+                               // currently non-resizable, becoming resizable
+                               (isResizable || this._makeResizable(value));
+                               break;
+                       case "title":
+                               $(".ui-dialog-title", this.uiDialogTitlebar).html(value || '&nbsp;');
+                               break;
+                       case "width":
+                               this.uiDialog.width(value);
+                               break;
+               }
+
+               $.widget.prototype._setData.apply(this, 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;
+
+               // reset content sizing
+               this.element.css({
+                       height: 0,
+                       minHeight: 0,
+                       width: 'auto'
+               });
+
+               // reset wrapper sizing
+               // determine the height of all the non-content elements
+               var nonContentHeight = this.uiDialog.css({
+                               height: 'auto',
+                               width: options.width
+                       })
+                       .height();
+
+               this.element
+                       .css({
+                               minHeight: Math.max(options.minHeight - nonContentHeight, 0),
+                               height: options.height == 'auto'
+                                       ? 'auto'
+                                       : Math.max(options.height - nonContentHeight, 0)
+                       });
+       }
+});
+
+$.extend($.ui.dialog, {
+       version: "1.7.1",
+       defaults: {
+               autoOpen: true,
+               bgiframe: false,
+               buttons: {},
+               closeOnEscape: true,
+               closeText: 'close',
+               dialogClass: '',
+               draggable: true,
+               hide: null,
+               height: 'auto',
+               maxHeight: false,
+               maxWidth: false,
+               minHeight: 150,
+               minWidth: 150,
+               modal: false,
+               position: 'center',
+               resizable: true,
+               show: null,
+               stack: true,
+               title: '',
+               width: 300,
+               zIndex: 1000
+       },
+
+       getter: 'isOpen',
+
+       uuid: 0,
+       maxZ: 0,
+
+       getTitleId: function($el) {
+               return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid);
+       },
+
+       overlay: function(dialog) {
+               this.$el = $.ui.dialog.overlay.create(dialog);
+       }
+});
+
+$.extend($.ui.dialog.overlay, {
+       instances: [],
+       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() {
+                               $(document).bind($.ui.dialog.overlay.events, function(event) {
+                                       var dialogZ = $(event.target).parents('.ui-dialog').css('zIndex') || 0;
+                                       return (dialogZ > $.ui.dialog.overlay.maxZ);
+                               });
+                       }, 1);
+
+                       // allow closing by pressing the escape key
+                       $(document).bind('keydown.dialog-overlay', function(event) {
+                               (dialog.options.closeOnEscape && event.keyCode
+                                               && event.keyCode == $.ui.keyCode.ESCAPE && dialog.close(event));
+                       });
+
+                       // handle window resize
+                       $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
+               }
+
+               var $el = $('<div></div>').appendTo(document.body)
+                       .addClass('ui-widget-overlay').css({
+                               width: this.width(),
+                               height: this.height()
+                       });
+
+               (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe());
+
+               this.instances.push($el);
+               return $el;
+       },
+
+       destroy: function($el) {
+               this.instances.splice($.inArray(this.instances, $el), 1);
+
+               if (this.instances.length === 0) {
+                       $([document, window]).unbind('.dialog-overlay');
+               }
+
+               $el.remove();
+       },
+
+       height: function() {
+               // handle IE 6
+               if ($.browser.msie && $.browser.version < 7) {
+                       var scrollHeight = Math.max(
+                               document.documentElement.scrollHeight,
+                               document.body.scrollHeight
+                       );
+                       var 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() {
+               // handle IE 6
+               if ($.browser.msie && $.browser.version < 7) {
+                       var scrollWidth = Math.max(
+                               document.documentElement.scrollWidth,
+                               document.body.scrollWidth
+                       );
+                       var 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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.draggable.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.draggable.js
new file mode 100644 (file)
index 0000000..e07d1c8
--- /dev/null
@@ -0,0 +1,766 @@
+/*
+ * jQuery UI Draggable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.draggable", $.extend({}, $.ui.mouse, {
+
+       _init: 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();
+       },
+
+       _mouseCapture: function(event) {
+
+               var o = this.options;
+
+               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.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._generatePosition(event);
+               this.originalPageX = event.pageX;
+               this.originalPageY = event.pageY;
+
+               //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+               if(o.cursorAt)
+                       this._adjustOffsetFromHelper(o.cursorAt);
+
+               //Set a containment if given in the options
+               if(o.containment)
+                       this._setContainment();
+
+               //Call plugins and callbacks
+               this._trigger("start", event);
+
+               //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();
+                       this._trigger('drag', event, ui);
+                       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((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() {
+                               self._trigger("stop", event);
+                               self._clear();
+                       });
+               } else {
+                       this._trigger("stop", event);
+                       this._clear();
+               }
+
+               return false;
+       },
+
+       _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(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+               if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+               if(obj.bottom != undefined) 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)
+               };
+       },
+
+       _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) && 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) - 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
+                       ];
+               } 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 && 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() ))
+                       )
+               };
+
+       },
+
+       _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,
+                       absolutePosition: this.positionAbs, //deprecated
+                       offset: this.positionAbs
+               };
+       }
+
+}));
+
+$.extend($.ui.draggable, {
+       version: "1.7.1",
+       eventPrefix: "drag",
+       defaults: {
+               addClasses: true,
+               appendTo: "parent",
+               axis: false,
+               cancel: ":input,option",
+               connectToSortable: false,
+               containment: false,
+               cursor: "auto",
+               cursorAt: false,
+               delay: 0,
+               distance: 1,
+               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
+       }
+});
+
+$.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._refreshItems();       //Do a one-time refresh at start to refresh the containerCache
+                               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.group)).sort(function(a,b) {
+                       return (parseInt($(a).css("zIndex"),10) || o.stack.min) - (parseInt($(b).css("zIndex"),10) || o.stack.min);
+               });
+
+               $(group).each(function(i) {
+                       this.style.zIndex = o.stack.min + i;
+               });
+
+               this[0].style.zIndex = o.stack.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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.droppable.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.droppable.js
new file mode 100644 (file)
index 0000000..22fcbaf
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * jQuery UI Droppable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Droppables
+ *
+ * Depends:
+ *     ui.core.js
+ *     ui.draggable.js
+ */
+(function($) {
+
+$.widget("ui.droppable", {
+
+       _init: function() {
+
+               var o = this.options, accept = o.accept;
+               this.isover = 0; this.isout = 1;
+
+               this.options.accept = this.options.accept && $.isFunction(this.options.accept) ? this.options.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[this.options.scope] = $.ui.ddmanager.droppables[this.options.scope] || [];
+               $.ui.ddmanager.droppables[this.options.scope].push(this);
+
+               (this.options.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");
+       },
+
+       _setData: function(key, value) {
+
+               if(key == 'accept') {
+                       this.options.accept = value && $.isFunction(value) ? value : function(d) {
+                               return d.is(value);
+                       };
+               } else {
+                       $.widget.prototype._setData.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.options.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.options.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 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)) {
+                               childrenIntersection = true; return false;
+                       }
+               });
+               if(childrenIntersection) return false;
+
+               if(this.options.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,
+                       absolutePosition: c.positionAbs, //deprecated
+                       offset: c.positionAbs
+               };
+       }
+
+});
+
+$.extend($.ui.droppable, {
+       version: "1.7.1",
+       eventPrefix: 'drop',
+       defaults: {
+               accept: '*',
+               activeClass: false,
+               addClasses: true,
+               greedy: false,
+               hoverClass: false,
+               scope: 'default',
+               tolerance: 'intersect'
+       }
+});
+
+$.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].options.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
+
+                       m[i].offset = m[i].element.offset();
+                       m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
+
+                       if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
+
+               }
+
+       },
+       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 = this._drop.call(this, event);
+
+                       if (!this.options.disabled && this.visible && this.options.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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.progressbar.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.progressbar.js
new file mode 100644 (file)
index 0000000..e69b225
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * jQuery UI Progressbar 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Progressbar
+ *
+ * Depends:
+ *   ui.core.js
+ */
+(function($) {
+
+$.widget("ui.progressbar", {
+
+       _init: function() {
+
+               this.element
+                       .addClass("ui-progressbar"
+                               + " ui-widget"
+                               + " ui-widget-content"
+                               + " ui-corner-all")
+                       .attr({
+                               role: "progressbar",
+                               "aria-valuemin": this._valueMin(),
+                               "aria-valuemax": this._valueMax(),
+                               "aria-valuenow": this._value()
+                       });
+
+               this.valueDiv = $('<div class="ui-progressbar-value ui-widget-header ui-corner-left"></div>').appendTo(this.element);
+
+               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")
+                       .removeData("progressbar")
+                       .unbind(".progressbar");
+
+               this.valueDiv.remove();
+
+               $.widget.prototype.destroy.apply(this, arguments);
+
+       },
+
+       value: function(newValue) {
+               arguments.length && this._setData("value", newValue);
+               return this._value();
+       },
+
+       _setData: function(key, value) {
+
+               switch (key) {
+                       case 'value':
+                               this.options.value = value;
+                               this._refreshValue();
+                               this._trigger('change', null, {});
+                               break;
+               }
+
+               $.widget.prototype._setData.apply(this, arguments);
+
+       },
+
+       _value: function() {
+
+               var val = this.options.value;
+               if (val < this._valueMin()) val = this._valueMin();
+               if (val > this._valueMax()) val = this._valueMax();
+
+               return val;
+
+       },
+
+       _valueMin: function() {
+               var valueMin = 0;
+               return valueMin;
+       },
+
+       _valueMax: function() {
+               var valueMax = 100;
+               return valueMax;
+       },
+
+       _refreshValue: function() {
+               var value = this.value();
+               this.valueDiv[value == this._valueMax() ? 'addClass' : 'removeClass']("ui-corner-right");
+               this.valueDiv.width(value + '%');
+               this.element.attr("aria-valuenow", value);
+       }
+
+});
+
+$.extend($.ui.progressbar, {
+       version: "1.7.1",
+       defaults: {
+               value: 0
+       }
+});
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.resizable.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.resizable.js
new file mode 100644 (file)
index 0000000..618102f
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * jQuery UI Resizable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.resizable", $.extend({}, $.ui.mouse, {
+
+       _init: 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.parent().append(
+                               this.originalElement.css({
+                                       position: wrapper.css('position'),
+                                       width: wrapper.outerWidth(),
+                                       height: wrapper.outerHeight(),
+                                       top: wrapper.css('top'),
+                                       left: wrapper.css('left')
+                               })
+                       ).end().remove();
+               }
+
+               this.originalElement.css('resize', this.originalResizeStyle);
+               _destroy(this.originalElement);
+
+       },
+
+       _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.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;
+
+                       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.7.1",
+       eventPrefix: "resize",
+       defaults: {
+               alsoResize: false,
+               animate: false,
+               animateDuration: "slow",
+               animateEasing: "swing",
+               aspectRatio: false,
+               autoHide: false,
+               cancel: ":input,option",
+               containment: false,
+               delay: 0,
+               distance: 1,
+               ghost: false,
+               grid: false,
+               handles: "e,s,se",
+               helper: false,
+               maxHeight: null,
+               maxWidth: null,
+               minHeight: 10,
+               minWidth: 10,
+               zIndex: 1000
+       }
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+       start: function(event, ui) {
+
+               var self = $(this).data("resizable"), o = self.options;
+
+               _store = function(exp) {
+                       $(exp).each(function() {
+                               $(this).data("resizable-alsoresize", {
+                                       width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
+                                       left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10)
+                               });
+                       });
+               };
+
+               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, c) { _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 : ['width', 'height', 'top', 'left'];
+
+                               $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) {
+                                       var sum = (start[prop]||0) + (delta[prop]||0);
+                                       if (sum && sum >= 0)
+                                               style[prop] = sum || null;
+                               });
+
+                               //Opera fixing relative position
+                               if (/relative/.test(el.css('position')) && $.browser.opera) {
+                                       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");
+
+               //Opera fixing relative position
+               if (self._revertToRelativePosition && $.browser.opera) {
+                       self._revertToRelativePosition = false;
+                       el.css({ position: 'relative' });
+               }
+
+               $(this).removeData("resizable-alsoresize-start");
+       }
+});
+
+$.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);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.selectable.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.selectable.js
new file mode 100644 (file)
index 0000000..32bc3d3
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * jQuery UI Selectable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Selectables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.selectable", $.extend({}, $.ui.mouse, {
+
+       _init: 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 = $(document.createElement('div'))
+                       .css({border:'1px dotted black'})
+                       .addClass("ui-selectable-helper");
+       },
+
+       destroy: function() {
+               this.element
+                       .removeClass("ui-selectable ui-selectable-disabled")
+                       .removeData("selectable")
+                       .unbind(".selectable");
+               this._mouseDestroy();
+       },
+
+       _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({
+                       "z-index": 100,
+                       "position": "absolute",
+                       "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) {
+                               selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting');
+                               selectee.unselecting = false;
+                               selectee.selecting = true;
+                               selectee.selected = true;
+                               // selectable SELECTING callback
+                               self._trigger("selecting", event, {
+                                       selecting: 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.7.1",
+       defaults: {
+               appendTo: 'body',
+               autoRefresh: true,
+               cancel: ":input,option",
+               delay: 0,
+               distance: 0,
+               filter: '*',
+               tolerance: 'touch'
+       }
+});
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.slider.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.slider.js
new file mode 100644 (file)
index 0000000..b1c1da6
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * jQuery UI Slider 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ *     ui.core.js
+ */
+
+(function($) {
+
+$.widget("ui.slider", $.extend({}, $.ui.mouse, {
+
+       _init: function() {
+
+               var self = this, o = this.options;
+               this._keySliding = false;
+               this._handleIndex = null;
+               this._detectOrientation();
+               this._mouseInit();
+
+               this.element
+                       .addClass("ui-slider"
+                               + " ui-slider-" + this.orientation
+                               + " ui-widget"
+                               + " ui-widget-content"
+                               + " ui-corner-all");
+
+               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() { $(this).addClass('ui-state-hover'); }, function() { $(this).removeClass('ui-state-hover'); })
+                       .focus(function() { $(".ui-slider .ui-state-focus").removeClass('ui-state-focus'); $(this).addClass('ui-state-focus'); })
+                       .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;
+
+                       var index = $(this).data("index.ui-slider-handle");
+
+                       if (self.options.disabled)
+                               return;
+
+                       switch (event.keyCode) {
+                               case $.ui.keyCode.HOME:
+                               case $.ui.keyCode.END:
+                               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");
+                                               self._start(event, index);
+                                       }
+                                       break;
+                       }
+
+                       var curVal, newVal, step = self._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.UP:
+                               case $.ui.keyCode.RIGHT:
+                                       if(curVal == self._valueMax()) return;
+                                       newVal = curVal + step;
+                                       break;
+                               case $.ui.keyCode.DOWN:
+                               case $.ui.keyCode.LEFT:
+                                       if(curVal == self._valueMin()) return;
+                                       newVal = 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._stop(event, index);
+                               self._change(event, index);
+                               self._keySliding = false;
+                               $(this).removeClass("ui-state-active");
+                       }
+
+               });
+
+               this._refreshValue();
+
+       },
+
+       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();
+
+       },
+
+       _mouseCapture: function(event) {
+
+               var o = this.options;
+
+               if (o.disabled)
+                       return false;
+
+               this.elementSize = {
+                       width: this.element.outerWidth(),
+                       height: this.element.outerHeight()
+               };
+               this.elementOffset = this.element.offset();
+
+               var position = { x: event.pageX, y: event.pageY };
+               var normValue = this._normValueFromMouse(position);
+
+               var distance = this._valueMax() - this._valueMin() + 1, closestHandle;
+               var self = this, index;
+               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) {
+                       closestHandle = $(this.handles[++index]);
+               }
+
+               this._start(event, index);
+
+               self._handleIndex = index;
+
+               closestHandle
+                       .addClass("ui-state-active")
+                       .focus();
+               
+               var offset = closestHandle.offset();
+               var 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)
+               };
+
+               normValue = this._normValueFromMouse(position);
+               this._slide(event, index, normValue);
+               return true;
+
+       },
+
+       _mouseStart: function(event) {
+               return true;
+       },
+
+       _mouseDrag: function(event) {
+
+               var position = { x: event.pageX, y: event.pageY };
+               var normValue = this._normValueFromMouse(position);
+               
+               this._slide(event, this._handleIndex, normValue);
+
+               return false;
+
+       },
+
+       _mouseStop: function(event) {
+
+               this.handles.removeClass("ui-state-active");
+               this._stop(event, this._handleIndex);
+               this._change(event, this._handleIndex);
+               this._handleIndex = null;
+               this._clickOffset = null;
+
+               return false;
+
+       },
+       
+       _detectOrientation: function() {
+               this.orientation = this.options.orientation == 'vertical' ? 'vertical' : 'horizontal';
+       },
+
+       _normValueFromMouse: function(position) {
+
+               var pixelTotal, pixelMouse;
+               if ('horizontal' == this.orientation) {
+                       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);
+               }
+
+               var percentMouse = (pixelMouse / pixelTotal);
+               if (percentMouse > 1) percentMouse = 1;
+               if (percentMouse < 0) percentMouse = 0;
+               if ('vertical' == this.orientation)
+                       percentMouse = 1 - percentMouse;
+
+               var valueTotal = this._valueMax() - this._valueMin(),
+                       valueMouse = percentMouse * valueTotal,
+                       valueMouseModStep = valueMouse % this.options.step,
+                       normValue = this._valueMin() + valueMouse - valueMouseModStep;
+
+               if (valueMouseModStep > (this.options.step / 2))
+                       normValue += this.options.step;
+
+               // Since JavaScript has problems with large floats, round
+               // the final value to 5 digits after the decimal point (see #4124)
+               return parseFloat(normValue.toFixed(5));
+
+       },
+
+       _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()
+               }
+               this._trigger("start", event, uiHash);
+       },
+
+       _slide: function(event, index, newVal) {
+
+               var handle = this.handles[index];
+
+               if (this.options.values && this.options.values.length) {
+
+                       var otherVal = this.values(index ? 0 : 1);
+
+                       if ((index == 0 && newVal >= otherVal) || (index == 1 && newVal <= otherVal))
+                               newVal = otherVal;
+
+                       if (newVal != this.values(index)) {
+                               var newValues = this.values();
+                               newValues[index] = newVal;
+                               // A slide can be canceled by returning false from the slide callback
+                               var allowed = this._trigger("slide", event, {
+                                       handle: this.handles[index],
+                                       value: newVal,
+                                       values: newValues
+                               });
+                               var otherVal = this.values(index ? 0 : 1);
+                               if (allowed !== false) {
+                                       this.values(index, newVal, ( event.type == 'mousedown' && this.options.animate ), true);
+                               }
+                       }
+
+               } else {
+
+                       if (newVal != this.value()) {
+                               // A slide can be canceled by returning false from the slide callback
+                               var allowed = this._trigger("slide", event, {
+                                       handle: this.handles[index],
+                                       value: newVal
+                               });
+                               if (allowed !== false) {
+                                       this._setData('value', newVal, ( event.type == 'mousedown' && this.options.animate ));
+                               }
+                                       
+                       }
+
+               }
+
+       },
+
+       _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) {
+               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._setData("value", newValue);
+                       this._change(null, 0);
+               }
+
+               return this._value();
+
+       },
+
+       values: function(index, newValue, animated, noPropagation) {
+
+               if (arguments.length > 1) {
+                       this.options.values[index] = newValue;
+                       this._refreshValue(animated);
+                       if(!noPropagation) this._change(null, index);
+               }
+
+               if (arguments.length) {
+                       if (this.options.values && this.options.values.length) {
+                               return this._values(index);
+                       } else {
+                               return this.value();
+                       }
+               } else {
+                       return this._values();
+               }
+
+       },
+
+       _setData: function(key, value, animated) {
+
+               $.widget.prototype._setData.apply(this, arguments);
+
+               switch (key) {
+                       case 'orientation':
+
+                               this._detectOrientation();
+                               
+                               this.element
+                                       .removeClass("ui-slider-horizontal ui-slider-vertical")
+                                       .addClass("ui-slider-" + this.orientation);
+                               this._refreshValue(animated);
+                               break;
+                       case 'value':
+                               this._refreshValue(animated);
+                               break;
+               }
+
+       },
+
+       _step: function() {
+               var step = this.options.step;
+               return step;
+       },
+
+       _value: function() {
+
+               var val = this.options.value;
+               if (val < this._valueMin()) val = this._valueMin();
+               if (val > this._valueMax()) val = this._valueMax();
+
+               return val;
+
+       },
+
+       _values: function(index) {
+
+               if (arguments.length) {
+                       var val = this.options.values[index];
+                       if (val < this._valueMin()) val = this._valueMin();
+                       if (val > this._valueMax()) val = this._valueMax();
+
+                       return val;
+               } else {
+                       return this.options.values;
+               }
+
+       },
+
+       _valueMin: function() {
+               var valueMin = this.options.min;
+               return valueMin;
+       },
+
+       _valueMax: function() {
+               var valueMax = this.options.max;
+               return valueMax;
+       },
+
+       _refreshValue: function(animate) {
+
+               var oRange = this.options.range, o = this.options, self = this;
+
+               if (this.options.values && this.options.values.length) {
+                       var vp0, vp1;
+                       this.handles.each(function(i, j) {
+                               var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100;
+                               var _set = {}; _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') {
+                                               (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ left: valPercent + '%' }, o.animate);
+                                               (i == 1) && self.range[animate ? 'animate' : 'css']({ width: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });
+                                       } else {
+                                               (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ bottom: (valPercent) + '%' }, o.animate);
+                                               (i == 1) && self.range[animate ? 'animate' : 'css']({ height: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });
+                                       }
+                               }
+                               lastValPercent = valPercent;
+                       });
+               } else {
+                       var value = this.value(),
+                               valueMin = this._valueMin(),
+                               valueMax = this._valueMax(),
+                               valPercent = valueMax != valueMin
+                                       ? (value - valueMin) / (valueMax - valueMin) * 100
+                                       : 0;
+                       var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%';
+                       this.handle.stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate);
+
+                       (oRange == "min") && (this.orientation == "horizontal") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ width: valPercent + '%' }, o.animate);
+                       (oRange == "max") && (this.orientation == "horizontal") && this.range[animate ? 'animate' : 'css']({ width: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });
+                       (oRange == "min") && (this.orientation == "vertical") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ height: valPercent + '%' }, o.animate);
+                       (oRange == "max") && (this.orientation == "vertical") && this.range[animate ? 'animate' : 'css']({ height: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });
+               }
+
+       }
+       
+}));
+
+$.extend($.ui.slider, {
+       getter: "value values",
+       version: "1.7.1",
+       eventPrefix: "slide",
+       defaults: {
+               animate: false,
+               delay: 0,
+               distance: 0,
+               max: 100,
+               min: 0,
+               orientation: 'horizontal',
+               range: false,
+               step: 1,
+               value: 0,
+               values: null
+       }
+});
+
+})(jQuery);
+
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.sortable.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.sortable.js
new file mode 100644 (file)
index 0000000..a119a6e
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ * jQuery UI Sortable 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Sortables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.sortable", $.extend({}, $.ui.mouse, {
+       _init: function() {
+
+               var o = this.options;
+               this.containerCache = {};
+               this.element.addClass("ui-sortable");
+
+               //Get the items
+               this.refresh();
+
+               //Let's determine if the items are floating
+               this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : 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");
+       },
+
+       _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
+               if(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)
+                       ) {
+
+                               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();
+
+                       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;
+                               }
+                       }
+
+               }
+
+               //$(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 true;
+
+       },
+
+       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]));
+               });
+
+               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();
+       },
+
+       _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"), 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"), 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();
+                       };
+               }
+
+       },
+
+       _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) {
+               for (var i = this.containers.length - 1; i >= 0; i--){
+
+                       if(this._intersectsWith(this.containers[i].containerCache)) {
+                               if(!this.containers[i].containerCache.over) {
+
+                                       if(this.currentContainer != this.containers[i]) {
+
+                                               //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[i].floating ? 'left' : 'top'];
+                                               for (var j = this.items.length - 1; j >= 0; j--) {
+                                                       if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue;
+                                                       var cur = this.items[j][this.containers[i].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
+                                                       continue;
+
+                                               this.currentContainer = this.containers[i];
+                                               itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[i].element, true);
+                                               this._trigger("change", event, this._uiHash());
+                                               this.containers[i]._trigger("change", event, this._uiHash(this));
+
+                                               //Update the placeholder
+                                               this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+                                       }
+
+                                       this.containers[i]._trigger("over", event, this._uiHash(this));
+                                       this.containers[i].containerCache.over = 1;
+                               }
+                       } else {
+                               if(this.containers[i].containerCache.over) {
+                                       this.containers[i]._trigger("out", event, this._uiHash(this));
+                                       this.containers[i].containerCache.over = 0;
+                               }
+                       }
+
+               };
+       },
+
+       _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(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+               if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+               if(obj.bottom != undefined) 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 cursor
+               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,
+                       absolutePosition: self.positionAbs, //deprecated
+                       offset: self.positionAbs,
+                       item: self.currentItem,
+                       sender: inst ? inst.element : null
+               };
+       }
+
+}));
+
+$.extend($.ui.sortable, {
+       getter: "serialize toArray",
+       version: "1.7.1",
+       eventPrefix: "sort",
+       defaults: {
+               appendTo: "parent",
+               axis: false,
+               cancel: ":input,option",
+               connectWith: false,
+               containment: false,
+               cursor: 'auto',
+               cursorAt: false,
+               delay: 0,
+               distance: 1,
+               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
+       }
+});
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.tabs.js b/js2/mwEmbed/jquery/jquery.ui-1.7.1/ui/ui.tabs.js
new file mode 100644 (file)
index 0000000..a73dbc9
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * jQuery UI Tabs 1.7.1
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.tabs", {
+
+       _init: function() {
+               if (this.options.deselectable !== undefined) {
+                       this.options.collapsible = this.options.deselectable;
+               }
+               this._tabify(true);
+       },
+
+       _setData: function(key, value) {
+               if (key == 'selected') {
+                       if (this.options.collapsible && value == this.options.selected) {
+                               return;
+                       }
+                       this.select(value);
+               }
+               else {
+                       this.options[key] = value;
+                       if (key == 'deselectable') {
+                               this.options.collapsible = value;
+                       }
+                       this._tabify();
+               }
+       },
+
+       _tabId: function(a) {
+               return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
+                       this.options.idPrefix + $.data(a);
+       },
+
+       _sanitizeSelector: function(hash) {
+               return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
+       },
+
+       _cookie: function() {
+               var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0]));
+               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) {
+
+               this.list = this.element.children('ul:first');
+               this.lis = $('li:has(a[href])', this.list);
+               this.anchors = this.lis.map(function() { return $('a', this)[0]; });
+               this.panels = $([]);
+
+               var self = this, o = this.options;
+
+               var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
+               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._sanitizeSelector(href));
+                       }
+
+                       // remote tab
+                       else if (href != '#') { // prevent loading the page itself if href is just "#"
+                               $.data(a, 'href.tabs', href); // required for restore on destroy
+
+                               // TODO until #3808 is fixed strip fragment identifier from url
+                               // (IE fails to load from such url)
+                               $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data
+
+                               var id = self._tabId(a);
+                               a.href = '#' + id;
+                               var $panel = $('#' + 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; // break
+                                               }
+                                       });
+                               }
+                               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 || 0;
+                       }
+                       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');
+                       if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
+                               this.panels.eq(o.selected).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.panels[o.selected]));
+                               });
+                               
+                               this.load(o.selected);
+                       }
+
+                       // clean up to avoid memory leaks in certain versions of IE 6
+                       $(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
+               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 &&
+                               !$(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 ($.browser.msie && fx.opacity) {
+                               $el[0].style.removeAttribute('filter');
+                       }
+               }
+
+               // Show a tab...
+               var showTab = showFx ?
+                       function(clicked, $show) {
+                               $(clicked).closest('li').removeClass('ui-state-default').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').removeClass('ui-state-default').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').addClass('ui-state-default');
+                                       $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').addClass('ui-state-default');
+                               $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 = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
+                                       $show = $(self._sanitizeSelector(this.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._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);
+                                       });
+
+                                       self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
+                                       
+                                       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;});
+
+       },
+
+       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);
+               }
+       },
+
+       add: function(url, label, index) {
+               if (index === undefined) {
+                       index = this.anchors.length; // append by default
+               }
+
+               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 = $('#' + 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) { // after tabify
+                       $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);
+               }
+
+               // callback
+               this._trigger('add', null, this._ui(this.anchors[index], this.panels[index]));
+       },
+
+       remove: function(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();
+
+               // callback
+               this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0]));
+       },
+
+       enable: function(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; });
+
+               // callback
+               this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index]));
+       },
+
+       disable: function(index) {
+               var self = this, o = this.options;
+               if (index != o.selected) { // cannot disable already selected tab
+                       this.lis.eq(index).addClass('ui-state-disabled');
+
+                       o.disabled.push(index);
+                       o.disabled.sort();
+
+                       // callback
+                       this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index]));
+               }
+       },
+
+       select: function(index) {
+               if (typeof index == 'string') {
+                       index = this.anchors.index(this.anchors.filter('[href$=' + index + ']'));
+               }
+               else if (index === null) { // usage of null is deprecated, TODO remove in next release
+                       index = -1;
+               }
+               if (index == -1 && this.options.collapsible) {
+                       index = this.options.selected;
+               }
+
+               this.anchors.eq(index).trigger(this.options.event + '.tabs');
+       },
+
+       load: function(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._sanitizeSelector(a.hash)).html(r);
+
+                               // take care of tab labels
+                               self._cleanup();
+
+                               if (o.cache) {
+                                       $.data(a, 'cache.tabs', true); // if loaded once do not load them again
+                               }
+
+                               // callbacks
+                               self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
+                               try {
+                                       o.ajaxOptions.success(r, s);
+                               }
+                               catch (e) {}
+
+                               // last, so that load event is fired before show...
+                               self.element.dequeue("tabs");
+                       }
+               }));
+       },
+
+       abort: function() {
+               // stop possibly running animations
+               this.element.queue([]);
+               this.panels.stop(false, true);
+
+               // terminate pending requests from other tabs
+               if (this.xhr) {
+                       this.xhr.abort();
+                       delete this.xhr;
+               }
+
+               // take care of tab labels
+               this._cleanup();
+
+       },
+
+       url: function(index, url) {
+               this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url);
+       },
+
+       length: function() {
+               return this.anchors.length;
+       }
+
+});
+
+$.extend($.ui.tabs, {
+       version: '1.7.1',
+       getter: 'length',
+       defaults: {
+               ajaxOptions: null,
+               cache: false,
+               cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
+               collapsible: false,
+               disabled: [],
+               event: 'click',
+               fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
+               idPrefix: 'ui-tabs-',
+               panelTemplate: '<div></div>',
+               spinner: '<em>Loading&#8230;</em>',
+               tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
+       }
+});
+
+/*
+ * 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;
+               }
+       }
+});
+
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/jquery.ui-1.7.1/version.txt b/js2/mwEmbed/jquery/jquery.ui-1.7.1/version.txt
new file mode 100644 (file)
index 0000000..081af9a
--- /dev/null
@@ -0,0 +1 @@
+1.7.1
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/date.js b/js2/mwEmbed/jquery/plugins/date.js
new file mode 100644 (file)
index 0000000..86f802f
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Date prototype extensions. Doesn't depend on any
+ * other code. Doens't overwrite existing methods.
+ *
+ * Adds dayNames, abbrDayNames, monthNames and abbrMonthNames static properties and isLeapYear,
+ * isWeekend, isWeekDay, getDaysInMonth, getDayName, getMonthName, getDayOfYear, getWeekOfYear,
+ * setDayOfYear, addYears, addMonths, addDays, addHours, addMinutes, addSeconds methods
+ *
+ * Copyright (c) 2006 Jörn Zaefferer and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ *
+ * Additional methods and properties added by Kelvin Luck: firstDayOfWeek, dateFormat, zeroTime, asString, fromString -
+ * I've added my name to these methods so you know who to blame if they are broken!
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+/**
+ * An Array of day names starting with Sunday.
+ *
+ * @example dayNames[0]
+ * @result 'Sunday'
+ *
+ * @name dayNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+
+/**
+ * An Array of abbreviated day names starting with Sun.
+ *
+ * @example abbrDayNames[0]
+ * @result 'Sun'
+ *
+ * @name abbrDayNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.abbrDayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+
+/**
+ * An Array of month names starting with Janurary.
+ *
+ * @example monthNames[0]
+ * @result 'January'
+ *
+ * @name monthNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+
+/**
+ * An Array of abbreviated month names starting with Jan.
+ *
+ * @example abbrMonthNames[0]
+ * @result 'Jan'
+ *
+ * @name monthNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.abbrMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+/**
+ * The first day of the week for this locale.
+ *
+ * @name firstDayOfWeek
+ * @type Number
+ * @cat Plugins/Methods/Date
+ * @author Kelvin Luck
+ */
+Date.firstDayOfWeek = 1;
+
+/**
+ * The format that string dates should be represented as (e.g. 'dd/mm/yyyy' for UK, 'mm/dd/yyyy' for US, 'yyyy-mm-dd' for Unicode etc).
+ *
+ * @name format
+ * @type String
+ * @cat Plugins/Methods/Date
+ * @author Kelvin Luck
+ */
+Date.format = 'dd/mm/yyyy';
+//Date.format = 'mm/dd/yyyy';
+//Date.format = 'yyyy-mm-dd';
+//Date.format = 'dd mmm yy';
+
+/**
+ * The first two numbers in the century to be used when decoding a two digit year. Since a two digit year is ambiguous (and date.setYear
+ * only works with numbers < 99 and so doesn't allow you to set years after 2000) we need to use this to disambiguate the two digit year codes.
+ *
+ * @name format
+ * @type String
+ * @cat Plugins/Methods/Date
+ * @author Kelvin Luck
+ */
+Date.fullYearStart = '20';
+
+(function() {
+
+       /**
+        * Adds a given method under the given name
+        * to the Date prototype if it doesn't
+        * currently exist.
+        *
+        * @private
+        */
+       function add(name, method) {
+               if( !Date.prototype[name] ) {
+                       Date.prototype[name] = method;
+               }
+       };
+
+       /**
+        * Checks if the year is a leap year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.isLeapYear();
+        * @result true
+        *
+        * @name isLeapYear
+        * @type Boolean
+        * @cat Plugins/Methods/Date
+        */
+       add("isLeapYear", function() {
+               var y = this.getFullYear();
+               return (y%4==0 && y%100!=0) || y%400==0;
+       });
+
+       /**
+        * Checks if the day is a weekend day (Sat or Sun).
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.isWeekend();
+        * @result false
+        *
+        * @name isWeekend
+        * @type Boolean
+        * @cat Plugins/Methods/Date
+        */
+       add("isWeekend", function() {
+               return this.getDay()==0 || this.getDay()==6;
+       });
+
+       /**
+        * Check if the day is a day of the week (Mon-Fri)
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.isWeekDay();
+        * @result false
+        *
+        * @name isWeekDay
+        * @type Boolean
+        * @cat Plugins/Methods/Date
+        */
+       add("isWeekDay", function() {
+               return !this.isWeekend();
+       });
+
+       /**
+        * Gets the number of days in the month.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDaysInMonth();
+        * @result 31
+        *
+        * @name getDaysInMonth
+        * @type Number
+        * @cat Plugins/Methods/Date
+        */
+       add("getDaysInMonth", function() {
+               return [31,(this.isLeapYear() ? 29:28),31,30,31,30,31,31,30,31,30,31][this.getMonth()];
+       });
+
+       /**
+        * Gets the name of the day.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDayName();
+        * @result 'Saturday'
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDayName(true);
+        * @result 'Sat'
+        *
+        * @param abbreviated Boolean When set to true the name will be abbreviated.
+        * @name getDayName
+        * @type String
+        * @cat Plugins/Methods/Date
+        */
+       add("getDayName", function(abbreviated) {
+               return abbreviated ? Date.abbrDayNames[this.getDay()] : Date.dayNames[this.getDay()];
+       });
+
+       /**
+        * Gets the name of the month.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getMonthName();
+        * @result 'Janurary'
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getMonthName(true);
+        * @result 'Jan'
+        *
+        * @param abbreviated Boolean When set to true the name will be abbreviated.
+        * @name getDayName
+        * @type String
+        * @cat Plugins/Methods/Date
+        */
+       add("getMonthName", function(abbreviated) {
+               return abbreviated ? Date.abbrMonthNames[this.getMonth()] : Date.monthNames[this.getMonth()];
+       });
+
+       /**
+        * Get the number of the day of the year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDayOfYear();
+        * @result 11
+        *
+        * @name getDayOfYear
+        * @type Number
+        * @cat Plugins/Methods/Date
+        */
+       add("getDayOfYear", function() {
+               var tmpdtm = new Date("1/1/" + this.getFullYear());
+               return Math.floor((this.getTime() - tmpdtm.getTime()) / 86400000);
+       });
+
+       /**
+        * Get the number of the week of the year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getWeekOfYear();
+        * @result 2
+        *
+        * @name getWeekOfYear
+        * @type Number
+        * @cat Plugins/Methods/Date
+        */
+       add("getWeekOfYear", function() {
+               return Math.ceil(this.getDayOfYear() / 7);
+       });
+
+       /**
+        * Set the day of the year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.setDayOfYear(1);
+        * dtm.toString();
+        * @result 'Tue Jan 01 2008 00:00:00'
+        *
+        * @name setDayOfYear
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("setDayOfYear", function(day) {
+               this.setMonth(0);
+               this.setDate(day);
+               return this;
+       });
+
+       /**
+        * Add a number of years to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addYears(1);
+        * dtm.toString();
+        * @result 'Mon Jan 12 2009 00:00:00'
+        *
+        * @name addYears
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addYears", function(num) {
+               this.setFullYear(this.getFullYear() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of months to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addMonths(1);
+        * dtm.toString();
+        * @result 'Tue Feb 12 2008 00:00:00'
+        *
+        * @name addMonths
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addMonths", function(num) {
+               var tmpdtm = this.getDate();
+
+               this.setMonth(this.getMonth() + num);
+
+               if (tmpdtm > this.getDate())
+                       this.addDays(-this.getDate());
+
+               return this;
+       });
+
+       /**
+        * Add a number of days to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addDays(1);
+        * dtm.toString();
+        * @result 'Sun Jan 13 2008 00:00:00'
+        *
+        * @name addDays
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addDays", function(num) {
+               this.setDate(this.getDate() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of hours to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addHours(24);
+        * dtm.toString();
+        * @result 'Sun Jan 13 2008 00:00:00'
+        *
+        * @name addHours
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addHours", function(num) {
+               this.setHours(this.getHours() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of minutes to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addMinutes(60);
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 01:00:00'
+        *
+        * @name addMinutes
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addMinutes", function(num) {
+               this.setMinutes(this.getMinutes() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of seconds to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addSeconds(60);
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 00:01:00'
+        *
+        * @name addSeconds
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addSeconds", function(num) {
+               this.setSeconds(this.getSeconds() + num);
+               return this;
+       });
+
+       /**
+        * Sets the time component of this Date to zero for cleaner, easier comparison of dates where time is not relevant.
+        *
+        * @example var dtm = new Date();
+        * dtm.zeroTime();
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 00:01:00'
+        *
+        * @name zeroTime
+        * @type Date
+        * @cat Plugins/Methods/Date
+        * @author Kelvin Luck
+        */
+       add("zeroTime", function() {
+               this.setMilliseconds(0);
+               this.setSeconds(0);
+               this.setMinutes(0);
+               this.setHours(0);
+               return this;
+       });
+
+       /**
+        * Returns a string representation of the date object according to Date.format.
+        * (Date.toString may be used in other places so I purposefully didn't overwrite it)
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.asString();
+        * @result '12/01/2008' // (where Date.format == 'dd/mm/yyyy'
+        *
+        * @name asString
+        * @type Date
+        * @cat Plugins/Methods/Date
+        * @author Kelvin Luck
+        */
+       add("asString", function() {
+               var r = Date.format;
+               return r
+                       .split('yyyy').join(this.getFullYear())
+                       .split('yy').join((this.getFullYear() + '').substring(2))
+                       .split('mmm').join(this.getMonthName(true))
+                       .split('mm').join(_zeroPad(this.getMonth()+1))
+                       .split('dd').join(_zeroPad(this.getDate()));
+       });
+
+       /**
+        * Returns a new date object created from the passed String according to Date.format or false if the attempt to do this results in an invalid date object
+        * (We can't simple use Date.parse as it's not aware of locale and I chose not to overwrite it incase it's functionality is being relied on elsewhere)
+        *
+        * @example var dtm = Date.fromString("12/01/2008");
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 00:00:00' // (where Date.format == 'dd/mm/yyyy'
+        *
+        * @name fromString
+        * @type Date
+        * @cat Plugins/Methods/Date
+        * @author Kelvin Luck
+        */
+       Date.fromString = function(s)
+       {
+               var f = Date.format;
+               var d = new Date('01/01/1977');
+               var iY = f.indexOf('yyyy');
+               if (iY > -1) {
+                       d.setFullYear(Number(s.substr(iY, 4)));
+               } else {
+                       // TODO - this doesn't work very well - are there any rules for what is meant by a two digit year?
+                       d.setFullYear(Number(Date.fullYearStart + s.substr(f.indexOf('yy'), 2)));
+               }
+               var iM = f.indexOf('mmm');
+               if (iM > -1) {
+                       var mStr = s.substr(iM, 3);
+                       for (var i=0; i<Date.abbrMonthNames.length; i++) {
+                               if (Date.abbrMonthNames[i] == mStr) break;
+                       }
+                       d.setMonth(i);
+               } else {
+                       d.setMonth(Number(s.substr(f.indexOf('mm'), 2)) - 1);
+               }
+               d.setDate(Number(s.substr(f.indexOf('dd'), 2)));
+               if (isNaN(d.getTime())) {
+                       return false;
+               }
+               return d;
+       };
+
+       // utility method
+       var _zeroPad = function(num) {
+               var s = '0'+num;
+               return s.substring(s.length-2)
+               //return ('0'+num).substring(-2); // doesn't work on IE :(
+       };
+
+})();
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/images/cut.png b/js2/mwEmbed/jquery/plugins/images/cut.png
new file mode 100644 (file)
index 0000000..f215d6f
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/images/cut.png differ
diff --git a/js2/mwEmbed/jquery/plugins/images/door.png b/js2/mwEmbed/jquery/plugins/images/door.png
new file mode 100644 (file)
index 0000000..369fc46
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/images/door.png differ
diff --git a/js2/mwEmbed/jquery/plugins/images/page_white_copy.png b/js2/mwEmbed/jquery/plugins/images/page_white_copy.png
new file mode 100644 (file)
index 0000000..a9f31a2
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/images/page_white_copy.png differ
diff --git a/js2/mwEmbed/jquery/plugins/images/page_white_delete.png b/js2/mwEmbed/jquery/plugins/images/page_white_delete.png
new file mode 100644 (file)
index 0000000..af1ecaf
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/images/page_white_delete.png differ
diff --git a/js2/mwEmbed/jquery/plugins/images/page_white_edit.png b/js2/mwEmbed/jquery/plugins/images/page_white_edit.png
new file mode 100644 (file)
index 0000000..b93e776
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/images/page_white_edit.png differ
diff --git a/js2/mwEmbed/jquery/plugins/images/page_white_paste.png b/js2/mwEmbed/jquery/plugins/images/page_white_paste.png
new file mode 100644 (file)
index 0000000..5b2cbb3
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/images/page_white_paste.png differ
diff --git a/js2/mwEmbed/jquery/plugins/indicator.gif b/js2/mwEmbed/jquery/plugins/indicator.gif
new file mode 100644 (file)
index 0000000..085ccae
Binary files /dev/null and b/js2/mwEmbed/jquery/plugins/indicator.gif differ
diff --git a/js2/mwEmbed/jquery/plugins/jquery.autocomplete.css b/js2/mwEmbed/jquery/plugins/jquery.autocomplete.css
new file mode 100644 (file)
index 0000000..cb9107b
--- /dev/null
@@ -0,0 +1,46 @@
+.ac_results {
+       padding: 0px;
+       border: 1px solid WindowFrame;
+       background-color: Window;
+       overflow: hidden;
+}
+
+.ac_results ul {
+       width: 100%;
+       list-style-position: outside;
+       list-style: none;
+       padding: 0;
+       margin: 0;
+}
+
+.ac_results iframe {
+       display:none;/*sorry for IE5*/
+       display/**/:block;/*sorry for IE5*/
+       position:absolute;
+       top:0;
+       left:0;
+       z-index:-1;
+       filter:mask();
+       width:3000px;
+       height:3000px;
+}
+
+.ac_results li {
+       margin: 0px;
+       padding: 2px 5px;
+       cursor: pointer;
+       display: block;
+       width: 100%;
+       font: menu;
+       font-size: 12px;
+       overflow: hidden;
+}
+
+.ac_loading {
+       background : Window url('./indicator.gif') right center no-repeat;
+}
+
+.ac_over {
+       background-color: Highlight;
+       color: HighlightText;
+}
diff --git a/js2/mwEmbed/jquery/plugins/jquery.autocomplete.js b/js2/mwEmbed/jquery/plugins/jquery.autocomplete.js
new file mode 100644 (file)
index 0000000..396ed27
--- /dev/null
@@ -0,0 +1,529 @@
+(function($){
+
+jQuery.autocomplete = function(input, options) {
+       // Create a link to self
+       var me = this;
+
+       // Create jQuery object for input element
+       var $input = $(input).attr("autocomplete", "off");
+
+       // Apply inputClass if necessary
+       if (options.inputClass) $input.addClass(options.inputClass);
+
+       // Create results
+       if(!options.resultElem){
+               var results = document.createElement("div");
+               // Create jQuery object for results
+               var $results = $(results);
+               // Add to body element
+               $("body").append(results);
+               $results.hide().addClass(options.resultsClass).css("position", "absolute");
+               if( options.width > 0 ) $results.css("width", options.width);
+       }else{
+               var results = $j(options.resultElem).get(0);
+               var $results = $j(options.resultElem);
+               $results.hide();
+       }
+
+
+       input.autocompleter = me;
+
+       var timeout = null;
+       var prev = "";
+       var active = -1;
+       var cache = {};
+       var keyb = false;
+       var hasFocus = false;
+       var lastKeyPressCode = null;
+
+       // flush cache
+       function flushCache(){
+               cache = {};
+               cache.data = {};
+               cache.length = 0;
+       };
+
+       // flush cache
+       flushCache();
+
+       // if there is a data array supplied
+       if( options.data != null ){
+               var sFirstChar = "", stMatchSets = {}, row = [];
+
+               // no url was specified, we need to adjust the cache length to make sure it fits the local data store
+               if( typeof options.url != "string" ) options.cacheLength = 1;
+
+               // loop through the array and create a lookup structure
+               for( var i=0; i < options.data.length; i++ ){
+                       // if row is a string, make an array otherwise just reference the array
+                       row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]);
+
+                       // if the length is zero, don't add to list
+                       if( row[0].length > 0 ){
+                               // get the first character
+                               sFirstChar = row[0].substring(0, 1).toLowerCase();
+                               // if no lookup array for this character exists, look it up now
+                               if( !stMatchSets[sFirstChar] ) stMatchSets[sFirstChar] = [];
+                               // if the match is a string
+                               stMatchSets[sFirstChar].push(row);
+                       }
+               }
+
+               // add the data items to the cache
+               for( var k in stMatchSets ){
+                       // increase the cache size
+                       options.cacheLength++;
+                       // add to the cache
+                       addToCache(k, stMatchSets[k]);
+               }
+       }
+
+       $input
+       .keydown(function(e) {
+               // track last key pressed
+               lastKeyPressCode = e.keyCode;
+               switch(e.keyCode) {
+                       case 38: // up
+                               e.preventDefault();
+                               moveSelect(-1);
+                               break;
+                       case 40: // down
+                               e.preventDefault();
+                               moveSelect(1);
+                               break;
+                       case 9:  // tab
+                       case 13: // return
+                               if( selectCurrent() ){
+                                       // make sure to blur off the current field
+                                       $input.get(0).blur();
+                                       e.preventDefault();
+                               }
+                               break;
+                       default:
+                               active = -1;
+                               if (timeout) clearTimeout(timeout);
+                               timeout = setTimeout(function(){onChange();}, options.delay);
+                               break;
+               }
+       })
+       .focus(function(){
+               // track whether the field has focus, we shouldn't process any results if the field no longer has focus
+               hasFocus = true;
+       })
+       .blur(function() {
+               // track whether the field has focus
+               hasFocus = false;
+               hideResults();
+       });
+
+       hideResultsNow();
+
+       function onChange() {
+               // ignore if the following keys are pressed: [del] [shift] [capslock]
+               if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ) return $results.hide();
+               var v = $input.val();
+               if (v == prev) return;
+               prev = v;
+               if (v.length >= options.minChars) {
+                       $input.addClass(options.loadingClass);
+                       requestData(v);
+               } else {
+                       $input.removeClass(options.loadingClass);
+                       $results.hide();
+               }
+       };
+
+       function moveSelect(step) {
+               var lis = $("li", results);
+               if (!lis) return;
+
+               active += step;
+
+               if (active < 0) {
+                       active = 0;
+               } else if (active >= lis.size()) {
+                       active = lis.size() - 1;
+               }
+
+               lis.removeClass("ac_over");
+
+               $(lis[active]).addClass("ac_over");
+
+               // Weird behaviour in IE
+               // if (lis[active] && lis[active].scrollIntoView) {
+               //      lis[active].scrollIntoView(false);
+               // }
+
+       };
+       function selectCurrent() {
+               var li = $("li.ac_over", results)[0];
+               if (!li) {
+                       var $li = $("li", results);
+                       if (options.selectOnly) {
+                               if ($li.length == 1) li = $li[0];
+                       } else if (options.selectFirst) {
+                               li = $li[0];
+                       }
+               }
+               if (li) {
+                       selectItem(li);
+                       return true;
+               } else {
+                       return false;
+               }
+       };
+
+       function selectItem(li) {
+               if (!li) {
+                       li = document.createElement("li");
+                       li.extra = [];
+                       li.selectValue = "";
+               }
+               var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML);
+               input.lastSelected = v;
+               prev = v;
+               $results.html("");
+               $input.val(v);
+               hideResultsNow();
+               if (options.onItemSelect) setTimeout(function() { options.onItemSelect(li) }, 1);
+       };
+
+       // selects a portion of the input string
+       function createSelection(start, end){
+               // get a reference to the input element
+               var field = $input.get(0);
+               if( field.createTextRange ){
+                       var selRange = field.createTextRange();
+                       selRange.collapse(true);
+                       selRange.moveStart("character", start);
+                       selRange.moveEnd("character", end);
+                       selRange.select();
+               } else if( field.setSelectionRange ){
+                       field.setSelectionRange(start, end);
+               } else {
+                       if( field.selectionStart ){
+                               field.selectionStart = start;
+                               field.selectionEnd = end;
+                       }
+               }
+               field.focus();
+       };
+
+       // fills in the input box w/the first match (assumed to be the best match)
+       function autoFill(sValue){
+               // if the last user key pressed was backspace, don't autofill
+               if( lastKeyPressCode != 8 ){
+                       // fill in the value (keep the case the user has typed)
+                       $input.val($input.val() + sValue.substring(prev.length));
+                       // select the portion of the value not typed by the user (so the next character will erase)
+                       createSelection(prev.length, sValue.length);
+               }
+       };
+
+       function showResults() {
+               // get the position of the input field right now (in case the DOM is shifted)
+               var pos = findPos(input);
+               // either use the specified width, or autocalculate based on form element
+               var iWidth = (options.width > 0) ? options.width : $input.width();
+               // reposition
+               if(!options.resultElem){
+                       $results.css({
+                               width: parseInt(iWidth) + "px",
+                               top: (pos.y + input.offsetHeight) + "px",
+                               left: pos.x + "px"
+                       }).show();
+               }else{
+                       $results.show();
+               }
+               if(options.resultContainer){
+                       $(options.resultContainer).css({top: (pos.y + input.offsetHeight) + "px",
+                               left: (pos.x- parseInt(iWidth)) + "px"}).show();
+               }
+       };
+
+       function hideResults() {
+               if (timeout) clearTimeout(timeout);
+               timeout = setTimeout(hideResultsNow, 200);
+       };
+
+       function hideResultsNow() {
+               if (timeout) clearTimeout(timeout);
+               $input.removeClass(options.loadingClass);
+               if ($results.is(":visible")) {
+                       $results.hide();
+               }
+               if(options.resultContainer){
+                       $(options.resultContainer).hide();
+               }
+               if (options.mustMatch) {
+                       var v = $input.val();
+                       if (v != input.lastSelected) {
+                               selectItem(null);
+                       }
+               }
+       };
+
+       function receiveData(q, data) {
+               if (data) {
+                       $input.removeClass(options.loadingClass);
+                       results.innerHTML = "";
+
+                       // if the field no longer has focus or if there are no matches, do not display the drop down
+                       if( !hasFocus || data.length == 0 ) return hideResultsNow();
+
+                       //messes with layout & ie7 does not have this problem
+                       /*if ($.browser.msie) {
+                               // we put a styled iframe behind the calendar so HTML SELECT elements don't show through
+                               $results.append(document.createElement('iframe'));
+                       }*/
+                       results.appendChild(dataToDom(data));
+                       // autofill in the complete box w/the first match as long as the user hasn't entered in more data
+                       if( options.autoFill && ($input.val().toLowerCase() == q.toLowerCase()) ) autoFill(data[0][0]);
+                       showResults();
+               } else {
+                       hideResultsNow();
+               }
+       };
+
+       function parseData(data) {
+               if (!data) return null;
+               var parsed = [];
+               var rows = data.split(options.lineSeparator);
+               for (var i=0; i < rows.length; i++) {
+                       var row = $.trim(rows[i]);
+                       if (row) {
+                               parsed[parsed.length] = row.split(options.cellSeparator);
+                       }
+               }
+               return parsed;
+       };
+
+       function dataToDom(data) {
+               var ul = document.createElement("ul");
+               if(options.ul_class)$(ul).addClass(options.ul_class);
+
+               var num = data.length;
+
+               // limited results to a max number
+               if( (options.maxItemsToShow > 0) && (options.maxItemsToShow < num) ) num = options.maxItemsToShow;
+
+               for (var i=0; i < num; i++) {
+                       var row = data[i];
+                       if (!row) continue;
+                       var li = document.createElement("li");
+                       if (options.formatItem) {
+                               li.innerHTML = options.formatItem(row, i, num);
+                               li.selectValue = row[0];
+                       } else {
+                               li.innerHTML = row[0];
+                               li.selectValue = row[0];
+                       }
+                       var extra = null;
+                       if (row.length > 1) {
+                               extra = [];
+                               for (var j=1; j < row.length; j++) {
+                                       extra[extra.length] = row[j];
+                               }
+                       }
+                       li.extra = extra;
+                       ul.appendChild(li);
+                       $(li).hover(
+                               function() { $("li", ul).removeClass("ac_over"); $(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); },
+                               function() { $(this).removeClass("ac_over"); }
+                       ).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this) });
+               }
+               return ul;
+       };
+
+       function requestData(q) {
+               if (!options.matchCase) q = q.toLowerCase();
+               //var data = options.cacheLength ? loadFromCache(q) : null;
+               var data=null;
+               // recieve the cached data
+               if (data) {
+                       receiveData(q, data);
+               // if an AJAX url has been supplied, try loading the data now
+               } else if( (typeof options.url == "string") && (options.url.length > 0) ){
+                       $.get(makeUrl(q), function(data) {
+                               data = parseData(data);
+                               addToCache(q, data);
+                               receiveData(q, data);
+                       });
+               // if there's been no data found, remove the loading class
+               } else {
+                       $input.removeClass(options.loadingClass);
+               }
+       };
+
+       function makeUrl(q) {
+               var url = options.url + "?"+options.paramName+'='+ encodeURI(q);
+               for (var i in options.extraParams) {
+                       url += "&" + i + "=" + encodeURI(options.extraParams[i]);
+               }
+               return url;
+       };
+
+       function loadFromCache(q) {
+               if (!q) return null;
+               if (typeof cache.data[q]!='undefined'){
+                       return cache.data[q];
+               }
+               if (options.matchSubset) {
+                       for (var i = q.length - 1; i >= options.minChars; i--) {
+                               var qs = q.substr(0, i);
+                               var c = cache.data[qs];
+                               if (c) {
+                                       var csub = [];
+                                       for (var j = 0; j < c.length; j++) {
+                                               var x = c[j];
+                                               var x0 = x[0];
+                                               if (matchSubset(x0, q)) {
+                                                       csub[csub.length] = x;
+                                               }
+                                       }
+                                       return csub;
+                               }
+                       }
+               }
+               return null;
+       };
+
+       function matchSubset(s, sub) {
+               if (!options.matchCase) s = s.toLowerCase();
+               var i = s.indexOf(sub);
+               if (i == -1) return false;
+               return i == 0 || options.matchContains;
+       };
+
+       this.flushCache = function() {
+               flushCache();
+       };
+
+       this.setExtraParams = function(p) {
+               options.extraParams = p;
+       };
+
+       this.findValue = function(){
+               var q = $input.val();
+
+               if (!options.matchCase) q = q.toLowerCase();
+               var data = options.cacheLength ? loadFromCache(q) : null;
+               if (data) {
+                       findValueCallback(q, data);
+               } else if( (typeof options.url == "string") && (options.url.length > 0) ){
+                       $.get(makeUrl(q), function(data) {
+                               data = parseData(data)
+                               addToCache(q, data);
+                               findValueCallback(q, data);
+                       });
+               } else {
+                       // no matches
+                       findValueCallback(q, null);
+               }
+       }
+
+       function findValueCallback(q, data){
+               if (data) $input.removeClass(options.loadingClass);
+
+               var num = (data) ? data.length : 0;
+               var li = null;
+
+               for (var i=0; i < num; i++) {
+                       var row = data[i];
+
+                       if( row[0].toLowerCase() == q.toLowerCase() ){
+                               li = document.createElement("li");
+                               if (options.formatItem) {
+                                       li.innerHTML = options.formatItem(row, i, num);
+                                       li.selectValue = row[0];
+                               } else {
+                                       li.innerHTML = row[0];
+                                       li.selectValue = row[0];
+                               }
+                               var extra = null;
+                               if( row.length > 1 ){
+                                       extra = [];
+                                       for (var j=1; j < row.length; j++) {
+                                               extra[extra.length] = row[j];
+                                       }
+                               }
+                               li.extra = extra;
+                       }
+               }
+
+               if( options.onFindValue ) setTimeout(function() { options.onFindValue(li) }, 1);
+       }
+
+       function addToCache(q, data) {
+               if (!data || !q || !options.cacheLength) return;
+               if (!cache.length || cache.length > options.cacheLength) {
+                       flushCache();
+                       cache.length++;
+               } else if (!cache[q]) {
+                       cache.length++;
+               }
+               cache.data[q] = data;
+       };
+
+       function findPos(obj) {
+               var curleft = obj.offsetLeft || 0;
+               var curtop = obj.offsetTop || 0;
+               while (obj = obj.offsetParent) {
+                       curleft += obj.offsetLeft
+                       curtop += obj.offsetTop
+               }
+               return {x:curleft,y:curtop};
+       }
+}
+})(jQuery);
+
+jQuery.fn.autocomplete = function(url, options, data) {
+       // Make sure options exists
+       options = options || {};
+       // Set url as option
+       options.url = url;
+       // set some bulk local data
+       options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null;
+
+       // Set default values for required options
+       options.resultElem = options.resultElem || null;
+       options.paramName = options.paramName || 'q';
+
+       options.inputClass = options.inputClass || "ac_input";
+       options.resultsClass = options.resultsClass || "ac_results";
+       options.lineSeparator = options.lineSeparator || "\n";
+       options.cellSeparator = options.cellSeparator || "|";
+       options.minChars = options.minChars || 1;
+       options.delay = options.delay || 400;
+       options.matchCase = options.matchCase || 0;
+       options.matchSubset = options.matchSubset || 1;
+       options.matchContains = options.matchContains || 0;
+       options.cacheLength = options.cacheLength || 1;
+       options.mustMatch = options.mustMatch || 0;
+       options.extraParams = options.extraParams || {};
+       options.loadingClass = options.loadingClass || "ac_loading";
+       options.selectFirst = options.selectFirst || false;
+       options.selectOnly = options.selectOnly || false;
+       options.maxItemsToShow = options.maxItemsToShow || -1;
+       options.autoFill = options.autoFill || false;
+       options.width = parseInt(options.width, 10) || 0;
+
+       this.each(function() {
+               var input = this;
+               new jQuery.autocomplete(input, options);
+       });
+
+       // Don't break the chain
+       return this;
+}
+
+jQuery.fn.autocompleteArray = function(data, options) {
+       return this.autocomplete(null, options, data);
+}
+
+jQuery.fn.indexOf = function(e){
+       for( var i=0; i<this.length; i++ ){
+               if( this[i] == e ) return i;
+       }
+       return -1;
+};
diff --git a/js2/mwEmbed/jquery/plugins/jquery.bgiframe.js b/js2/mwEmbed/jquery/plugins/jquery.bgiframe.js
new file mode 100644 (file)
index 0000000..d6369a1
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate$
+ * $Rev$
+ *
+ * Version 2.1.1
+ */
+
+(function($){
+
+/**
+ * The bgiframe is chainable and applies the iframe hack to get
+ * around zIndex issues in IE6. It will only apply itself in IE6
+ * and adds a class to the iframe called 'bgiframe'. The iframe
+ * is appeneded as the first child of the matched element(s)
+ * with a tabIndex and zIndex of -1.
+ *
+ * By default the plugin will take borders, sized with pixel units,
+ * into account. If a different unit is used for the border's width,
+ * then you will need to use the top and left settings as explained below.
+ *
+ * NOTICE: This plugin has been reported to cause perfromance problems
+ * when used on elements that change properties (like width, height and
+ * opacity) a lot in IE6. Most of these problems have been caused by
+ * the expressions used to calculate the elements width, height and
+ * borders. Some have reported it is due to the opacity filter. All
+ * these settings can be changed if needed as explained below.
+ *
+ * @example $('div').bgiframe();
+ * @before <div><p>Paragraph</p></div>
+ * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
+ *
+ * @param Map settings Optional settings to configure the iframe.
+ * @option String|Number top The iframe must be offset to the top
+ *             by the width of the top border. This should be a negative
+ *       number representing the border-top-width. If a number is
+ *             is used here, pixels will be assumed. Otherwise, be sure
+ *             to specify a unit. An expression could also be used.
+ *             By default the value is "auto" which will use an expression
+ *             to get the border-top-width if it is in pixels.
+ * @option String|Number left The iframe must be offset to the left
+ *             by the width of the left border. This should be a negative
+ *       number representing the border-left-width. If a number is
+ *             is used here, pixels will be assumed. Otherwise, be sure
+ *             to specify a unit. An expression could also be used.
+ *             By default the value is "auto" which will use an expression
+ *             to get the border-left-width if it is in pixels.
+ * @option String|Number width This is the width of the iframe. If
+ *             a number is used here, pixels will be assume. Otherwise, be sure
+ *             to specify a unit. An experssion could also be used.
+ *             By default the value is "auto" which will use an experssion
+ *             to get the offsetWidth.
+ * @option String|Number height This is the height of the iframe. If
+ *             a number is used here, pixels will be assume. Otherwise, be sure
+ *             to specify a unit. An experssion could also be used.
+ *             By default the value is "auto" which will use an experssion
+ *             to get the offsetHeight.
+ * @option Boolean opacity This is a boolean representing whether or not
+ *             to use opacity. If set to true, the opacity of 0 is applied. If
+ *             set to false, the opacity filter is not applied. Default: true.
+ * @option String src This setting is provided so that one could change
+ *             the src of the iframe to whatever they need.
+ *             Default: "javascript:false;"
+ *
+ * @name bgiframe
+ * @type jQuery
+ * @cat Plugins/bgiframe
+ * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ */
+$.fn.bgIframe = $.fn.bgiframe = function(s) {
+       // This is only for IE6
+       if ( $.browser.msie && /6.0/.test(navigator.userAgent) ) {
+               s = $.extend({
+                       top      : 'auto', // auto == .currentStyle.borderTopWidth
+                       left    : 'auto', // auto == .currentStyle.borderLeftWidth
+                       width   : 'auto', // auto == offsetWidth
+                       height  : 'auto', // auto == offsetHeight
+                       opacity : true,
+                       src      : 'javascript:false;'
+               }, s || {});
+               var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
+                       html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
+                                          'style="display:block;position:absolute;z-index:-1;'+
+                                                  (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
+                                                  'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
+                                                  'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
+                                                  'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
+                                                  'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
+                                       '"/>';
+               return this.each(function() {
+                       if ( $('> iframe.bgiframe', this).length == 0 )
+                               this.insertBefore( document.createElement(html), this.firstChild );
+               });
+       }
+       return this;
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/jquery.contextMenu.css b/js2/mwEmbed/jquery/plugins/jquery.contextMenu.css
new file mode 100644 (file)
index 0000000..cc67001
--- /dev/null
@@ -0,0 +1,62 @@
+/* Generic context menu styles */
+.contextMenu {
+       position: absolute;
+       width: 120px;
+       z-index: 99999;
+       border: solid 1px #CCC;
+       background: #EEE;
+       padding: 0px;
+       margin: 0px;
+       display: none;
+}
+
+.contextMenu LI {
+       list-style: none;
+       padding: 0px;
+       margin: 0px;
+}
+
+.contextMenu A {
+       color: #333;
+       text-decoration: none;
+       display: block;
+       line-height: 20px;
+       height: 20px;
+       background-position: 6px center;
+       background-repeat: no-repeat;
+       outline: none;
+       padding: 1px 5px;
+       padding-left: 28px;
+}
+
+.contextMenu LI.hover A {
+       color: #FFF;
+       background-color: #3399FF;
+}
+
+.contextMenu LI.disabled A {
+       color: #AAA;
+       cursor: default;
+}
+
+.contextMenu LI.hover.disabled A {
+       background-color: transparent;
+}
+
+.contextMenu LI.separator {
+       border-top: solid 1px #CCC;
+}
+
+/*
+       Adding Icons
+       
+       You can add icons to the context menu by adding
+       classes to the respective LI element(s)
+*/
+
+.contextMenu LI.edit A { background-image: url(images/page_white_edit.png); }
+.contextMenu LI.cut A { background-image: url(images/cut.png); }
+.contextMenu LI.copy A { background-image: url(images/page_white_copy.png); }
+.contextMenu LI.paste A { background-image: url(images/page_white_paste.png); }
+.contextMenu LI.delete A { background-image: url(images/page_white_delete.png); }
+.contextMenu LI.quit A { background-image: url(images/door.png); }
diff --git a/js2/mwEmbed/jquery/plugins/jquery.contextMenu.js b/js2/mwEmbed/jquery/plugins/jquery.contextMenu.js
new file mode 100644 (file)
index 0000000..c93defc
--- /dev/null
@@ -0,0 +1,211 @@
+// jQuery Context Menu Plugin
+//
+// Version 1.00
+//
+// Cory S.N. LaViska
+// A Beautiful Site (http://abeautifulsite.net/)
+//
+// Visit http://abeautifulsite.net/notebook/80 for usage and more information
+//
+// Terms of Use
+//
+// This software is licensed under a Creative Commons License and is copyrighted
+// (C)2008 by Cory S.N. LaViska.
+//
+// For details, visit http://creativecommons.org/licenses/by/3.0/us/
+//
+(function($){
+       $.extend({
+               
+               contextMenu: function(o, callback) {
+                       // Defaults
+                       if( o.menu == undefined ) return false;
+                       if( o.inSpeed == undefined ) o.inSpeed = 150;
+                       if( o.outSpeed == undefined ) o.outSpeed = 75;
+                       // 0 needs to be -1 for expected results (no fade)
+                       if( o.inSpeed == 0 ) o.inSpeed = -1;
+                       if( o.outSpeed == 0 ) o.outSpeed = -1;
+                       // Loop each context menu
+                       $(this).each( function() {
+                               var el = $(this);
+                               var offset = $(el).offset();
+                               // Add contextMenu class
+                               $('#' + o.menu).addClass('contextMenu');
+                               // Simulate a true right click
+                               $(this).mousedown( function(e) {
+                                       var evt = e;
+                                       $(this).mouseup( function(e) {
+                                               var srcElement = $(this);
+                                               $(this).unbind('mouseup');
+                                               if( evt.button == 2 ) {
+                                                       // Hide context menus that may be showing
+                                                       $(".contextMenu").hide();
+                                                       // Get this context menu
+                                                       var menu = $('#' + o.menu);
+                                                       
+                                                       if( $(el).hasClass('disabled') ) return false;
+                                                       
+                                                       // Detect mouse position
+                                                       var d = {}, x, y;
+                                                       if( self.innerHeight ) {
+                                                               d.pageYOffset = self.pageYOffset;
+                                                               d.pageXOffset = self.pageXOffset;
+                                                               d.innerHeight = self.innerHeight;
+                                                               d.innerWidth = self.innerWidth;
+                                                       } else if( document.documentElement &&
+                                                               document.documentElement.clientHeight ) {
+                                                               d.pageYOffset = document.documentElement.scrollTop;
+                                                               d.pageXOffset = document.documentElement.scrollLeft;
+                                                               d.innerHeight = document.documentElement.clientHeight;
+                                                               d.innerWidth = document.documentElement.clientWidth;
+                                                       } else if( document.body ) {
+                                                               d.pageYOffset = document.body.scrollTop;
+                                                               d.pageXOffset = document.body.scrollLeft;
+                                                               d.innerHeight = document.body.clientHeight;
+                                                               d.innerWidth = document.body.clientWidth;
+                                                       }
+                                                       (e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft;
+                                                       (e.pageY) ? y = e.pageY : x = e.clientY + d.scrollTop;
+                                                       
+                                                       // Show the menu
+                                                       $(document).unbind('click');
+                                                       $(menu).css({ top: y, left: x }).fadeIn(o.inSpeed);
+                                                       // Hover events
+                                                       $(menu).find('A').mouseover( function() {
+                                                               $(menu).find('LI.hover').removeClass('hover');
+                                                               $(this).parent().addClass('hover');
+                                                       }).mouseout( function() {
+                                                               $(menu).find('LI.hover').removeClass('hover');
+                                                       });
+                                                       
+                                                       // Keyboard
+                                                       $(document).keypress( function(e) {
+                                                               switch( e.keyCode ) {
+                                                                       case 38: // up
+                                                                               if( $(menu).find('LI.hover').size() == 0 ) {
+                                                                                       $(menu).find('LI:last').addClass('hover');
+                                                                               } else {
+                                                                                       $(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
+                                                                                       if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');
+                                                                               }
+                                                                       break;
+                                                                       case 40: // down
+                                                                               if( $(menu).find('LI.hover').size() == 0 ) {
+                                                                                       $(menu).find('LI:first').addClass('hover');
+                                                                               } else {
+                                                                                       $(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
+                                                                                       if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover');
+                                                                               }
+                                                                       break;
+                                                                       case 13: // enter
+                                                                               $(menu).find('LI.hover A').trigger('click');
+                                                                       break;
+                                                                       case 27: // esc
+                                                                               $(document).trigger('click');
+                                                                       break
+                                                               }
+                                                       });
+                                                       
+                                                       // When items are selected
+                                                       $('#' + o.menu).find('A').unbind('click');
+                                                       $('#' + o.menu).find('LI:not(.disabled) A').click( function() {
+                                                               $(document).unbind('click').unbind('keypress');
+                                                               $(".contextMenu").hide();
+                                                               // Callback
+                                                               if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} );
+                                                               return false;
+                                                       });
+                                                       
+                                                       // Hide bindings
+                                                       setTimeout( function() { // Delay for Mozilla
+                                                               $(document).click( function() {
+                                                                       $(document).unbind('click').unbind('keypress');
+                                                                       $(menu).fadeOut(o.outSpeed);
+                                                                       return false;
+                                                               });
+                                                       }, 0);
+                                               }
+                                       });
+                               });
+                               
+                               // Disable text selection
+                               if( $.browser.mozilla ) {
+                                       $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); });
+                               } else if( $.browser.msie ) {
+                                       $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); });
+                               } else {
+                                       $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); });
+                               }
+                               // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
+                               $(el).add('UL.contextMenu').bind('contextmenu', function() { return false; });
+                               
+                       });
+                       return $(this);
+               },
+               
+               // Disable context menu items on the fly
+               disableContextMenuItems: function(o) {
+                       if( o == undefined ) {
+                               // Disable all
+                               $(this).find('LI').addClass('disabled');
+                               return( $(this) );
+                       }
+                       $(this).each( function() {
+                               if( o != undefined ) {
+                                       var d = o.split(',');
+                                       for( var i = 0; i < d.length; i++ ) {
+                                               $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
+                                               
+                                       }
+                               }
+                       });
+                       return( $(this) );
+               },
+               
+               // Enable context menu items on the fly
+               enableContextMenuItems: function(o) {
+                       if( o == undefined ) {
+                               // Enable all
+                               $(this).find('LI.disabled').removeClass('disabled');
+                               return( $(this) );
+                       }
+                       $(this).each( function() {
+                               if( o != undefined ) {
+                                       var d = o.split(',');
+                                       for( var i = 0; i < d.length; i++ ) {
+                                               $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
+                                               
+                                       }
+                               }
+                       });
+                       return( $(this) );
+               },
+               
+               // Disable context menu(s)
+               disableContextMenu: function() {
+                       $(this).each( function() {
+                               $(this).addClass('disabled');
+                       });
+                       return( $(this) );
+               },
+               
+               // Enable context menu(s)
+               enableContextMenu: function() {
+                       $(this).each( function() {
+                               $(this).removeClass('disabled');
+                       });
+                       return( $(this) );
+               },
+               
+               // Destroy context menu(s)
+               destroyContextMenu: function() {
+                       // Destroy specified context menus
+                       $(this).each( function() {
+                               // Disable action
+                               $(this).unbind('mousedown').unbind('mouseup');
+                       });
+                       return( $(this) );
+               }
+               
+       });
+})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/jquery.cookie.js b/js2/mwEmbed/jquery/plugins/jquery.cookie.js
new file mode 100644 (file)
index 0000000..a80bfa2
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+/**
+ * Create a cookie with the given name and value and other optional parameters.
+ *
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Set the value of a cookie.
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
+ * @desc Create a cookie with all available options.
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Create a session cookie.
+ * @example $.cookie('the_cookie', null);
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
+ *       used when the cookie was set.
+ *
+ * @param String name The name of the cookie.
+ * @param String value The value of the cookie.
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
+ *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
+ *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
+ *                             when the the browser exits.
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
+ *                        require a secure protocol (like HTTPS).
+ * @type undefined
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
+ */
+
+/**
+ * Get the value of a cookie with the given name.
+ *
+ * @example $.cookie('the_cookie');
+ * @desc Get the value of a cookie.
+ *
+ * @param String name The name of the cookie.
+ * @return The value of the cookie.
+ * @type String
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
+ */
+jQuery.cookie = function(name, value, options) {
+    if (typeof value != 'undefined') { // name and value given, set cookie
+        options = options || {};
+        if (value === null) {
+            value = '';
+            options = $.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed
+            options.expires = -1;
+        }
+        var expires = '';
+        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
+            var date;
+            if (typeof options.expires == 'number') {
+                date = new Date();
+                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
+            } else {
+                date = options.expires;
+            }
+            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
+        }
+        // NOTE Needed to parenthesize options.path and options.domain
+        // in the following expressions, otherwise they evaluate to undefined
+        // in the packed version for some reason...
+        var path = options.path ? '; path=' + (options.path) : '';
+        var domain = options.domain ? '; domain=' + (options.domain) : '';
+        var secure = options.secure ? '; secure' : '';
+        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
+    } else { // only name given, get cookie
+        var cookieValue = null;
+        if (document.cookie && document.cookie != '') {
+            var cookies = document.cookie.split(';');
+            for (var i = 0; i < cookies.length; i++) {
+                var cookie = jQuery.trim(cookies[i]);
+                // Does this cookie string begin with the name we want?
+                if (cookie.substring(0, name.length + 1) == (name + '=')) {
+                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+                    break;
+                }
+            }
+        }
+        return cookieValue;
+    }
+};
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/jquery.datePicker.js b/js2/mwEmbed/jquery/plugins/jquery.datePicker.js
new file mode 100644 (file)
index 0000000..f576c37
--- /dev/null
@@ -0,0 +1,1525 @@
+/**
+ * Copyright (c) 2007 Kelvin Luck (http://www.kelvinluck.com/)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $Id: jquery.datePicker.js 3739 2007-10-25 13:55:30Z kelvin.luck $
+ **/
+
+(function($){
+
+       $.fn.extend({
+/**
+ * Render a calendar table into any matched elements.
+ *
+ * @param Object s (optional) Customize your calendars.
+ * @option Number month The month to render (NOTE that months are zero based). Default is today's month.
+ * @option Number year The year to render. Default is today's year.
+ * @option Function renderCallback A reference to a function that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Default is no callback.
+ * @option Number showHeader Whether or not to show the header row, possible values are: $.dpConst.SHOW_HEADER_NONE (no header), $.dpConst.SHOW_HEADER_SHORT (first letter of each day) and $.dpConst.SHOW_HEADER_LONG (full name of each day). Default is $.dpConst.SHOW_HEADER_SHORT.
+ * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
+ * @type jQuery
+ * @name renderCalendar
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('#calendar-me').renderCalendar({month:0, year:2007});
+ * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me.
+ *
+ * @example
+ * var testCallback = function($td, thisDate, month, year)
+ * {
+ * if ($td.is('.current-month') && thisDate.getDay() == 4) {
+ *             var d = thisDate.getDate();
+ *             $td.bind(
+ *                     'click',
+ *                     function()
+ *                     {
+ *                             alert('You clicked on ' + d + '/' + (Number(month)+1) + '/' + year);
+ *                     }
+ *             ).addClass('thursday');
+ *     } else if (thisDate.getDay() == 5) {
+ *             $td.html('Friday the ' + $td.html() + 'th');
+ *     }
+ * }
+ * $('#calendar-me').renderCalendar({month:0, year:2007, renderCallback:testCallback});
+ *
+ * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me. Every Thursday in the current month has a class of "thursday" applied to it, is clickable and shows an alert when clicked. Every Friday on the calendar has the number inside replaced with text.
+ **/
+               renderCalendar  :   function(s)
+               {
+                       var dc = function(a)
+                       {
+                               return document.createElement(a);
+                       };
+
+                       s = $.extend(
+                               {
+                                       month                   : null,
+                                       year                    : null,
+                                       renderCallback  : null,
+                                       showHeader              : $.dpConst.SHOW_HEADER_SHORT,
+                                       dpController    : null,
+                                       hoverClass              : 'dp-hover'
+                               }
+                               , s
+                       );
+
+                       if (s.showHeader != $.dpConst.SHOW_HEADER_NONE) {
+                               var headRow = $(dc('tr'));
+                               for (var i=Date.firstDayOfWeek; i<Date.firstDayOfWeek+7; i++) {
+                                       var weekday = i%7;
+                                       var day = Date.dayNames[weekday];
+                                       headRow.append(
+                                               jQuery(dc('th')).attr({'scope':'col', 'abbr':day, 'title':day, 'class':(weekday == 0 || weekday == 6 ? 'weekend' : 'weekday')}).html(s.showHeader == $.dpConst.SHOW_HEADER_SHORT ? day.substr(0, 1) : day)
+                                       );
+                               }
+                       };
+
+                       var calendarTable = $(dc('table'))
+                                                                       .attr(
+                                                                               {
+                                                                                       'cellspacing':2,
+                                                                                       'className':'jCalendar'
+                                                                               }
+                                                                       )
+                                                                       .append(
+                                                                               (s.showHeader != $.dpConst.SHOW_HEADER_NONE ?
+                                                                                       $(dc('thead'))
+                                                                                               .append(headRow)
+                                                                                       :
+                                                                                       dc('thead')
+                                                                               )
+                                                                       );
+                       var tbody = $(dc('tbody'));
+
+                       var today = (new Date()).zeroTime();
+
+                       var month = s.month == undefined ? today.getMonth() : s.month;
+                       var year = s.year || today.getFullYear();
+
+                       var currentDate = new Date(year, month, 1);
+
+
+                       var firstDayOffset = Date.firstDayOfWeek - currentDate.getDay() + 1;
+                       if (firstDayOffset > 1) firstDayOffset -= 7;
+                       var weeksToDraw = Math.ceil(( (-1*firstDayOffset+1) + currentDate.getDaysInMonth() ) /7);
+                       currentDate.addDays(firstDayOffset-1);
+
+                       var doHover = function()
+                       {
+                               if (s.hoverClass) {
+                                       $(this).addClass(s.hoverClass);
+                               }
+                       };
+                       var unHover = function()
+                       {
+                               if (s.hoverClass) {
+                                       $(this).removeClass(s.hoverClass);
+                               }
+                       };
+
+                       var w = 0;
+                       while (w++<weeksToDraw) {
+                               var r = jQuery(dc('tr'));
+                               for (var i=0; i<7; i++) {
+                                       var thisMonth = currentDate.getMonth() == month;
+                                       var d = $(dc('td'))
+                                                               .text(currentDate.getDate() + '')
+                                                               .attr('className', (thisMonth ? 'current-month ' : 'other-month ') +
+                                                                                                       (currentDate.isWeekend() ? 'weekend ' : 'weekday ') +
+                                                                                                       (thisMonth && currentDate.getTime() == today.getTime() ? 'today ' : '')
+                                                               )
+                                                               .hover(doHover, unHover)
+                                                       ;
+                                       if (s.renderCallback) {
+                                               s.renderCallback(d, currentDate, month, year);
+                                       }
+                                       r.append(d);
+                                       currentDate.addDays(1);
+                               }
+                               tbody.append(r);
+                       }
+                       calendarTable.append(tbody);
+
+                       return this.each(
+                               function()
+                               {
+                                       $(this).empty().append(calendarTable);
+                               }
+                       );
+               },
+/**
+ * Create a datePicker associated with each of the matched elements.
+ *
+ * The matched element will receive a few custom events with the following signatures:
+ *
+ * dateSelected(event, date, $td, status)
+ * Triggered when a date is selected. event is a reference to the event, date is the Date selected, $td is a jquery object wrapped around the TD that was clicked on and status is whether the date was selected (true) or deselected (false)
+ *
+ * dpClosed(event, selected)
+ * Triggered when the date picker is closed. event is a reference to the event and selected is an Array containing Date objects.
+ *
+ * dpMonthChanged(event, displayedMonth, displayedYear)
+ * Triggered when the month of the popped up calendar is changed. event is a reference to the event, displayedMonth is the number of the month now displayed (zero based) and displayedYear is the year of the month.
+ *
+ * dpDisplayed(event, $datePickerDiv)
+ * Triggered when the date picker is created. $datePickerDiv is the div containing the date picker. Use this event to add custom content/ listeners to the popped up date picker.
+ *
+ * @param Object s (optional) Customize your date pickers.
+ * @option Number month The month to render when the date picker is opened (NOTE that months are zero based). Default is today's month.
+ * @option Number year The year to render when the date picker is opened. Default is today's year.
+ * @option String startDate The first date date can be selected.
+ * @option String endDate The last date that can be selected.
+ * @option Boolean inline Whether to create the datePicker as inline (e.g. always on the page) or as a model popup. Default is false (== modal popup)
+ * @option Boolean createButton Whether to create a .dp-choose-date anchor directly after the matched element which when clicked will trigger the showing of the date picker. Default is true.
+ * @option Boolean showYearNavigation Whether to display buttons which allow the user to navigate through the months a year at a time. Default is true.
+ * @option Boolean closeOnSelect Whether to close the date picker when a date is selected. Default is true.
+ * @option Boolean displayClose Whether to create a "Close" button within the date picker popup. Default is false.
+ * @option Boolean selectMultiple Whether a user should be able to select multiple dates with this date picker. Default is false.
+ * @option Boolean clickInput If the matched element is an input type="text" and this option is true then clicking on the input will cause the date picker to appear.
+ * @option Number verticalPosition The vertical alignment of the popped up date picker to the matched element. One of $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM. Default is $.dpConst.POS_TOP.
+ * @option Number horizontalPosition The horizontal alignment of the popped up date picker to the matched element. One of $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT.
+ * @option Number verticalOffset The number of pixels offset from the defined verticalPosition of this date picker that it should pop up in. Default in 0.
+ * @option Number horizontalOffset The number of pixels offset from the defined horizontalPosition of this date picker that it should pop up in. Default in 0.
+ * @option (Function|Array) renderCallback A reference to a function (or an array of separate functions) that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Each callback function will receive four arguments; a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year. Default is no callback.
+ * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
+ * @type jQuery
+ * @name datePicker
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('input.date-picker').datePicker();
+ * @desc Creates a date picker button next to all matched input elements. When the button is clicked on the value of the selected date will be placed in the corresponding input (formatted according to Date.format).
+ *
+ * @example demo/index.html
+ * @desc See the projects homepage for many more complex examples...
+ **/
+               datePicker : function(s)
+               {
+                       if (!$.event._dpCache) $.event._dpCache = [];
+
+                       // initialise the date picker controller with the relevant settings...
+                       s = $.extend(
+                               {
+                                       month                           : undefined,
+                                       year                            : undefined,
+                                       startDate                       : undefined,
+                                       endDate                         : undefined,
+                                       inline                          : false,
+                                       renderCallback          : [],
+                                       createButton            : true,
+                                       showYearNavigation      : true,
+                                       closeOnSelect           : true,
+                                       displayClose            : false,
+                                       selectMultiple          : false,
+                                       clickInput                      : false,
+                                       verticalPosition        : $.dpConst.POS_TOP,
+                                       horizontalPosition      : $.dpConst.POS_LEFT,
+                                       verticalOffset          : 0,
+                                       horizontalOffset        : 0,
+                                       hoverClass                      : 'dp-hover'
+                               }
+                               , s
+                       );
+
+                       return this.each(
+                               function()
+                               {
+                                       var $this = $(this);
+                                       var alreadyExists = true;
+
+                                       if (!this._dpId) {
+                                               this._dpId = $.event.guid++;
+                                               $.event._dpCache[this._dpId] = new DatePicker(this);
+                                               alreadyExists = false;
+                                       }
+
+                                       if (s.inline) {
+                                               s.createButton = false;
+                                               s.displayClose = false;
+                                               s.closeOnSelect = false;
+                                               $this.empty();
+                                       }
+
+                                       var controller = $.event._dpCache[this._dpId];
+
+                                       controller.init(s);
+
+                                       if (!alreadyExists && s.createButton) {
+                                               // create it!
+                                               controller.button = $('<a href="#" class="dp-choose-date" title="' + $.dpText.TEXT_CHOOSE_DATE + '">' + $.dpText.TEXT_CHOOSE_DATE + '</a>')
+                                                               .bind(
+                                                                       'click',
+                                                                       function()
+                                                                       {
+                                                                               $this.dpDisplay(this);
+                                                                               this.blur();
+                                                                               return false;
+                                                                       }
+                                                               );
+                                               $this.after(controller.button);
+                                       }
+
+                                       if (!alreadyExists && $this.is(':text')) {
+                                               $this
+                                                       .bind(
+                                                               'dateSelected',
+                                                               function(e, selectedDate, $td)
+                                                               {
+                                                                       this.value = selectedDate.asString();
+                                                               }
+                                                       ).bind(
+                                                               'change',
+                                                               function()
+                                                               {
+                                                                       var d = Date.fromString(this.value);
+                                                                       if (d) {
+                                                                               controller.setSelected(d, true, true);
+                                                                       }
+                                                               }
+                                                       );
+                                               if (s.clickInput) {
+                                                       $this.bind(
+                                                               'click',
+                                                               function()
+                                                               {
+                                                                       $this.dpDisplay();
+                                                               }
+                                                       );
+                                               }
+                                               var d = Date.fromString(this.value);
+                                               if (this.value != '' && d) {
+                                                       controller.setSelected(d, true, true);
+                                               }
+                                       }
+
+                                       $this.addClass('dp-applied');
+
+                               }
+                       )
+               },
+/**
+ * Disables or enables this date picker
+ *
+ * @param Boolean s Whether to disable (true) or enable (false) this datePicker
+ * @type jQuery
+ * @name dpSetDisabled
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-picker').datePicker();
+ * $('.date-picker').dpSetDisabled(true);
+ * @desc Prevents this date picker from displaying and adds a class of dp-disabled to it (and it's associated button if it has one) for styling purposes. If the matched element is an input field then it will also set the disabled attribute to stop people directly editing the field.
+ **/
+               dpSetDisabled : function(s)
+               {
+                       return _w.call(this, 'setDisabled', s);
+               },
+/**
+ * Updates the first selectable date for any date pickers on any matched elements.
+ *
+ * @param String d A string representing the first selectable date (formatted according to Date.format).
+ * @type jQuery
+ * @name dpSetStartDate
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-picker').datePicker();
+ * $('.date-picker').dpSetStartDate('01/01/2000');
+ * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the first selectable date for each of these to the first day of the millenium.
+ **/
+               dpSetStartDate : function(d)
+               {
+                       return _w.call(this, 'setStartDate', d);
+               },
+/**
+ * Updates the last selectable date for any date pickers on any matched elements.
+ *
+ * @param String d A string representing the last selectable date (formatted according to Date.format).
+ * @type jQuery
+ * @name dpSetEndDate
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-picker').datePicker();
+ * $('.date-picker').dpSetEndDate('01/01/2010');
+ * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the last selectable date for each of these to the first Janurary 2010.
+ **/
+               dpSetEndDate : function(d)
+               {
+                       return _w.call(this, 'setEndDate', d);
+               },
+/**
+ * Gets a list of Dates currently selected by this datePicker. This will be an empty array if no dates are currently selected or NULL if there is no datePicker associated with the matched element.
+ *
+ * @type Array
+ * @name dpGetSelected
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-picker').datePicker();
+ * alert($('.date-picker').dpGetSelected());
+ * @desc Will alert an empty array (as nothing is selected yet)
+ **/
+               dpGetSelected : function()
+               {
+                       var c = _getController(this[0]);
+                       if (c) {
+                               return c.getSelected();
+                       }
+                       return null;
+               },
+/**
+ * Selects or deselects a date on any matched element's date pickers. Deselcting is only useful on date pickers where selectMultiple==true. Selecting will only work if the passed date is within the startDate and endDate boundries for a given date picker.
+ *
+ * @param String d A string representing the date you want to select (formatted according to Date.format).
+ * @param Boolean v Whether you want to select (true) or deselect (false) this date. Optional - default = true.
+ * @param Boolean m Whether you want the date picker to open up on the month of this date when it is next opened. Optional - default = true.
+ * @type jQuery
+ * @name dpSetSelected
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-picker').datePicker();
+ * $('.date-picker').dpSetSelected('01/01/2010');
+ * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
+ **/
+               dpSetSelected : function(d, v, m)
+               {
+                       if (v == undefined) v=true;
+                       if (m == undefined) m=true;
+                       return _w.call(this, 'setSelected', Date.fromString(d), v, m);
+               },
+/**
+ * Sets the month that will be displayed when the date picker is next opened. If the passed month is before startDate then the month containing startDate will be displayed instead. If the passed month is after endDate then the month containing the endDate will be displayed instead.
+ *
+ * @param Number m The month you want the date picker to display. Optional - defaults to the currently displayed month.
+ * @param Number y The year you want the date picker to display. Optional - defaults to the currently displayed year.
+ * @type jQuery
+ * @name dpSetDisplayedMonth
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-picker').datePicker();
+ * $('.date-picker').dpSetDisplayedMonth(10, 2008);
+ * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
+ **/
+               dpSetDisplayedMonth : function(m, y)
+               {
+                       return _w.call(this, 'setDisplayedMonth', Number(m), Number(y));
+               },
+/**
+ * Displays the date picker associated with the matched elements. Since only one date picker can be displayed at once then the date picker associated with the last matched element will be the one that is displayed.
+ *
+ * @param HTMLElement e An element that you want the date picker to pop up relative in position to. Optional - default behaviour is to pop up next to the element associated with this date picker.
+ * @type jQuery
+ * @name dpDisplay
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('#date-picker').datePicker();
+ * $('#date-picker').dpDisplay();
+ * @desc Creates a date picker associated with the element with an id of date-picker and then causes it to pop up.
+ **/
+               dpDisplay : function(e)
+               {
+                       return _w.call(this, 'display', e);
+               },
+/**
+ * Sets a function or array of functions that is called when each TD of the date picker popup is rendered to the page
+ *
+ * @param (Function|Array) a A function or an array of functions that are called when each td is rendered. Each function will receive four arguments; a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year.
+ * @type jQuery
+ * @name dpSetRenderCallback
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('#date-picker').datePicker();
+ * $('#date-picker').dpSetRenderCallback(function($td, thisDate, month, year)
+ * {
+ *     // do stuff as each td is rendered dependant on the date in the td and the displayed month and year
+ * });
+ * @desc Creates a date picker associated with the element with an id of date-picker and then creates a function which is called as each td is rendered when this date picker is displayed.
+ **/
+               dpSetRenderCallback : function(a)
+               {
+                       return _w.call(this, 'setRenderCallback', a);
+               },
+/**
+ * Sets the position that the datePicker will pop up (relative to it's associated element)
+ *
+ * @param Number v The vertical alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM
+ * @param Number h The horizontal alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT
+ * @type jQuery
+ * @name dpSetPosition
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('#date-picker').datePicker();
+ * $('#date-picker').dpSetPosition($.dpConst.POS_BOTTOM, $.dpConst.POS_RIGHT);
+ * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be bottom and right aligned to the #date-picker element.
+ **/
+               dpSetPosition : function(v, h)
+               {
+                       return _w.call(this, 'setPosition', v, h);
+               },
+/**
+ * Sets the offset that the popped up date picker will have from it's default position relative to it's associated element (as set by dpSetPosition)
+ *
+ * @param Number v The vertical offset of the created date picker.
+ * @param Number h The horizontal offset of the created date picker.
+ * @type jQuery
+ * @name dpSetOffset
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('#date-picker').datePicker();
+ * $('#date-picker').dpSetOffset(-20, 200);
+ * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be 20 pixels above and 200 pixels to the right of it's default position.
+ **/
+               dpSetOffset : function(v, h)
+               {
+                       return _w.call(this, 'setOffset', v, h);
+               },
+/**
+ * Closes the open date picker associated with this element.
+ *
+ * @type jQuery
+ * @name dpClose
+ * @cat plugins/datePicker
+ * @author Kelvin Luck (http://www.kelvinluck.com/)
+ *
+ * @example $('.date-pick')
+ *             .datePicker()
+ *             .bind(
+ *                     'focus',
+ *                     function()
+ *                     {
+ *                             $(this).dpDisplay();
+ *                     }
+ *             ).bind(
+ *                     'blur',
+ *                     function()
+ *                     {
+ *                             $(this).dpClose();
+ *                     }
+ *             );
+ * @desc Creates a date picker and makes it appear when the relevant element is focused and disappear when it is blurred.
+ **/
+               dpClose : function()
+               {
+                       return _w.call(this, '_closeCalendar', false, this[0]);
+               },
+               // private function called on unload to clean up any expandos etc and prevent memory links...
+               _dpDestroy : function()
+               {
+                       // TODO - implement this?
+               }
+       });
+
+       // private internal function to cut down on the amount of code needed where we forward
+       // dp* methods on the jQuery object on to the relevant DatePicker controllers...
+       var _w = function(f, a1, a2, a3)
+       {
+               return this.each(
+                       function()
+                       {
+                               var c = _getController(this);
+                               if (c) {
+                                       c[f](a1, a2, a3);
+                               }
+                       }
+               );
+       };
+
+       function DatePicker(ele)
+       {
+               this.ele = ele;
+
+               // initial values...
+               this.displayedMonth             =       null;
+               this.displayedYear              =       null;
+               this.startDate                  =       null;
+               this.endDate                    =       null;
+               this.showYearNavigation =       null;
+               this.closeOnSelect              =       null;
+               this.displayClose               =       null;
+               this.selectMultiple             =       null;
+               this.verticalPosition   =       null;
+               this.horizontalPosition =       null;
+               this.verticalOffset             =       null;
+               this.horizontalOffset   =       null;
+               this.button                             =       null;
+               this.renderCallback             =       [];
+               this.selectedDates              =       {};
+               this.inline                             =       null;
+               this.context                    =       '#dp-popup';
+       };
+       $.extend(
+               DatePicker.prototype,
+               {
+                       init : function(s)
+                       {
+                               this.setStartDate(s.startDate);
+                               this.setEndDate(s.endDate);
+                               this.setDisplayedMonth(Number(s.month), Number(s.year));
+                               this.setRenderCallback(s.renderCallback);
+                               this.showYearNavigation = s.showYearNavigation;
+                               this.closeOnSelect = s.closeOnSelect;
+                               this.displayClose = s.displayClose;
+                               this.selectMultiple = s.selectMultiple;
+                               this.verticalPosition = s.verticalPosition;
+                               this.horizontalPosition = s.horizontalPosition;
+                               this.hoverClass = s.hoverClass;
+                               this.setOffset(s.verticalOffset, s.horizontalOffset);
+                               this.inline = s.inline;
+                               if (this.inline) {
+                                       this.context = this.ele;
+                                       this.display();
+                               }
+                       },
+                       setStartDate : function(d)
+                       {
+                               if (d) {
+                                       this.startDate = Date.fromString(d);
+                               }
+                               if (!this.startDate) {
+                                       this.startDate = (new Date()).zeroTime();
+                               }
+                               this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
+                       },
+                       setEndDate : function(d)
+                       {
+                               if (d) {
+                                       this.endDate = Date.fromString(d);
+                               }
+                               if (!this.endDate) {
+                                       this.endDate = (new Date('12/31/2999')); // using the JS Date.parse function which expects mm/dd/yyyy
+                               }
+                               if (this.endDate.getTime() < this.startDate.getTime()) {
+                                       this.endDate = this.startDate;
+                               }
+                               this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
+                       },
+                       setPosition : function(v, h)
+                       {
+                               this.verticalPosition = v;
+                               this.horizontalPosition = h;
+                       },
+                       setOffset : function(v, h)
+                       {
+                               this.verticalOffset = parseInt(v) || 0;
+                               this.horizontalOffset = parseInt(h) || 0;
+                       },
+                       setDisabled : function(s)
+                       {
+                               $e = $(this.ele);
+                               $e[s ? 'addClass' : 'removeClass']('dp-disabled');
+                               if (this.button) {
+                                       $but = $(this.button);
+                                       $but[s ? 'addClass' : 'removeClass']('dp-disabled');
+                                       $but.attr('title', s ? '' : $.dpText.TEXT_CHOOSE_DATE);
+                               }
+                               if ($e.is(':text')) {
+                                       $e.attr('disabled', s ? 'disabled' : '');
+                               }
+                       },
+                       setDisplayedMonth : function(m, y)
+                       {
+                               if (this.startDate == undefined || this.endDate == undefined) {
+                                       return;
+                               }
+                               var s = new Date(this.startDate.getTime());
+                               s.setDate(1);
+                               var e = new Date(this.endDate.getTime());
+                               e.setDate(1);
+
+                               var t;
+                               if ((!m && !y) || (isNaN(m) && isNaN(y))) {
+                                       // no month or year passed - default to current month
+                                       t = new Date().zeroTime();
+                                       t.setDate(1);
+                               } else if (isNaN(m)) {
+                                       // just year passed in - presume we want the displayedMonth
+                                       t = new Date(y, this.displayedMonth, 1);
+                               } else if (isNaN(y)) {
+                                       // just month passed in - presume we want the displayedYear
+                                       t = new Date(this.displayedYear, m, 1);
+                               } else {
+                                       // year and month passed in - that's the date we want!
+                                       t = new Date(y, m, 1)
+                               }
+
+                               // check if the desired date is within the range of our defined startDate and endDate
+                               if (t.getTime() < s.getTime()) {
+                                       t = s;
+                               } else if (t.getTime() > e.getTime()) {
+                                       t = e;
+                               }
+                               this.displayedMonth = t.getMonth();
+                               this.displayedYear = t.getFullYear();
+                       },
+                       setSelected : function(d, v, moveToMonth)
+                       {
+                               if (this.selectMultiple == false) {
+                                       this.selectedDates = {};
+                                       $('td.selected', this.context).removeClass('selected');
+                               }
+                               if (moveToMonth) {
+                                       this.setDisplayedMonth(d.getMonth(), d.getFullYear());
+                               }
+                               this.selectedDates[d.toString()] = v;
+                       },
+                       isSelected : function(d)
+                       {
+                               return this.selectedDates[d.toString()];
+                       },
+                       getSelected : function()
+                       {
+                               var r = [];
+                               for(s in this.selectedDates) {
+                                       if (this.selectedDates[s] == true) {
+                                               r.push(Date.parse(s));
+                                       }
+                               }
+                               return r;
+                       },
+                       display : function(eleAlignTo)
+                       {
+                               if ($(this.ele).is('.dp-disabled')) return;
+
+                               eleAlignTo = eleAlignTo || this.ele;
+                               var c = this;
+                               var $ele = $(eleAlignTo);
+                               var eleOffset = $ele.offset();
+
+                               var $createIn;
+                               var attrs;
+                               var attrsCalendarHolder;
+                               var cssRules;
+
+                               if (c.inline) {
+                                       $createIn = $(this.ele);
+                                       attrs = {
+                                               'id'            :       'calendar-' + this.ele._dpId,
+                                               'className'     :       'dp-popup dp-popup-inline'
+                                       };
+                                       cssRules = {
+                                       };
+                               } else {
+                                       $createIn = $('body');
+                                       attrs = {
+                                               'id'            :       'dp-popup',
+                                               'className'     :       'dp-popup'
+                                       };
+                                       cssRules = {
+                                               'top'   :       eleOffset.top + c.verticalOffset,
+                                               'left'  :       eleOffset.left + c.horizontalOffset
+                                       };
+
+                                       var _checkMouse = function(e)
+                                       {
+                                               var el = e.target;
+                                               var cal = $('#dp-popup')[0];
+
+                                               while (true){
+                                                       if (el == cal) {
+                                                               return true;
+                                                       } else if (el == document) {
+                                                               c._closeCalendar();
+                                                               return false;
+                                                       } else {
+                                                               el = $(el).parent()[0];
+                                                       }
+                                               }
+                                       };
+                                       this._checkMouse = _checkMouse;
+
+                                       this._closeCalendar(true);
+                               }
+
+
+                               $createIn
+                                       .append(
+                                               $('<div></div>')
+                                                       .attr(attrs)
+                                                       .css(cssRules)
+                                                       .append(
+                                                               $('<h2></h2>'),
+                                                               $('<div class="dp-nav-prev"></div>')
+                                                                       .append(
+                                                                               $('<a class="dp-nav-prev-year" href="#" title="' + $.dpText.TEXT_PREV_YEAR + '">&lt;&lt;</a>')
+                                                                                       .bind(
+                                                                                               'click',
+                                                                                               function()
+                                                                                               {
+                                                                                                       return c._displayNewMonth.call(c, this, 0, -1);
+                                                                                               }
+                                                                                       ),
+                                                                               $('<a class="dp-nav-prev-month" href="#" title="' + $.dpText.TEXT_PREV_MONTH + '">&lt;</a>')
+                                                                                       .bind(
+                                                                                               'click',
+                                                                                               function()
+                                                                                               {
+                                                                                                       return c._displayNewMonth.call(c, this, -1, 0);
+                                                                                               }
+                                                                                       )
+                                                                       ),
+                                                               $('<div class="dp-nav-next"></div>')
+                                                                       .append(
+                                                                               $('<a class="dp-nav-next-year" href="#" title="' + $.dpText.TEXT_NEXT_YEAR + '">&gt;&gt;</a>')
+                                                                                       .bind(
+                                                                                               'click',
+                                                                                               function()
+                                                                                               {
+                                                                                                       return c._displayNewMonth.call(c, this, 0, 1);
+                                                                                               }
+                                                                                       ),
+                                                                               $('<a class="dp-nav-next-month" href="#" title="' + $.dpText.TEXT_NEXT_MONTH + '">&gt;</a>')
+                                                                                       .bind(
+                                                                                               'click',
+                                                                                               function()
+                                                                                               {
+                                                                                                       return c._displayNewMonth.call(c, this, 1, 0);
+                                                                                               }
+                                                                                       )
+                                                                       ),
+                                                               $('<div></div>')
+                                                                       .attr('className', 'dp-calendar')
+                                                       )
+                                                       .bgIframe()
+                                               );
+
+                               var $pop = this.inline ? $('.dp-popup', this.context) : $('#dp-popup');
+
+                               if (this.showYearNavigation == false) {
+                                       $('.dp-nav-prev-year, .dp-nav-next-year', c.context).css('display', 'none');
+                               }
+                               if (this.displayClose) {
+                                       $pop.append(
+                                               $('<a href="#" id="dp-close">' + $.dpText.TEXT_CLOSE + '</a>')
+                                                       .bind(
+                                                               'click',
+                                                               function()
+                                                               {
+                                                                       c._closeCalendar();
+                                                                       return false;
+                                                               }
+                                                       )
+                                       );
+                               }
+                               c._renderCalendar();
+
+                               $(this.ele).trigger('dpDisplayed', $pop);
+
+                               if (!c.inline) {
+                                       if (this.verticalPosition == $.dpConst.POS_BOTTOM) {
+                                               $pop.css('top', eleOffset.top + $ele.height() - $pop.height() + c.verticalOffset);
+                                       }
+                                       if (this.horizontalPosition == $.dpConst.POS_RIGHT) {
+                                               $pop.css('left', eleOffset.left + $ele.width() - $pop.width() + c.horizontalOffset);
+                                       }
+                                       $(document).bind('mousedown', this._checkMouse);
+                               }
+                       },
+                       setRenderCallback : function(a)
+                       {
+                               if (a && typeof(a) == 'function') {
+                                       a = [a];
+                               }
+                               this.renderCallback = this.renderCallback.concat(a);
+                       },
+                       cellRender : function ($td, thisDate, month, year) {
+                               var c = this.dpController;
+                               var d = new Date(thisDate.getTime());
+
+                               // add our click handlers to deal with it when the days are clicked...
+
+                               $td.bind(
+                                       'click',
+                                       function()
+                                       {
+                                               var $this = $(this);
+                                               if (!$this.is('.disabled')) {
+                                                       c.setSelected(d, !$this.is('.selected') || !c.selectMultiple);
+                                                       var s = c.isSelected(d);
+                                                       $(c.ele).trigger('dateSelected', [d, $td, s]);
+                                                       $(c.ele).trigger('change');
+                                                       if (c.closeOnSelect) {
+                                                               c._closeCalendar();
+                                                       } else {
+                                                               $this[s ? 'addClass' : 'removeClass']('selected');
+                                                       }
+                                               }
+                                       }
+                               );
+
+                               if (c.isSelected(d)) {
+                                       $td.addClass('selected');
+                               }
+
+                               // call any extra renderCallbacks that were passed in
+                               for (var i=0; i<c.renderCallback.length; i++) {
+                                       c.renderCallback[i].apply(this, arguments);
+                               }
+
+
+                       },
+                       // ele is the clicked button - only proceed if it doesn't have the class disabled...
+                       // m and y are -1, 0 or 1 depending which direction we want to go in...
+                       _displayNewMonth : function(ele, m, y)
+                       {
+                               if (!$(ele).is('.disabled')) {
+                                       this.setDisplayedMonth(this.displayedMonth + m, this.displayedYear + y);
+                                       this._clearCalendar();
+                                       this._renderCalendar();
+                                       $(this.ele).trigger('dpMonthChanged', [this.displayedMonth, this.displayedYear]);
+                               }
+                               ele.blur();
+                               return false;
+                       },
+                       _renderCalendar : function()
+                       {
+                               // set the title...
+                               $('h2', this.context).html(Date.monthNames[this.displayedMonth] + ' ' + this.displayedYear);
+
+                               // render the calendar...
+                               $('.dp-calendar', this.context).renderCalendar(
+                                       {
+                                               month                   : this.displayedMonth,
+                                               year                    : this.displayedYear,
+                                               renderCallback  : this.cellRender,
+                                               dpController    : this,
+                                               hoverClass              : this.hoverClass
+                                       }
+                               );
+
+                               // update the status of the control buttons and disable dates before startDate or after endDate...
+                               // TODO: When should the year buttons be disabled? When you can't go forward a whole year from where you are or is that annoying?
+                               if (this.displayedYear == this.startDate.getFullYear() && this.displayedMonth == this.startDate.getMonth()) {
+                                       $('.dp-nav-prev-year', this.context).addClass('disabled');
+                                       $('.dp-nav-prev-month', this.context).addClass('disabled');
+                                       $('.dp-calendar td.other-month', this.context).each(
+                                               function()
+                                               {
+                                                       var $this = $(this);
+                                                       if (Number($this.text()) > 20) {
+                                                               $this.addClass('disabled');
+                                                       }
+                                               }
+                                       );
+                                       var d = this.startDate.getDate();
+                                       $('.dp-calendar td.current-month', this.context).each(
+                                               function()
+                                               {
+                                                       var $this = $(this);
+                                                       if (Number($this.text()) < d) {
+                                                               $this.addClass('disabled');
+                                                       }
+                                               }
+                                       );
+                               } else {
+                                       $('.dp-nav-prev-year', this.context).removeClass('disabled');
+                                       $('.dp-nav-prev-month', this.context).removeClass('disabled');
+                                       var d = this.startDate.getDate();
+                                       if (d > 20) {
+                                               // check if the startDate is last month as we might need to add some disabled classes...
+                                               var sd = new Date(this.startDate.getTime());
+                                               sd.addMonths(1);
+                                               if (this.displayedYear == sd.getFullYear() && this.displayedMonth == sd.getMonth()) {
+                                                       $('dp-calendar td.other-month', this.context).each(
+                                                               function()
+                                                               {
+                                                                       var $this = $(this);
+                                                                       if (Number($this.text()) < d) {
+                                                                               $this.addClass('disabled');
+                                                                       }
+                                                               }
+                                                       );
+                                               }
+                                       }
+                               }
+                               if (this.displayedYear == this.endDate.getFullYear() && this.displayedMonth == this.endDate.getMonth()) {
+                                       $('.dp-nav-next-year', this.context).addClass('disabled');
+                                       $('.dp-nav-next-month', this.context).addClass('disabled');
+                                       $('.dp-calendar td.other-month', this.context).each(
+                                               function()
+                                               {
+                                                       var $this = $(this);
+                                                       if (Number($this.text()) < 14) {
+                                                               $this.addClass('disabled');
+                                                       }
+                                               }
+                                       );
+                                       var d = this.endDate.getDate();
+                                       $('.dp-calendar td.current-month', this.context).each(
+                                               function()
+                                               {
+                                                       var $this = $(this);
+                                                       if (Number($this.text()) > d) {
+                                                               $this.addClass('disabled');
+                                                       }
+                                               }
+                                       );
+                               } else {
+                                       $('.dp-nav-next-year', this.context).removeClass('disabled');
+                                       $('.dp-nav-next-month', this.context).removeClass('disabled');
+                                       var d = this.endDate.getDate();
+                                       if (d < 13) {
+                                               // check if the endDate is next month as we might need to add some disabled classes...
+                                               var ed = new Date(this.endDate.getTime());
+                                               ed.addMonths(-1);
+                                               if (this.displayedYear == ed.getFullYear() && this.displayedMonth == ed.getMonth()) {
+                                                       $('.dp-calendar td.other-month', this.context).each(
+                                                               function()
+                                                               {
+                                                                       var $this = $(this);
+                                                                       if (Number($this.text()) > d) {
+                                                                               $this.addClass('disabled');
+                                                                       }
+                                                               }
+                                                       );
+                                               }
+                                       }
+                               }
+                       },
+                       _closeCalendar : function(programatic, ele)
+                       {
+                               if (!ele || ele == this.ele)
+                               {
+                                       $(document).unbind('mousedown', this._checkMouse);
+                                       this._clearCalendar();
+                                       $('#dp-popup a').unbind();
+                                       $('#dp-popup').empty().remove();
+                                       if (!programatic) {
+                                               $(this.ele).trigger('dpClosed', [this.getSelected()]);
+                                       }
+                               }
+                       },
+                       // empties the current dp-calendar div and makes sure that all events are unbound
+                       // and expandos removed to avoid memory leaks...
+                       _clearCalendar : function()
+                       {
+                               // TODO.
+                               $('.dp-calendar td', this.context).unbind();
+                               $('.dp-calendar', this.context).empty();
+                       }
+               }
+       );
+
+       // static constants
+       $.dpConst = {
+               SHOW_HEADER_NONE        :       0,
+               SHOW_HEADER_SHORT       :       1,
+               SHOW_HEADER_LONG        :       2,
+               POS_TOP                         :       0,
+               POS_BOTTOM                      :       1,
+               POS_LEFT                        :       0,
+               POS_RIGHT                       :       1
+       };
+       // localisable text
+       $.dpText = {
+               TEXT_PREV_YEAR          :       'Previous year',
+               TEXT_PREV_MONTH         :       'Previous month',
+               TEXT_NEXT_YEAR          :       'Next year',
+               TEXT_NEXT_MONTH         :       'Next month',
+               TEXT_CLOSE                      :       'Close',
+               TEXT_CHOOSE_DATE        :       'Choose date'
+       };
+       // version
+       $.dpVersion = '$Id: jquery.datePicker.js 3739 2007-10-25 13:55:30Z kelvin.luck $';
+
+       function _getController(ele)
+       {
+               if (ele._dpId) return $.event._dpCache[ele._dpId];
+               return false;
+       };
+
+       // make it so that no error is thrown if bgIframe plugin isn't included (allows you to use conditional
+       // comments to only include bgIframe where it is needed in IE without breaking this plugin).
+       if ($.fn.bgIframe == undefined) {
+               $.fn.bgIframe = function() {return this; };
+       };
+
+
+       // clean-up
+       $(window)
+               .bind('unload', function() {
+                       var els = $.event._dpCache || [];
+                       for (var i in els) {
+                               $(els[i].ele)._dpDestroy();
+                       }
+               });
+
+
+})(jQuery);
+
+
+/*
+ * Date prototype extensions. Doesn't depend on any
+ * other code. Doens't overwrite existing methods.
+ *
+ * Adds dayNames, abbrDayNames, monthNames and abbrMonthNames static properties and isLeapYear,
+ * isWeekend, isWeekDay, getDaysInMonth, getDayName, getMonthName, getDayOfYear, getWeekOfYear,
+ * setDayOfYear, addYears, addMonths, addDays, addHours, addMinutes, addSeconds methods
+ *
+ * Copyright (c) 2006 Jörn Zaefferer and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ *
+ * Additional methods and properties added by Kelvin Luck: firstDayOfWeek, dateFormat, zeroTime, asString, fromString -
+ * I've added my name to these methods so you know who to blame if they are broken!
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+/**
+ * An Array of day names starting with Sunday.
+ *
+ * @example dayNames[0]
+ * @result 'Sunday'
+ *
+ * @name dayNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+
+/**
+ * An Array of abbreviated day names starting with Sun.
+ *
+ * @example abbrDayNames[0]
+ * @result 'Sun'
+ *
+ * @name abbrDayNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.abbrDayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+
+/**
+ * An Array of month names starting with Janurary.
+ *
+ * @example monthNames[0]
+ * @result 'January'
+ *
+ * @name monthNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+
+/**
+ * An Array of abbreviated month names starting with Jan.
+ *
+ * @example abbrMonthNames[0]
+ * @result 'Jan'
+ *
+ * @name monthNames
+ * @type Array
+ * @cat Plugins/Methods/Date
+ */
+Date.abbrMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+/**
+ * The first day of the week for this locale.
+ *
+ * @name firstDayOfWeek
+ * @type Number
+ * @cat Plugins/Methods/Date
+ * @author Kelvin Luck
+ */
+Date.firstDayOfWeek = 1;
+
+/**
+ * The format that string dates should be represented as (e.g. 'dd/mm/yyyy' for UK, 'mm/dd/yyyy' for US, 'yyyy-mm-dd' for Unicode etc).
+ *
+ * @name format
+ * @type String
+ * @cat Plugins/Methods/Date
+ * @author Kelvin Luck
+ */
+Date.format = 'dd/mm/yyyy';
+//Date.format = 'mm/dd/yyyy';
+//Date.format = 'yyyy-mm-dd';
+//Date.format = 'dd mmm yy';
+
+/**
+ * The first two numbers in the century to be used when decoding a two digit year. Since a two digit year is ambiguous (and date.setYear
+ * only works with numbers < 99 and so doesn't allow you to set years after 2000) we need to use this to disambiguate the two digit year codes.
+ *
+ * @name format
+ * @type String
+ * @cat Plugins/Methods/Date
+ * @author Kelvin Luck
+ */
+Date.fullYearStart = '20';
+
+(function() {
+
+       /**
+        * Adds a given method under the given name
+        * to the Date prototype if it doesn't
+        * currently exist.
+        *
+        * @private
+        */
+       function add(name, method) {
+               if( !Date.prototype[name] ) {
+                       Date.prototype[name] = method;
+               }
+       };
+
+       /**
+        * Checks if the year is a leap year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.isLeapYear();
+        * @result true
+        *
+        * @name isLeapYear
+        * @type Boolean
+        * @cat Plugins/Methods/Date
+        */
+       add("isLeapYear", function() {
+               var y = this.getFullYear();
+               return (y%4==0 && y%100!=0) || y%400==0;
+       });
+
+       /**
+        * Checks if the day is a weekend day (Sat or Sun).
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.isWeekend();
+        * @result false
+        *
+        * @name isWeekend
+        * @type Boolean
+        * @cat Plugins/Methods/Date
+        */
+       add("isWeekend", function() {
+               return this.getDay()==0 || this.getDay()==6;
+       });
+
+       /**
+        * Check if the day is a day of the week (Mon-Fri)
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.isWeekDay();
+        * @result false
+        *
+        * @name isWeekDay
+        * @type Boolean
+        * @cat Plugins/Methods/Date
+        */
+       add("isWeekDay", function() {
+               return !this.isWeekend();
+       });
+
+       /**
+        * Gets the number of days in the month.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDaysInMonth();
+        * @result 31
+        *
+        * @name getDaysInMonth
+        * @type Number
+        * @cat Plugins/Methods/Date
+        */
+       add("getDaysInMonth", function() {
+               return [31,(this.isLeapYear() ? 29:28),31,30,31,30,31,31,30,31,30,31][this.getMonth()];
+       });
+
+       /**
+        * Gets the name of the day.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDayName();
+        * @result 'Saturday'
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDayName(true);
+        * @result 'Sat'
+        *
+        * @param abbreviated Boolean When set to true the name will be abbreviated.
+        * @name getDayName
+        * @type String
+        * @cat Plugins/Methods/Date
+        */
+       add("getDayName", function(abbreviated) {
+               return abbreviated ? Date.abbrDayNames[this.getDay()] : Date.dayNames[this.getDay()];
+       });
+
+       /**
+        * Gets the name of the month.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getMonthName();
+        * @result 'Janurary'
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getMonthName(true);
+        * @result 'Jan'
+        *
+        * @param abbreviated Boolean When set to true the name will be abbreviated.
+        * @name getDayName
+        * @type String
+        * @cat Plugins/Methods/Date
+        */
+       add("getMonthName", function(abbreviated) {
+               return abbreviated ? Date.abbrMonthNames[this.getMonth()] : Date.monthNames[this.getMonth()];
+       });
+
+       /**
+        * Get the number of the day of the year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getDayOfYear();
+        * @result 11
+        *
+        * @name getDayOfYear
+        * @type Number
+        * @cat Plugins/Methods/Date
+        */
+       add("getDayOfYear", function() {
+               var tmpdtm = new Date("1/1/" + this.getFullYear());
+               return Math.floor((this.getTime() - tmpdtm.getTime()) / 86400000);
+       });
+
+       /**
+        * Get the number of the week of the year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.getWeekOfYear();
+        * @result 2
+        *
+        * @name getWeekOfYear
+        * @type Number
+        * @cat Plugins/Methods/Date
+        */
+       add("getWeekOfYear", function() {
+               return Math.ceil(this.getDayOfYear() / 7);
+       });
+
+       /**
+        * Set the day of the year.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.setDayOfYear(1);
+        * dtm.toString();
+        * @result 'Tue Jan 01 2008 00:00:00'
+        *
+        * @name setDayOfYear
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("setDayOfYear", function(day) {
+               this.setMonth(0);
+               this.setDate(day);
+               return this;
+       });
+
+       /**
+        * Add a number of years to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addYears(1);
+        * dtm.toString();
+        * @result 'Mon Jan 12 2009 00:00:00'
+        *
+        * @name addYears
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addYears", function(num) {
+               this.setFullYear(this.getFullYear() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of months to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addMonths(1);
+        * dtm.toString();
+        * @result 'Tue Feb 12 2008 00:00:00'
+        *
+        * @name addMonths
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addMonths", function(num) {
+               var tmpdtm = this.getDate();
+
+               this.setMonth(this.getMonth() + num);
+
+               if (tmpdtm > this.getDate())
+                       this.addDays(-this.getDate());
+
+               return this;
+       });
+
+       /**
+        * Add a number of days to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addDays(1);
+        * dtm.toString();
+        * @result 'Sun Jan 13 2008 00:00:00'
+        *
+        * @name addDays
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addDays", function(num) {
+               this.setDate(this.getDate() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of hours to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addHours(24);
+        * dtm.toString();
+        * @result 'Sun Jan 13 2008 00:00:00'
+        *
+        * @name addHours
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addHours", function(num) {
+               this.setHours(this.getHours() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of minutes to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addMinutes(60);
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 01:00:00'
+        *
+        * @name addMinutes
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addMinutes", function(num) {
+               this.setMinutes(this.getMinutes() + num);
+               return this;
+       });
+
+       /**
+        * Add a number of seconds to the date object.
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.addSeconds(60);
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 00:01:00'
+        *
+        * @name addSeconds
+        * @type Date
+        * @cat Plugins/Methods/Date
+        */
+       add("addSeconds", function(num) {
+               this.setSeconds(this.getSeconds() + num);
+               return this;
+       });
+
+       /**
+        * Sets the time component of this Date to zero for cleaner, easier comparison of dates where time is not relevant.
+        *
+        * @example var dtm = new Date();
+        * dtm.zeroTime();
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 00:01:00'
+        *
+        * @name zeroTime
+        * @type Date
+        * @cat Plugins/Methods/Date
+        * @author Kelvin Luck
+        */
+       add("zeroTime", function() {
+               this.setMilliseconds(0);
+               this.setSeconds(0);
+               this.setMinutes(0);
+               this.setHours(0);
+               return this;
+       });
+
+       /**
+        * Returns a string representation of the date object according to Date.format.
+        * (Date.toString may be used in other places so I purposefully didn't overwrite it)
+        *
+        * @example var dtm = new Date("01/12/2008");
+        * dtm.asString();
+        * @result '12/01/2008' // (where Date.format == 'dd/mm/yyyy'
+        *
+        * @name asString
+        * @type Date
+        * @cat Plugins/Methods/Date
+        * @author Kelvin Luck
+        */
+       add("asString", function() {
+               var r = Date.format;
+               return r
+                       .split('yyyy').join(this.getFullYear())
+                       .split('yy').join((this.getFullYear() + '').substring(2))
+                       .split('mmm').join(this.getMonthName(true))
+                       .split('mm').join(_zeroPad(this.getMonth()+1))
+                       .split('dd').join(_zeroPad(this.getDate()));
+       });
+
+       /**
+        * Returns a new date object created from the passed String according to Date.format or false if the attempt to do this results in an invalid date object
+        * (We can't simple use Date.parse as it's not aware of locale and I chose not to overwrite it incase it's functionality is being relied on elsewhere)
+        *
+        * @example var dtm = Date.fromString("12/01/2008");
+        * dtm.toString();
+        * @result 'Sat Jan 12 2008 00:00:00' // (where Date.format == 'dd/mm/yyyy'
+        *
+        * @name fromString
+        * @type Date
+        * @cat Plugins/Methods/Date
+        * @author Kelvin Luck
+        */
+       Date.fromString = function(s)
+       {
+               var f = Date.format;
+               var d = new Date('01/01/1977');
+               var iY = f.indexOf('yyyy');
+               if (iY > -1) {
+                       d.setFullYear(Number(s.substr(iY, 4)));
+               } else {
+                       // TODO - this doesn't work very well - are there any rules for what is meant by a two digit year?
+                       d.setFullYear(Number(Date.fullYearStart + s.substr(f.indexOf('yy'), 2)));
+               }
+               var iM = f.indexOf('mmm');
+               if (iM > -1) {
+                       var mStr = s.substr(iM, 3);
+                       for (var i=0; i<Date.abbrMonthNames.length; i++) {
+                               if (Date.abbrMonthNames[i] == mStr) break;
+                       }
+                       d.setMonth(i);
+               } else {
+                       d.setMonth(Number(s.substr(f.indexOf('mm'), 2)) - 1);
+               }
+               d.setDate(Number(s.substr(f.indexOf('dd'), 2)));
+               if (isNaN(d.getTime())) {
+                       return false;
+               }
+               return d;
+       };
+
+       // utility method
+       var _zeroPad = function(num) {
+               var s = '0'+num;
+               return s.substring(s.length-2)
+               //return ('0'+num).substring(-2); // doesn't work on IE :(
+       };
+
+})();
diff --git a/js2/mwEmbed/jquery/plugins/jquery.dimensions.js b/js2/mwEmbed/jquery/plugins/jquery.dimensions.js
new file mode 100644 (file)
index 0000000..100e60c
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-09-10 19:38:31 -0700 (Mon, 10 Sep 2007) $
+ * $Rev: 3238 $
+ *
+ * Version: @VERSION
+ *
+ * Requires: jQuery 1.2+
+ */
+
+(function($){
+
+$.dimensions = {
+       version: '@VERSION'
+};
+
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+$.each( [ 'Height', 'Width' ], function(i, name){
+
+       // innerHeight and innerWidth
+       $.fn[ 'inner' + name ] = function() {
+               if (!this[0]) return;
+
+               var torl = name == 'Height' ? 'Top'     : 'Left',  // top or left
+                       borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
+
+               return this[ name.toLowerCase() ]() + num(this, 'padding' + torl) + num(this, 'padding' + borr);
+       };
+
+       // outerHeight and outerWidth
+       $.fn[ 'outer' + name ] = function(options) {
+               if (!this[0]) return;
+
+               var torl = name == 'Height' ? 'Top'     : 'Left',  // top or left
+                       borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
+
+               options = $.extend({ margin: false }, options || {});
+
+               return this[ name.toLowerCase() ]()
+                               + num(this, 'border' + torl + 'Width') + num(this, 'border' + borr + 'Width')
+                               + num(this, 'padding' + torl) + num(this, 'padding' + borr)
+                               + (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0);
+       };
+});
+
+// Create scrollLeft and scrollTop methods
+$.each( ['Left', 'Top'], function(i, name) {
+       $.fn[ 'scroll' + name ] = function(val) {
+               if (!this[0]) return;
+
+               return val != undefined ?
+
+                       // Set the scroll offset
+                       this.each(function() {
+                               this == window || this == document ?
+                                       window.scrollTo(
+                                               name == 'Left' ? val : $(window)[ 'scrollLeft' ](),
+                                               name == 'Top'  ? val : $(window)[ 'scrollTop'  ]()
+                                       ) :
+                                       this[ 'scroll' + name ] = val;
+                       }) :
+
+                       // Return the scroll offset
+                       this[0] == window || this[0] == document ?
+                               self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] ||
+                                       $.boxModel && document.documentElement[ 'scroll' + name ] ||
+                                       document.body[ 'scroll' + name ] :
+                               this[0][ 'scroll' + name ];
+       };
+});
+
+$.fn.extend({
+       position: function() {
+               var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results;
+
+               if (elem) {
+                       // Get *real* offsetParent
+                       offsetParent = this.offsetParent();
+
+                       // Get correct offsets
+                       offset     = this.offset();
+                       parentOffset = offsetParent.offset();
+
+                       // Subtract element margins
+                       offset.top  -= num(elem, 'marginTop');
+                       offset.left -= num(elem, 'marginLeft');
+
+                       // Add offsetParent borders
+                       parentOffset.top  += num(offsetParent, 'borderTopWidth');
+                       parentOffset.left += num(offsetParent, 'borderLeftWidth');
+
+                       // Subtract the two offsets
+                       results = {
+                               top:  offset.top  - parentOffset.top,
+                               left: offset.left - parentOffset.left
+                       };
+               }
+
+               return results;
+       },
+
+       offsetParent: function() {
+               var offsetParent = this[0].offsetParent;
+               while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
+                       offsetParent = offsetParent.offsetParent;
+               return $(offsetParent);
+       }
+});
+
+var num = function(el, prop) {
+       return parseInt($.css(el.jquery?el[0]:el,prop))||0;
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/jquery.highlight.js b/js2/mwEmbed/jquery/plugins/jquery.highlight.js
new file mode 100644 (file)
index 0000000..c10c805
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+highlight v1
+
+Highlights arbitrary terms.
+<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>
+MIT license.
+
+Johann Burkard
+<http://johannburkard.de>
+<mailto:jb@eaio.com>
+*/
+$(function() {
+ jQuery.highlight = document.body.createTextRange ?
+
+/*
+Version for IE using TextRanges.
+*/
+  function(node, te) {
+   var r = document.body.createTextRange();
+   r.moveToElementText(node);
+   for (var i = 0; r.findText(te); i++) {
+    r.pasteHTML('<span class="highlight">' +  r.text + '<\/span>');
+    r.collapse(false);
+   }
+  }
+
+ :
+
+/*
+ (Complicated) version for Mozilla and Opera using span tags.
+*/
+  function(node, te) {
+   var pos, skip, spannode, middlebit, endbit, middleclone;
+   skip = 0;
+   if (node.nodeType == 3) {
+    pos = node.data.toUpperCase().indexOf(te);
+    if (pos >= 0) {
+     spannode = document.createElement('span');
+     spannode.className = 'highlight';
+     middlebit = node.splitText(pos);
+     endbit = middlebit.splitText(te.length);
+     middleclone = middlebit.cloneNode(true);
+     spannode.appendChild(middleclone);
+     middlebit.parentNode.replaceChild(spannode, middlebit);
+     skip = 1;
+    }
+   }
+   else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
+    for (var i = 0; i < node.childNodes.length; ++i) {
+     i += $.highlight(node.childNodes[i], te);
+    }
+   }
+   return skip;
+  }
+
+ ;
+});
+
+jQuery.fn.removeHighlight = function() {
+ return this.find("span.highlight").each(function() {
+  this.parentNode.replaceChild(this.firstChild, this).normalize();
+ });
+};
diff --git a/js2/mwEmbed/jquery/plugins/jquery.hoverIntent.js b/js2/mwEmbed/jquery/plugins/jquery.hoverIntent.js
new file mode 100644 (file)
index 0000000..9687ca0
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+* hoverIntent is similar to jQuery's built-in "hover" function except that
+* instead of firing the onMouseOver event immediately, hoverIntent checks
+* to see if the user's mouse has slowed down (beneath the sensitivity
+* threshold) before firing the onMouseOver event.
+*
+* hoverIntent r5 // 2007.03.27 // jQuery 1.1.2
+* <http://cherne.net/brian/resources/jquery.hoverIntent.html>
+*
+* hoverIntent is currently available for use in all personal or commercial
+* projects under both MIT and GPL licenses. This means that you can choose
+* the license that best suits your project, and use it accordingly.
+*
+* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions
+* $("ul li").hoverIntent( showNav , hideNav );
+*
+* // advanced usage receives configuration object only
+* $("ul li").hoverIntent({
+*      sensitivity: 2, // number = sensitivity threshold (must be 1 or higher)
+*      interval: 50,   // number = milliseconds of polling interval
+*      over: showNav,  // function = onMouseOver callback (required)
+*      timeout: 100,   // number = milliseconds delay before onMouseOut function call
+*      out: hideNav    // function = onMouseOut callback (required)
+* });
+*
+* @param  f  onMouseOver function || An object with configuration options
+* @param  g  onMouseOut function  || Nothing (use configuration options object)
+* @return    The object (aka "this") that called hoverIntent, and the event object
+* @author    Brian Cherne <brian@cherne.net>
+*/
+(function($) {
+       $.fn.hoverIntent = function(f,g) {
+               // default configuration options
+               var cfg = {
+                       sensitivity: 7,
+                       interval: 100,
+                       timeout: 0
+               };
+               // override configuration options with user supplied object
+               cfg = $.extend(cfg, g ? { over: f, out: g } : f );
+
+               // instantiate variables
+               // cX, cY = current X and Y position of mouse, updated by mousemove event
+               // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
+               var cX, cY, pX, pY;
+
+               // A private function for getting mouse position
+               var track = function(ev) {
+                       cX = ev.pageX;
+                       cY = ev.pageY;
+               };
+
+               // A private function for comparing current and previous mouse position
+               var compare = function(ev,ob) {
+                       ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+                       // compare mouse positions to see if they've crossed the threshold
+                       if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
+                               $(ob).unbind("mousemove",track);
+                               // set hoverIntent state to true (so mouseOut can be called)
+                               ob.hoverIntent_s = 1;
+                               return cfg.over.apply(ob,[ev]);
+                       } else {
+                               // set previous coordinates for next time
+                               pX = cX; pY = cY;
+                               // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
+                               ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
+                       }
+               };
+
+               // A private function for delaying the mouseOut function
+               var delay = function(ev,ob) {
+                       ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+                       ob.hoverIntent_s = 0;
+                       return cfg.out.apply(ob,[ev]);
+               };
+
+               // A private function for handling mouse 'hovering'
+               var handleHover = function(e) {
+                       // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
+                       var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
+                       while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
+                       if ( p == this ) { return false; }
+
+                       // copy objects to be passed into t (required for event object to be passed in IE)
+                       var ev = jQuery.extend({},e);
+                       var ob = this;
+
+                       // cancel hoverIntent timer if it exists
+                       if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
+
+                       // else e.type == "onmouseover"
+                       if (e.type == "mouseover") {
+                               // set "previous" X and Y position based on initial entry point
+                               pX = ev.pageX; pY = ev.pageY;
+                               // update "current" X and Y position based on mousemove
+                               $(ob).bind("mousemove",track);
+                               // start polling interval (self-calling timeout) to compare mouse coordinates over time
+                               if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
+
+                       // else e.type == "onmouseout"
+                       } else {
+                               // unbind expensive mousemove event
+                               $(ob).unbind("mousemove",track);
+                               // if hoverIntent state is true, then call the mouseOut function after the specified delay
+                               if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
+                       }
+               };
+
+               // bind the function to the two event listeners
+               return this.mouseover(handleHover).mouseout(handleHover);
+       };
+})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/jquery/plugins/jquery.json-1.3.js b/js2/mwEmbed/jquery/plugins/jquery.json-1.3.js
new file mode 100755 (executable)
index 0000000..225ca82
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * jQuery JSON Plugin
+ * version: 1.0 (2008-04-17)
+ *
+ * This document is licensed as free software under the terms of the
+ * MIT License: http://www.opensource.org/licenses/mit-license.php
+ *
+ * Brantley Harris technically wrote this plugin, but it is based somewhat
+ * on the JSON.org website's http://www.json.org/json2.js, which proclaims:
+ * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
+ * I uphold.  I really just cleaned it up.
+ *
+ * It is also based heavily on MochiKit's serializeJSON, which is 
+ * copywrited 2005 by Bob Ippolito.
+ */
+(function($) {   
+    function toIntegersAtLease(n) 
+    // Format integers to have at least two digits.
+    {    
+        return n < 10 ? '0' + n : n;
+    }
+
+    Date.prototype.toJSON = function(date)
+    // Yes, it polutes the Date namespace, but we'll allow it here, as
+    // it's damned usefull.
+    {
+        return this.getUTCFullYear()   + '-' +
+             toIntegersAtLease(this.getUTCMonth()) + '-' +
+             toIntegersAtLease(this.getUTCDate());
+    };
+
+    var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
+    var meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        };
+        
+    $.quoteString = function(string)
+    // Places quotes around a string, inteligently.
+    // If the string contains no control characters, no quote characters, and no
+    // backslash characters, then we can safely slap some quotes around it.
+    // Otherwise we must also replace the offending characters with safe escape
+    // sequences.
+    {
+        if (escapeable.test(string))
+        {
+            return '"' + string.replace(escapeable, function (a) 
+            {
+                var c = meta[a];
+                if (typeof c === 'string') {
+                    return c;
+                }
+                c = a.charCodeAt();
+                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
+            }) + '"';
+        }
+        return '"' + string + '"';
+    };
+    
+    $.toJSON = function(o, compact)
+    {
+        var type = typeof(o);
+        
+        if (type == "undefined")
+            return "undefined";
+        else if (type == "number" || type == "boolean")
+            return o + "";
+        else if (o === null)
+            return "null";
+        
+        // Is it a string?
+        if (type == "string") 
+        {
+            return $.quoteString(o);
+        }
+        
+        // Does it have a .toJSON function?
+        if (type == "object" && typeof o.toJSON == "function") 
+            return o.toJSON(compact);
+        
+        // Is it an array?
+        if (type != "function" && typeof(o.length) == "number") 
+        {
+            var ret = [];
+            for (var i = 0; i < o.length; i++) {
+                ret.push( $.toJSON(o[i], compact) );
+            }
+            if (compact)
+                return "[" + ret.join(",") + "]";
+            else
+                return "[" + ret.join(", ") + "]";
+        }
+        
+        // If it's a function, we have to warn somebody!
+        if (type == "function") {
+            throw new TypeError("Unable to convert object of type 'function' to json.");
+        }
+        
+        // It's probably an object, then.
+        var ret = [];
+        for (var k in o) {
+            var name;
+            type = typeof(k);
+            
+            if (type == "number")
+                name = '"' + k + '"';
+            else if (type == "string")
+                name = $.quoteString(k);
+            else
+                continue;  //skip non-string or number keys
+            
+            var val = $.toJSON(o[k], compact);
+            if (typeof(val) != "string") {
+                // skip non-serializable values
+                continue;
+            }
+            
+            if (compact)
+                ret.push(name + ":" + val);
+            else
+                ret.push(name + ": " + val);
+        }
+        return "{" + ret.join(", ") + "}";
+    };
+    
+    $.compactJSON = function(o)
+    {
+        return $.toJSON(o, true);
+    };
+    
+    $.evalJSON = function(src)
+    // Evals JSON that we know to be safe.
+    {
+        return eval("(" + src + ")");
+    };
+    
+    $.secureEvalJSON = function(src)
+    // Evals JSON in a way that is *more* secure.
+    {
+        var filtered = src;
+        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
+        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
+        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
+        
+        if (/^[\],:{}\s]*$/.test(filtered))
+            return eval("(" + src + ")");
+        else
+            throw new SyntaxError("Error parsing JSON, source is not valid.");
+    };
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/plugins/jquery.pngFix.js b/js2/mwEmbed/jquery/plugins/jquery.pngFix.js
new file mode 100644 (file)
index 0000000..6adfcc9
--- /dev/null
@@ -0,0 +1,113 @@
+/**\r
+ * --------------------------------------------------------------------\r
+ * jQuery-Plugin "pngFix"\r
+ * Version: 1.2, 09.03.2009\r
+ * by Andreas Eberhard, andreas.eberhard@gmail.com\r
+ *                      http://jquery.andreaseberhard.de/\r
+ *\r
+ * Copyright (c) 2007 Andreas Eberhard\r
+ * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)\r
+ *\r
+ * Changelog:\r
+ *    09.03.2009 Version 1.2\r
+ *    - Update for jQuery 1.3.x, removed @ from selectors\r
+ *    11.09.2007 Version 1.1\r
+ *    - removed noConflict\r
+ *    - added png-support for input type=image\r
+ *    - 01.08.2007 CSS background-image support extension added by Scott Jehl, scott@filamentgroup.com, http://www.filamentgroup.com\r
+ *    31.05.2007 initial Version 1.0\r
+ * --------------------------------------------------------------------\r
+ * @example $(function(){$(document).pngFix();});\r
+ * @desc Fixes all PNG's in the document on document.ready\r
+ *\r
+ * jQuery(function(){jQuery(document).pngFix();});\r
+ * @desc Fixes all PNG's in the document on document.ready when using noConflict\r
+ *\r
+ * @example $(function(){$('div.examples').pngFix();});\r
+ * @desc Fixes all PNG's within div with class examples\r
+ *\r
+ * @example $(function(){$('div.examples').pngFix( { blankgif:'ext.gif' } );});\r
+ * @desc Fixes all PNG's within div with class examples, provides blank gif for input with png\r
+ * --------------------------------------------------------------------\r
+ */\r
+\r
+(function($) {\r
+\r
+jQuery.fn.pngFix = function(settings) {\r
+\r
+       // Settings\r
+       settings = jQuery.extend({\r
+               blankgif: 'blank.gif'\r
+       }, settings);\r
+\r
+       var ie55 = (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion) == 4 && navigator.appVersion.indexOf("MSIE 5.5") != -1);\r
+       var ie6 = (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion) == 4 && navigator.appVersion.indexOf("MSIE 6.0") != -1);\r
+\r
+       if (jQuery.browser.msie && (ie55 || ie6)) {\r
+\r
+               //fix images with png-source\r
+               jQuery(this).find("img[src$=.png]").each(function() {\r
+\r
+                       jQuery(this).attr('width',jQuery(this).width());\r
+                       jQuery(this).attr('height',jQuery(this).height());\r
+\r
+                       var prevStyle = '';\r
+                       var strNewHTML = '';\r
+                       var imgId = (jQuery(this).attr('id')) ? 'id="' + jQuery(this).attr('id') + '" ' : '';\r
+                       var imgClass = (jQuery(this).attr('class')) ? 'class="' + jQuery(this).attr('class') + '" ' : '';\r
+                       var imgTitle = (jQuery(this).attr('title')) ? 'title="' + jQuery(this).attr('title') + '" ' : '';\r
+                       var imgAlt = (jQuery(this).attr('alt')) ? 'alt="' + jQuery(this).attr('alt') + '" ' : '';\r
+                       var imgAlign = (jQuery(this).attr('align')) ? 'float:' + jQuery(this).attr('align') + ';' : '';\r
+                       var imgHand = (jQuery(this).parent().attr('href')) ? 'cursor:hand;' : '';\r
+                       if (this.style.border) {\r
+                               prevStyle += 'border:'+this.style.border+';';\r
+                               this.style.border = '';\r
+                       }\r
+                       if (this.style.padding) {\r
+                               prevStyle += 'padding:'+this.style.padding+';';\r
+                               this.style.padding = '';\r
+                       }\r
+                       if (this.style.margin) {\r
+                               prevStyle += 'margin:'+this.style.margin+';';\r
+                               this.style.margin = '';\r
+                       }\r
+                       var imgStyle = (this.style.cssText);\r
+\r
+                       strNewHTML += '<span '+imgId+imgClass+imgTitle+imgAlt;\r
+                       strNewHTML += 'style="position:relative;white-space:pre-line;display:inline-block;background:transparent;'+imgAlign+imgHand;\r
+                       strNewHTML += 'width:' + jQuery(this).width() + 'px;' + 'height:' + jQuery(this).height() + 'px;';\r
+                       strNewHTML += 'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + jQuery(this).attr('src') + '\', sizingMethod=\'scale\');';\r
+                       strNewHTML += imgStyle+'"></span>';\r
+                       if (prevStyle != ''){\r
+                               strNewHTML = '<span style="position:relative;display:inline-block;'+prevStyle+imgHand+'width:' + jQuery(this).width() + 'px;' + 'height:' + jQuery(this).height() + 'px;'+'">' + strNewHTML + '</span>';\r
+                       }\r
+\r
+                       jQuery(this).hide();\r
+                       jQuery(this).after(strNewHTML);\r
+\r
+               });\r
+\r
+               // fix css background pngs\r
+               jQuery(this).find("*").each(function(){\r
+                       var bgIMG = jQuery(this).css('background-image');\r
+                       if(bgIMG.indexOf(".png")!=-1){\r
+                               var iebg = bgIMG.split('url("')[1].split('")')[0];\r
+                               jQuery(this).css('background-image', 'none');\r
+                               jQuery(this).get(0).runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + iebg + "',sizingMethod='scale')";\r
+                       }\r
+               });\r
+               \r
+               //fix input with png-source\r
+               jQuery(this).find("input[src$=.png]").each(function() {\r
+                       var bgIMG = jQuery(this).attr('src');\r
+                       jQuery(this).get(0).runtimeStyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + bgIMG + '\', sizingMethod=\'scale\');';\r
+               jQuery(this).attr('src', settings.blankgif)\r
+               });\r
+       \r
+       }\r
+       \r
+       return jQuery;\r
+\r
+};\r
+\r
+})(jQuery);\r
diff --git a/js2/mwEmbed/jquery/plugins/jquery.secureEvalJSON.js b/js2/mwEmbed/jquery/plugins/jquery.secureEvalJSON.js
new file mode 100644 (file)
index 0000000..225ca82
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * jQuery JSON Plugin
+ * version: 1.0 (2008-04-17)
+ *
+ * This document is licensed as free software under the terms of the
+ * MIT License: http://www.opensource.org/licenses/mit-license.php
+ *
+ * Brantley Harris technically wrote this plugin, but it is based somewhat
+ * on the JSON.org website's http://www.json.org/json2.js, which proclaims:
+ * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
+ * I uphold.  I really just cleaned it up.
+ *
+ * It is also based heavily on MochiKit's serializeJSON, which is 
+ * copywrited 2005 by Bob Ippolito.
+ */
+(function($) {   
+    function toIntegersAtLease(n) 
+    // Format integers to have at least two digits.
+    {    
+        return n < 10 ? '0' + n : n;
+    }
+
+    Date.prototype.toJSON = function(date)
+    // Yes, it polutes the Date namespace, but we'll allow it here, as
+    // it's damned usefull.
+    {
+        return this.getUTCFullYear()   + '-' +
+             toIntegersAtLease(this.getUTCMonth()) + '-' +
+             toIntegersAtLease(this.getUTCDate());
+    };
+
+    var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
+    var meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        };
+        
+    $.quoteString = function(string)
+    // Places quotes around a string, inteligently.
+    // If the string contains no control characters, no quote characters, and no
+    // backslash characters, then we can safely slap some quotes around it.
+    // Otherwise we must also replace the offending characters with safe escape
+    // sequences.
+    {
+        if (escapeable.test(string))
+        {
+            return '"' + string.replace(escapeable, function (a) 
+            {
+                var c = meta[a];
+                if (typeof c === 'string') {
+                    return c;
+                }
+                c = a.charCodeAt();
+                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
+            }) + '"';
+        }
+        return '"' + string + '"';
+    };
+    
+    $.toJSON = function(o, compact)
+    {
+        var type = typeof(o);
+        
+        if (type == "undefined")
+            return "undefined";
+        else if (type == "number" || type == "boolean")
+            return o + "";
+        else if (o === null)
+            return "null";
+        
+        // Is it a string?
+        if (type == "string") 
+        {
+            return $.quoteString(o);
+        }
+        
+        // Does it have a .toJSON function?
+        if (type == "object" && typeof o.toJSON == "function") 
+            return o.toJSON(compact);
+        
+        // Is it an array?
+        if (type != "function" && typeof(o.length) == "number") 
+        {
+            var ret = [];
+            for (var i = 0; i < o.length; i++) {
+                ret.push( $.toJSON(o[i], compact) );
+            }
+            if (compact)
+                return "[" + ret.join(",") + "]";
+            else
+                return "[" + ret.join(", ") + "]";
+        }
+        
+        // If it's a function, we have to warn somebody!
+        if (type == "function") {
+            throw new TypeError("Unable to convert object of type 'function' to json.");
+        }
+        
+        // It's probably an object, then.
+        var ret = [];
+        for (var k in o) {
+            var name;
+            type = typeof(k);
+            
+            if (type == "number")
+                name = '"' + k + '"';
+            else if (type == "string")
+                name = $.quoteString(k);
+            else
+                continue;  //skip non-string or number keys
+            
+            var val = $.toJSON(o[k], compact);
+            if (typeof(val) != "string") {
+                // skip non-serializable values
+                continue;
+            }
+            
+            if (compact)
+                ret.push(name + ":" + val);
+            else
+                ret.push(name + ": " + val);
+        }
+        return "{" + ret.join(", ") + "}";
+    };
+    
+    $.compactJSON = function(o)
+    {
+        return $.toJSON(o, true);
+    };
+    
+    $.evalJSON = function(src)
+    // Evals JSON that we know to be safe.
+    {
+        return eval("(" + src + ")");
+    };
+    
+    $.secureEvalJSON = function(src)
+    // Evals JSON in a way that is *more* secure.
+    {
+        var filtered = src;
+        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
+        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
+        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
+        
+        if (/^[\],:{}\s]*$/.test(filtered))
+            return eval("(" + src + ")");
+        else
+            throw new SyntaxError("Error parsing JSON, source is not valid.");
+    };
+})(jQuery);
diff --git a/js2/mwEmbed/jquery/plugins/jquery.timers.js b/js2/mwEmbed/jquery/plugins/jquery.timers.js
new file mode 100644 (file)
index 0000000..406de7e
--- /dev/null
@@ -0,0 +1,142 @@
+jQuery.fn.extend({
+       everyTime: function(interval, label, fn, times, belay) {
+               return this.each(function() {
+                       jQuery.timer.add(this, interval, label, fn, times, belay);
+               });
+       },
+       oneTime: function(interval, label, fn) {
+               return this.each(function() {
+                       jQuery.timer.add(this, interval, label, fn, 1);
+               });
+       },
+       stopTime: function(label, fn) {
+               return this.each(function() {
+                       jQuery.timer.remove(this, label, fn);
+               });
+       }
+});
+
+jQuery.extend({
+       timer: {
+               guid: 1,
+               global: {},
+               regex: /^([0-9]+)\s*(.*s)?$/,
+               powers: {
+                       // Yeah this is major overkill...
+                       'ms': 1,
+                       'cs': 10,
+                       'ds': 100,
+                       's': 1000,
+                       'das': 10000,
+                       'hs': 100000,
+                       'ks': 1000000
+               },
+               timeParse: function(value) {
+                       if (value == undefined || value == null)
+                               return null;
+                       var result = this.regex.exec(jQuery.trim(value.toString()));
+                       if (result[2]) {
+                               var num = parseInt(result[1], 10);
+                               var mult = this.powers[result[2]] || 1;
+                               return num * mult;
+                       } else {
+                               return value;
+                       }
+               },
+               add: function(element, interval, label, fn, times, belay) {
+                       var counter = 0;
+                       
+                       if (jQuery.isFunction(label)) {
+                               if (!times) 
+                                       times = fn;
+                               fn = label;
+                               label = interval;
+                       }
+                       
+                       interval = jQuery.timer.timeParse(interval);
+
+                       if (typeof interval != 'number' || isNaN(interval) || interval <= 0)
+                               return;
+
+                       if (times && times.constructor != Number) {
+                               belay = !!times;
+                               times = 0;
+                       }
+                       
+                       times = times || 0;
+                       belay = belay || false;
+                       
+                       if (!element.$timers) 
+                               element.$timers = {};
+                       
+                       if (!element.$timers[label])
+                               element.$timers[label] = {};
+                       
+                       fn.$timerID = fn.$timerID || this.guid++;
+                       
+                       var handler = function() {
+                               if (belay && this.inProgress) 
+                                       return;
+                               this.inProgress = true;
+                               if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
+                                       jQuery.timer.remove(element, label, fn);
+                               this.inProgress = false;
+                       };
+                       
+                       handler.$timerID = fn.$timerID;
+                       
+                       if (!element.$timers[label][fn.$timerID]) 
+                               element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);
+                       
+                       if ( !this.global[label] )
+                               this.global[label] = [];
+                       this.global[label].push( element );
+                       
+               },
+               remove: function(element, label, fn) {
+                       var timers = element.$timers, ret;
+                       
+                       if ( timers ) {
+                               
+                               if (!label) {
+                                       for ( label in timers )
+                                               this.remove(element, label, fn);
+                               } else if ( timers[label] ) {
+                                       if ( fn ) {
+                                               if ( fn.$timerID ) {
+                                                       window.clearInterval(timers[label][fn.$timerID]);
+                                                       delete timers[label][fn.$timerID];
+                                               }
+                                       } else {
+                                               for ( var fn in timers[label] ) {
+                                                       window.clearInterval(timers[label][fn]);
+                                                       delete timers[label][fn];
+                                               }
+                                       }
+                                       
+                                       for ( ret in timers[label] ) break;
+                                       if ( !ret ) {
+                                               ret = null;
+                                               delete timers[label];
+                                       }
+                               }
+                               
+                               for ( ret in timers ) break;
+                               if ( !ret ) 
+                                       element.$timers = null;
+                       }
+               }
+       }
+});
+
+if (jQuery.browser.msie)
+       jQuery(window).one("unload", function() {
+               var global = jQuery.timer.global;
+               for ( var label in global ) {
+                       var els = global[label], i = els.length;
+                       while ( --i )
+                               jQuery.timer.remove(els[i], label);
+               }
+       });
+
+
diff --git a/js2/mwEmbed/jquery/plugins/jqueryContextMenu.html b/js2/mwEmbed/jquery/plugins/jqueryContextMenu.html
new file mode 100644 (file)
index 0000000..1c8368a
--- /dev/null
@@ -0,0 +1,195 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+       <head>
+               <title>jQuery Context Menu Plugin Demo</title>
+               <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+               
+               <style type="text/css">
+                       BODY,
+                       HTML {
+                               padding: 0px;
+                               margin: 0px;
+                       }
+                       BODY {
+                               font-family: Verdana, Arial, Helvetica, sans-serif;
+                               font-size: 11px;
+                               background: #FFF;
+                               padding: 15px;
+                       }
+                       
+                       H1 {
+                               font-family: Georgia, serif;
+                               font-size: 20px;
+                               font-weight: normal;
+                       }
+                       
+                       H2 {
+                               font-family: Georgia, serif;
+                               font-size: 16px;
+                               font-weight: normal;
+                               margin: 0px 0px 10px 0px;
+                       }
+                       
+                       #myDiv {
+                               width: 150px;
+                               border: solid 1px #2AA7DE;
+                               background: #6CC8EF;
+                               padding: 1em .5em;
+                               margin: 1em;
+                               float: left;
+                       }
+                       
+                       #myList {
+                               margin: 1em;
+                               float: left;
+                       }
+                       
+                       #myList UL {
+                               padding: 0px;
+                               margin: 0em 1em;
+                       }
+                       
+                       #myList LI {
+                               width: 100px;
+                               border: solid 1px #CCC;
+                               background: #EEE;
+                               padding: 2px 5px;
+                               margin: 2px 0px;
+                               list-style: none;
+                       }
+                       
+                       #options {
+                               clear: left;
+                       }
+                       
+                       #options INPUT {
+                               font-family: Verdana, Arial, Helvetica, sans-serif;
+                               font-size: 11px;
+                               width: 150px;
+                       }
+                       
+               </style>                
+               
+               <script src="http://abeautifulsite.net/includes/jquery.js" type="text/javascript"></script>
+               <script src="jquery.contextMenu.js" type="text/javascript"></script>
+               <link href="jquery.contextMenu.css" rel="stylesheet" type="text/css" />
+               
+               <script type="text/javascript">
+                       
+                       $(document).ready( function() {
+                               
+                               // Show menu when #myDiv is clicked
+                               $("#myDiv").contextMenu({
+                                       menu: 'myMenu'
+                               },
+                                       function(action, el, pos) {
+                                       alert(
+                                               'Action: ' + action + '\n\n' +
+                                               'Element ID: ' + $(el).attr('id') + '\n\n' + 
+                                               'X: ' + pos.x + '  Y: ' + pos.y + ' (relative to element)\n\n' + 
+                                               'X: ' + pos.docX + '  Y: ' + pos.docY+ ' (relative to document)'
+                                               );
+                               });
+                               
+                               // Show menu when a list item is clicked
+                               $("#myList UL LI").contextMenu({
+                                       menu: 'myMenu'
+                               }, function(action, el, pos) {
+                                       alert(
+                                               'Action: ' + action + '\n\n' +
+                                               'Element text: ' + $(el).text() + '\n\n' + 
+                                               'X: ' + pos.x + '  Y: ' + pos.y + ' (relative to element)\n\n' + 
+                                               'X: ' + pos.docX + '  Y: ' + pos.docY+ ' (relative to document)'
+                                               );
+                               });
+                               
+                               // Disable menus
+                               $("#disableMenus").click( function() {
+                                       $('#myDiv, #myList UL LI').disableContextMenu();
+                                       $(this).attr('disabled', true);
+                                       $("#enableMenus").attr('disabled', false);
+                               });
+                               
+                               // Enable menus
+                               $("#enableMenus").click( function() {
+                                       $('#myDiv, #myList UL LI').enableContextMenu();
+                                       $(this).attr('disabled', true);
+                                       $("#disableMenus").attr('disabled', false);
+                               });
+                               
+                               // Disable cut/copy
+                               $("#disableItems").click( function() {
+                                       $('#myMenu').disableContextMenuItems('#cut,#copy');
+                                       $(this).attr('disabled', true);
+                                       $("#enableItems").attr('disabled', false);
+                               });
+                               
+                               // Enable cut/copy
+                               $("#enableItems").click( function() {
+                                       $('#myMenu').enableContextMenuItems('#cut,#copy');
+                                       $(this).attr('disabled', true);
+                                       $("#disableItems").attr('disabled', false);
+                               });                             
+                               
+                       });
+                       
+               </script>
+       </head>
+       
+       <body>
+               
+               <h1>jQuery Context Menu Plugin Demo</h1>
+               <p>
+                       This plugin lets you add context menu functionality to your web applications.
+               </p>
+               
+               <p>
+                       <strong>Tip:</strong> Try using your keyboard to make a selection.
+               </p>
+               
+               <p>
+                       <a href="/notebook.php?article=69">Back to the project page</a>
+               </p>
+               
+               <h2>Demo</h2>
+               
+               <div id="myDiv">
+                       Right click for the standard context menu
+               </div>
+               
+               <div id="myList">
+                       <ul>
+                               <li>Item 1</li>
+                               <li>Item 2</li>
+                               <li>Item 3</li>
+                               <li>Item 4</li>
+                               <li>Item 5</li>
+                               <li>Item 6</li>
+                       </ul>
+               </div>
+               
+               <div id="options">
+                       <p>
+                               <input type="button" id="disableItems" value="Disable Cut/Copy" />
+                               <input type="button" id="enableItems" value="Enable Cut/Copy" disabled="disabled" />
+                       </p>
+                       
+                       <p>
+                               <input type="button" id="disableMenus" value="Disable Context Menus" />
+                               <input type="button" id="enableMenus" value="Enable Context Menus" disabled="disabled" />
+                       </p>
+               </div>
+               
+               <ul id="myMenu" class="contextMenu">
+                       <li class="edit"><a href="#edit">Edit</a></li>
+                       <li class="cut separator"><a href="#cut">Cut</a></li>
+                       <li class="copy"><a href="#copy">Copy</a></li>
+                       <li class="paste"><a href="#paste">Paste</a></li>
+                       <li class="delete"><a href="#delete">Delete</a></li>
+                       <li class="quit separator"><a href="#quit">Quit</a></li>
+               </ul>
+               
+       </body>
+</html>
\ No newline at end of file
diff --git a/js2/mwEmbed/jsScriptLoader.php b/js2/mwEmbed/jsScriptLoader.php
new file mode 100644 (file)
index 0000000..e77ee42
--- /dev/null
@@ -0,0 +1,364 @@
+<?php
+//This core jsScriptLoader class provides the script loader functionality
+//check if we are being invoked in mediaWiki context or stand alone usage:
+if ( !defined( 'MEDIAWIKI' ) ){
+       //load noMediaWiki helper:
+       require_once( realpath( dirname(__FILE__) ) . '/php/noMediaWikiConfig.php' );
+
+       //run the main action:
+       $myScriptLoader = new jsScriptLoader();
+       //preset request values via normal $_GET operation:
+       $myScriptLoader->doScriptLoader();
+}else{
+    $wgExtensionMessagesFiles['mwEmbed'] =  realpath( dirname(__FILE__) ) .'/php/mwEmbed.i18n.php';
+}
+
+//setup page output hook
+class jsScriptLoader{
+       var $jsFileList = array();
+       var $jsout = '';
+       var $rKey = ''; // the request key
+       var $error_msg ='';
+       var $debug = false;
+       var $jsvarurl =false; // if we should include generated js (special class '-')
+       var $doProcReqFlag =true;
+
+       function doScriptLoader(){
+               global  $wgJSAutoloadClasses,$wgJSAutoloadLocalClasses, $wgEnableScriptLoaderJsFile, $IP,
+                               $wgEnableScriptMinify, $wgUseFileCache;
+
+               //process the request
+               $this->procRequestVars();
+
+               //if cache is on and file is present grab it from there:
+               if( $wgUseFileCache && !$this->debug ) {
+                       //setup file cache obj:
+                       $this->sFileCache = new simpleFileCache( $this->rKey );
+                       if( $this->sFileCache->isFileCached() ){
+                           //just output headers so we can use php "efficient" readfile
+                               $this->outputJsHeaders();
+                               $this->sFileCache->outputFromFileCache();
+                               die();
+                       }
+               }
+
+               //setup script loader header info
+               $this->jsout .= 'var mwSlScript = "'. $_SERVER['SCRIPT_NAME'] . '";' . "\n";
+               $this->jsout .= 'var mwSlGenISODate = "'. date('c') . '";'  ."\n";
+               $this->jsout .= 'var mwSlURID = "' . $this->urid . '";'  ."\n";
+               //Build the Output:
+               //swap in the appropriate language per js_file
+               foreach($this->jsFileList as $classKey => $file_name){
+                       //special case: - title classes:
+                       if( substr( $classKey, 0, 3) == 'WT:' ){
+                               //get just the tile part:
+                               $title_block = substr( $classKey, 3);
+                               if($title_block[0] == '-' && strpos($title_block, '|') !== false){
+                                       //special case of "-" title with skin
+                                       $parts = explode('|', $title_block);
+                                       $title = array_shift($parts);
+                                       foreach($parts as $tparam){
+                                               list($key, $val)= explode('=', $tparam);
+                                               if( $key=='useskin' ){
+                                                       $skin= $val;
+                                               }
+                                       }
+                                       //make sure the skin name is valid
+                                       $skinNames = Skin::getSkinNames();
+                                       //get the lower case skin name (array keys)
+                                       $skinNames = array_keys($skinNames);
+                                       if( in_array(strtolower($skin), $skinNames )){
+                                               $this->jsout .= Skin::generateUserJs( $skin ) . "\n";
+                                               //success continue:
+                                               continue;
+                                       }
+                               }else{
+                                       //its a wikiTitle append the output of the wikitext:
+                                       $t =  Title::newFromText ( $title_block );
+                                       $a =  new Article( $t );
+                                       //only get content if the page is not empty:
+                                       if($a->getID() !== 0 ){
+                                               $this->jsout .= $a->getContent() .  "\n";
+                                       }
+                                       continue;
+                               }
+                       }
+
+                       if( trim( $file_name ) != ''){
+                               //if in debug add a comment with the file name:
+                               if($this->debug)
+                                       $this->jsout .= "\n/**
+* File: $file_name
+*/\n";
+                               $this->jsout .= ( $this->doProccessJsFile( $file_name ) ). "\n";
+                       }
+               }
+               //check if we should minify :
+               if( $wgEnableScriptMinify && !$this->debug){
+                       //do the minification and output
+                       $this->jsout = JSMin::minify( $this->jsout);
+               }
+               //save to the file cache:
+               if( $wgUseFileCache && !$this->debug) {
+                       $status = $this->sFileCache->saveToFileCache($this->jsout);
+                       if($status!==true)
+                           $this->error_msg.= $status;
+               }
+               //check for error msg:
+               if( $this->error_msg != ''){
+                       echo 'alert(\'Error With ScriptLoader.php ::' . str_replace("\n", '\'+"\n"+'."\n'", $this->error_msg ). '\');';
+                       echo trim($this->jsout);
+               }else{
+                   //all good lets output cache forever headers:
+                   $this->outputJsWithHeaders();
+               }
+       }
+       function outputJsHeaders(){
+           global $wgJsMimeType;
+               //output js mime type:
+               header( 'Content-type: '.$wgJsMimeType);
+               header( "Pragma: public" );
+               //cache forever:
+               //(the point is we never have to re validate since we should always change the request url based on the svn or article version)
+               $one_year = 60*60*24*365;
+               header("Expires: " . gmdate( "D, d M Y H:i:s", time() + $one_year  ) . " GM");
+       }
+       function outputJsWithHeaders(){
+           global $wgUseGzip;
+           $this->outputJsHeaders();
+           if( $wgUseGzip ) {
+               if( wfClientAcceptsGzip() ) {
+                               header( 'Content-Encoding: gzip' );
+                               echo gzencode( $this->jsout );
+               }else{
+                   echo $this->jsout;
+               }
+               }else{
+                   echo $this->jsout;
+               }
+       }
+       /*
+        * updates the proc Request
+        */
+       function procRequestVars(){
+               global $wgContLanguageCode, $wgEnableScriptMinify, $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgStyleVersion;
+
+               //set debug flag:
+               if( (isset($_GET['debug']) && $_GET['debug']=='true') || (isset($wgEnableScriptDebug) && $wgEnableScriptDebug==true )){
+                               $this->debug = true;
+               }
+
+               //set the urid: (be sure to escape it as it goes into our js output)
+               if( isset( $_GET['urid'] ) && $_GET['urid'] !=''){
+                       $this->urid = htmlspecialchars( $_GET['urid'] );
+               }else{
+                       //just give it the current style sheet id:
+                       //@@todo read the svn version number
+                       $this->urid =  $wgStyleVersion;
+               }
+
+               $reqClassList = false;
+               if( isset($_GET['class']) && $_GET['class']!=''){
+                       $reqClassList = explode( ',', $_GET['class'] );
+               }
+               //check for the requested classes
+               if( $reqClassList ){
+                       //clean the class list and populate jsFileList
+                       foreach( $reqClassList as $reqClass ){
+                               if(trim($reqClass) != ''){
+                                       //check for special case '-' class for user generated js
+                                       if( substr( $reqClass, 0, 3) == 'WT:' ){
+                                               $this->jsFileList[ $reqClass ] = true;
+                                               $this->rKey .= $reqClass;
+                                               $this->jsvarurl = true;
+                                               continue;
+                                       }
+
+                                       $reqClass = ereg_replace("[^A-Za-z0-9_\-\.]", "", $reqClass );
+
+                                       if( isset( $wgJSAutoloadLocalClasses[$reqClass] ) ){
+                                               $this->jsFileList[ $reqClass ] = $wgJSAutoloadLocalClasses[ $reqClass ];
+                                               $this->rKey.=$reqClass;
+                                       }else if( isset($wgJSAutoloadClasses[$reqClass])) {
+                                               $this->jsFileList[ $reqClass ] = $wgJSAutoloadClasses[ $reqClass ];
+                                               $this->rKey.=$reqClass;
+                                       }else{
+                                               $this->error_msg.= 'Requested class: ' . $reqClass . ' not found'."\n";
+                                       }
+                               }
+                       }
+               }
+
+               //check for requested files if enabled:
+               if( $wgEnableScriptLoaderJsFile ){
+                       if( isset($_GET['files'])){
+                               $reqFileList = explode(',', isset($_GET['files']));
+                               //clean the file list and populate jsFileList
+                               foreach($reqFileList as $reqFile){
+                                       //no jumping dirs:
+                                       $reqFile = str_replace('../','',$reqFile);
+                                       //only allow alphanumeric underscores periods and ending with .js
+                                       $reqFile = ereg_replace("[^A-Za-z0-9_\-\/\.]", "", $reqFile );
+                                       if( substr($reqFile, -3) == '.js' ){
+                                               //don't add it twice:
+                                               if( !in_array($reqFile, $jsFileList )) {
+                                                       $this->jsFileList[] = $IP . $reqFile;
+                                                       $this->rKey.=$reqFile;
+                                               }
+                                       }else{
+                                               $this->error_msg.= 'Not valid requsted javascript file' . "\n";
+                                       }
+                               }
+                       }
+               }
+
+               //add the language code to the rKey:
+               $this->rKey .= '_' . $wgContLanguageCode;
+
+               //add the unique rid to the rKey
+               $this->rKey .= $this->urid;
+
+               //add a min flag:
+               if($wgEnableScriptMinify){
+                       $this->rKey.='_min';
+               }
+       }
+       function doProccessJsFile( $file_name ){
+               global $IP, $wgEnableScriptLocalization, $IP;
+
+               //load the file:
+               $str = @file_get_contents("{$IP}/{$file_name}");
+
+               if($str===false){
+                       //@@todo check php error level (don't want to expose paths if errors are hidden)
+                       $this->error_msg.= 'Requested File: ' . htmlspecialchars( $file_name ) . ' could not be read' . "\n";
+                       return '';
+               }
+               $this->cur_file = $file_name;
+
+               //strip out js_log debug lines not much luck with this regExp yet:
+               //if( !$this->debug )
+               //       $str = preg_replace('/\n\s*js_log\s*\([^\)]([^;]|\n])*;/', "\n", $str);
+
+               // do language swap
+               if($wgEnableScriptLocalization)
+                       $str = preg_replace_callback('/loadGM\s*\(\s*{(.*)}\s*\)\s*/siU',       //@@todo fix: will break down if someone does }) in their msg text
+                                                                               array($this, 'languageMsgReplace'),
+                                                                               $str);
+
+               return $str;
+       }
+       function languageMsgReplace($jvar){
+               if(!isset($jvar[1]))
+                       return ;
+
+               $jmsg = json_decode( '{' . $jvar[1] . '}', true );
+               //do the language lookup:
+               if($jmsg){
+                       foreach($jmsg as $msgKey => $default_en_value){
+                               $jmsg[$msgKey] = wfMsgNoTrans( $msgKey );
+                       }
+                       //return the updated loadGM json with fixed new lines:
+                       return 'loadGM( ' . json_encode( $jmsg ) . ')';
+               }else{
+                       $this->error_msg.= "Could not parse JSON language msg in File:\n" .
+                                                               $this->cur_file ."\n";
+               }
+               //could not parse json (throw error?)
+               return $jvar[0];
+       }
+}
+//a simple version of HTMLFileCache (@@todo abstract shared pieces)
+class simpleFileCache{
+       var $mFileCache;
+       var $filename= null;
+       var $rKey= null;
+       public function __construct( &$rKey ) {
+               $this->rKey = $rKey;
+               $this->filename = $this->fileCacheName(); // init name
+       }
+       public function fileCacheName() {
+           global $wgUseGzip;
+               if( !$this->mFileCache ) {
+                       global $wgFileCacheDirectory;
+
+                       $hash = md5( $this->rKey );
+                       # Avoid extension confusion
+                       $key = str_replace( '.', '%2E', urlencode( $this->rKey ) );
+
+                       $hash1 = substr( $hash, 0, 1 );
+                       $hash2 = substr( $hash, 0, 2 );
+                       $this->mFileCache = "{$wgFileCacheDirectory}/{$subdir}{$hash1}/{$hash2}/{$this->rKey}.js";
+
+                       if( $wgUseGzip )
+                               $this->mFileCache .= '.gz';
+
+                       wfDebug( " fileCacheName() - {$this->mFileCache}\n" );
+               }
+               return $this->mFileCache;
+       }
+       public function isFileCached() {
+               return file_exists( $this->filename );
+       }
+       public function outputFromFileCache(){
+               global $wgUseGzip;
+               if( $wgUseGzip ) {
+                       if( wfClientAcceptsGzip() ) {
+                               header( 'Content-Encoding: gzip' );
+                               readfile( $this->filename );
+                       } else {
+                               /* Send uncompressed  (check if fileCache is in compressed state (ends with .gz)
+                               * (unlikely to execute this since $wgUseGzip would have created a new file above.. but just in case:
+                               */
+                           if(substr($this->filename, -3)=='.gz'){
+                                   readgzfile( $this->filename );
+                           }else{
+                               readfile( $this->filename );
+                           }
+                       }
+               }else{
+                   //just output the file
+                   readfile( $this->filename );
+               }
+               //return true
+               return true;
+       }
+       public function saveToFileCache(& $text ) {
+               global $wgUseFileCache, $wgUseGzip;
+               if( !$wgUseFileCache ) {
+                       return 'Error: Called saveToFileCache with $wgUseFileCache off';
+               }
+               if( strcmp($text,'') == 0 ) return 'saveToFileCache: empty output file';
+
+        //check the directories if we could not create them error out:
+        $status = $this->checkCacheDirs();
+
+        if($wgUseGzip){
+            $outputText = gzencode( trim($text) );
+        }else{
+            $outputText = trim($text);
+        }
+
+               if($status !== true)
+                   return $status;
+               $f = fopen( $this->filename, 'w' );
+               if($f) {
+                       fwrite( $f, $outputText );
+                       fclose( $f );
+               }else{
+                   return 'Could not open file for writing. Check your cache directory permissions?';
+               }
+               return true;
+       }
+       protected function checkCacheDirs() {
+               $mydir2 = substr($this->filename,0,strrpos($this->filename,'/')); # subdirectory level 2
+               $mydir1 = substr($mydir2,0,strrpos($mydir2,'/')); # subdirectory level 1
+
+               if( wfMkdirParents( $mydir1 ) === false || wfMkdirParents( $mydir2 ) === false){
+                   return 'Could not create cache directory. Check your cache directory permissions?';
+               }else{
+                   return true;
+               }
+       }
+}
+?>
\ No newline at end of file
diff --git a/js2/mwEmbed/libAddMedia/mediaWikiUploadHelper.OFF.js b/js2/mwEmbed/libAddMedia/mediaWikiUploadHelper.OFF.js
new file mode 100644 (file)
index 0000000..5bbeb7e
--- /dev/null
@@ -0,0 +1,163 @@
+/* the upload javascript 
+presently does hackery to work with Special:Upload page...
+will be replaced with upload API once that is ready
+*/
+
+loadGM({ 
+    "upload-enable-converter" : "Enable video converter (to upload source video not yet converted to theora format) <a href=\"http://commons.wikimedia.org/wiki/Commons:Firefogg\">more info</a>",
+    "upload-fogg_not_installed": "If you want to upload video consider installing <a href=\"http://firefogg.org\">firefogg.org</a>, <a href=\"http://commons.wikimedia.org/wiki/Commons:Firefogg\">more info</a>",
+    "upload-transcode-in-progress":"Doing Transcode & Upload (do not close this window)",
+    "upload-in-progress": "Upload in Progress (do not close this window)",
+    "upload-transcoded-status": "Transcoded",
+    "uploaded-status": "Uploaded",
+    "upload-select-file": "Select File...",    
+    "wgfogg_wrong_version": "You have firefogg installed but its outdated, <a href=\"http://firefogg.org\">please upgrade</a> ",
+    "wgfogg_waring_ogg_upload": "You have selected an ogg file for conversion to ogg (this is probably unnessesary). Maybe disable the video converter?",
+    "wgfogg_waring_bad_extension" : "You have selected a file with an unsuported extension. <a href=\"http://commons.wikimedia.org/wiki/Commons:Firefogg#Supported_File_Types\">More help</a>",
+    "upload-stats-fileprogres": "$1 of $2",
+    
+    "mv_upload_done"       : "Your upload <i>should be</i> accessible <a href=\"$1\">here</a>",
+    "upload-unknown-size": "Unknown size",    
+    
+    "successfulupload" : "Successful upload",
+    "uploaderror" : "Upload error",
+    "uploadwarning": "Upload warning",
+    "unknown-error": "Unknown Error",
+    "return-to-form": "Return to form",
+    
+    "file-exists-duplicate" : "This file is a duplicate of the following file",
+    "fileexists" : "A file with this name exists already, please check <b><tt>$1</tt></b> if you are not sure if you want to change it.",
+    "fileexists-thumb": "<center><b>Existing file</b></center>",
+    "ignorewarning" : "Ignore warning and save file anyway",
+    "file-thumbnail-no" :  "The filename begins with <b><tt>$1</tt></b>"    
+});
+
+var default_upload_options = {
+    'target_div':'',
+    'upload_done_action':'redirect',
+    'api_url':false
+}
+
+var mediaWikiUploadHelper = function(iObj){
+    return this.init( iObj );
+}
+mediaWikiUploadHelper.prototype = {
+    init:function( iObj ){
+        var _this = this;    
+        js_log('init uploader');
+        if(!iObj)
+            iObj = {};
+        for(var i in default_upload_options){
+            if(iObj[i]){
+                this[i] = iObj[i];
+            }else{
+                this[i] = default_upload_options[i];
+            }
+        }
+        //check if we are on the uplaod page: 
+        this.on_upload_page = ( wgPageName== "Special:Upload")?true:false;                    
+        js_log('f:mvUploader: onuppage:' + this.on_upload_page);
+        //grab firefogg.js: 
+        mvJsLoader.doLoad([
+                'mvFirefogg'
+            ],function(){
+                //if we are not on the upload page grab the upload html via ajax:
+                //@@todo refactor with         
+                if( !_this.on_upload_page){                    
+                    $j.get(wgArticlePath.replace(/\$1/, 'Special:Upload'), {}, function(data){
+                        //add upload.js: 
+                        $j.getScript( stylepath + '/common/upload.js', function(){     
+                            //really _really_ need an "upload api"!
+                            wgAjaxUploadDestCheck = true;
+                            wgAjaxLicensePreview = false;
+                            wgUploadAutoFill = true;                                    
+                            //strip out inline scripts:
+                            sp = data.indexOf('<div id="content">');
+                            se = data.indexOf('<!-- end content -->');    
+                            if(sp!=-1 && se !=-1){        
+                                result_data = data.substr(sp, (se-sp) ).replace('/\<script\s.*?\<\/script\>/gi',' ');
+                                js_log("trying to set: " + result_data );                                                                            
+                                //$j('#'+_this.target_div).html( result_data );
+                            }                        
+                            _this.setupFirefogg();
+                        });    
+                    });                
+                }else{
+                    //@@could check if firefogg is enabled here: 
+                    _this.setupFirefogg();            
+                    //if only want httpUploadFrom help enable it here:         
+                }                            
+            }
+        );
+    },
+    /**
+     * setupBaseUpInterface supports intefaces for progress indication if the browser supports it
+     * also sets up ajax progress updates for http posts
+     * //pre
+     */     
+    setupBaseUpInterface:function(){    
+        //check if this feature is not false (we want it on by default (null) instances that don't have the upload api or any modifications)              
+        this.upForm = new mvBaseUploadInterface( {
+                'api_url' : this.api_url,
+                'parent_uploader': this
+            } 
+        );        
+        this.upForm.setupForm();        
+    },
+    setupFirefogg:function(){
+        var _this = this;
+        //add firefogg html if not already there: ( same as $wgEnableFirebug added in SpecialUpload.php )  
+        if( $j('#fogg-video-file').length==0 ){
+            js_log('add addFirefoggHtml');
+            _this.addFirefoggHtml();
+        }else{
+            js_log('firefogg already init:');                    
+        }    
+        //set up the upload_done action 
+        //redirect if we are on the upload page  
+        //do a callback if in called from gui) 
+        var intFirefoggObj = ( this.on_upload_page )? 
+                {'upload_done_action':'redirect'}:
+                {'upload_done_action':function( rTitle ){
+                        js_log( 'add_done_action callback for uploader' );
+                        //call the parent insert resource preview    
+                        _this.upload_done_action( rTitle );        
+                    }
+                };
+                
+        if( _this.api_url )
+            intFirefoggObj['api_url'] =  _this.api_url;
+        
+        js_log('new mvFirefogg  extends mvUploader (this)');        
+        this.fogg = new mvFirefogg( intFirefoggObj );        
+        this.fogg.setupForm();                    
+    },
+    //same add code as specialUpload if($wgEnableFirefogg){
+    addFirefoggHtml:function(){        
+        var itd_html = $j('#mw-upload-table .mw-input:first').html();            
+        $j('#mw-upload-table .mw-input').eq(0).html('<div id="wg-base-upload">' + itd_html + '</div>');
+        //add in firefogg control            
+        $j('#wg-base-upload').after('<p id="fogg-enable-item" >' + 
+            '<input style="display:none" id="fogg-video-file" name="fogg-video-file" type="button" value="' + gM('upload-select-file') + '">' +
+            "<span id='wgfogg_not_installed'>" + 
+                gM('upload-fogg_not_installed') +
+            "</span>" +
+            "<span class='error' id='wgfogg_wrong_version'  style='display:none;'><br>" +
+                gM('wgfogg_wrong_version') +
+            "<br>" +
+            "</span>" +
+            "<span class='error' id='wgfogg_waring_ogg_upload' style='display:none;'><br>"+
+                gM('wgfogg_waring_ogg_upload') +
+            "<br>" +
+            "</span>" + 
+            "<span class='error' id='wgfogg_waring_bad_extension' style='display:none;'><br>"+
+                gM('wgfogg_waring_bad_extension') +                         
+            "<br>" +
+            "</span>" +  
+            "<span id='wgfogg_installed' style='display:none' >"+
+                '<input id="wgEnableFirefogg" type="checkbox" name="wgEnableFirefogg" >' +                             
+                    gM('upload-enable-converter') +
+            '</span><br></p>');                    
+    },
+
+};
diff --git a/js2/mwEmbed/libAddMedia/mvAdvFirefogg.js b/js2/mwEmbed/libAddMedia/mvAdvFirefogg.js
new file mode 100644 (file)
index 0000000..410a996
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+* Adds advanced firefogg support (let you control and structure advanced controls over many aspects of video encoding)  
+*/
+
+//@@todo put all msg text into loadGM json
+
+loadGM({
+       "help-sticky": "Help (Click to Keep Help on Screen)",
+       "fogg-cg-preset": "Preset: <strong>$1</strong>",
+       "fogg-cg-quality": "Basic Quality and Resolution Control",
+       "fogg-cg-meta": "Meta Data for the Clip",
+       "fogg-cg-advVideo": "Advanced Video Encoding Controls",
+       "fogg-cg-advAudio": "Advanced Audio Encoding Controls",
+       "fogg-preset-custom": "Custom Settings"
+       
+});
+
+var mvAdvFirefogg = function( iObj ){
+       return this.init( iObj );
+}
+var default_mvAdvFirefogg_config = {
+       //which config groups to include
+       'config_groups'  : ['preset', 'quality', 'meta', 'advVideo', 'advAudio'],
+       
+       //if you want to load any custom presets must follow the mvAdvFirefogg.presetConf json outline below
+       'custom_presets'        : {}, 
+       
+       //any firefog config properties that may need to be excluded from options
+       'exclude_settings' : [],
+       
+       //the control container (where we put all the controls)                          
+       'target_control_container':false
+}
+
+mvAdvFirefogg.prototype = {    
+       //the global groupings and titles for for configuration options : 
+       config_groups : [ 'preset','quality', 'meta'     ,'advVideo', 'advAudio'],              
+       //list of pre-sets:      
+       //local instance encoder config:
+       default_local_settings:{
+               'd'     : 'webvideo',
+               'type'  : 'select',             
+               'selectVal': ['webvideo'],
+               'group' : "preset",
+               'pSet' : {
+                       'custom':{
+                               'descKey': 'fogg-preset-custom',
+                               'conf': {}
+                       },
+                       'webvideo': {
+                               'desc': "Web Video Theora, Vorbis 400kbs & 400px max width",
+                               'conf': {
+                                               'maxSize': 400, 
+                                               'videoBitrate': 400,
+                                               'noUpscaling':true
+                                       }
+                       }
+               }       
+       }, 
+       local_settings: {},
+       
+       //core firefogg default encoder configuration
+       //see encoder options here: http://www.firefogg.org/dev/index.html
+       default_encoder_config : {              
+               //base quality settings:
+               'videoQuality': { 
+                       'd'                     : 5,
+                       't'                     : 'Video Quality',
+                       'range'  : {'min':0,'max':10},
+                       'type'           : 'slider',
+                       'group'         : 'quality',
+                       'help'           : "Used to set the <i>Visual Quality</i> of the encoded video. (not used if you set bitrate in advanced controls below)"
+               },
+               'audioQuality': {
+                       'd'                     : 1,
+                       't'                     : 'Audio Quality',
+                       'range'  : {'min':-1,'max':10},
+                       'type'    : 'slider',
+                       'group'  : 'quality',
+                       'help'    : "Used to set the <i>Acoustic Quality</i> of the encoded audio. (not used if you set bitrate in advanced controls below)"
+               },
+               'videoCodec':{
+                       'd'                     : "theora",
+                       't'                     : 'Video Codec',
+                       'selectVal'     : ['theora'],
+                       'type'          : "select",
+                       'group'         : "quality",
+                       'help'    : "Used to select the clip video codec. Presently only Theora is supported. More about the <a href=\"http://www.theora.org/\">theora codec</a> "
+               },
+               'audioCodec':{
+                       'd'                     : "vorbis",
+                       't'                     : 'Audio Codec',
+                       'selectVal'     : ['vorbis'],
+                       'type'          : "select",
+                       'group'         : "quality",
+                       'help'    : "Used to set the clip audio codec. Presently only Vorbis is supported. More about the <a href=\"http://www.vorbis.com//\">vorbis codec</a> "
+               },
+               'width': {
+                       't'                     : 'Video Width',
+                       'range'  : {'min':0,'max':1080},
+                       'step'          : 4,
+                       'type'    : 'slider',                   
+                       'group'  : "quality",
+                       'help'          : "Resize to given width."
+               },
+               'height': {
+                       't'                     : 'Video Height',
+                       'range'  : {'min':0,'max':1080},
+                       'step'          : 4,
+                       'type'          : "slider",                                             
+                       'group'         : "quality",
+                       'help'          : "Resize to given height"
+               },                              
+               //advanced Video control configs:
+               'videoBitrate':{
+                       't'                     : 'Video Bitrate',
+                       'range'         : {'min':1, 'max':16778},                       
+                       'type'          : "slider",
+                       'group'         : "advVideo",
+                       'help'          : "Video Bitrate sets the encoding bitrate for video in (kb/s)"                 
+               } ,
+               'framerate':{
+                       't'                     : 'Framerate',
+                       'd'                     : '24',
+                       'selectVal'     : ['12', '16', {'24000:1001':'23.97'}, '24', '25', {'30000:1001':'29.97'}, '30'],
+                       'type'             : "select",
+                       'group'         : "advVideo",
+                       'help'             : "The video Framerate. More about <a target=\"_new\" href=\"http://en.wikipedia.org/wiki/Frame_rate\">Framerate</a>"
+               },              
+               'aspect':{
+                       't'                     : 'Aspect Ratio',
+                       'd'                     : '4:3',
+                       'type'          : "select",     
+                       'selectVal'     : ['4:3', '16:9'],
+                       'group'         : "advVideo",
+                       'help'          : "The video aspect ratio can be fraction 4:3 or 16:9. More about <a target=\"_new\" href=\"http://en.wikipedia.org/wiki/Aspect_ratio_%28image%29\">aspect ratios</a>"
+               },
+               'keyframeInterval':{
+                       'd'                     : '64',
+                       't'                     : 'Key Frame Interval',
+                       'range'  : {'min':0,'max':65536},
+                       'numberType': 'force keyframe every $1 frames',
+                       'type'           : 'int',
+                       'group'         : 'advVideo',
+                       'help'          : "The keyframe interval in frames. Note: Most codecs force keyframes if the difference between frames is greater than keyframe encode size. More about <a href=\"http://en.wikipedia.org/wiki/I-frame\">keyframes</a>"
+               },
+               'denoise':{     
+                       'type'          : "boolean",
+                       't'                     : "Denoise Filter",
+                       'group'         : 'advVideo',
+                       'help'          : "Denoise input video. More about <a target=\"_new\" href=\"http://en.wikipedia.org/wiki/Video_denoising\">denoise</a>"
+               },
+               'novideo':{
+                       't'                     : "No Video",
+                       'type'          : "boolean",
+                       'group'         : 'advVideo',
+                       'help'          : "disable video in the output"
+               },
+       
+               //advanced Audio control Config: 
+               'audioBitrate':{
+                       't'                     : "Audio Bitrate",
+                       'range'         : {'min':32,'max':500},
+                       'numberType': '$1 kbs',
+                       'type'          : 'slider',
+                       'group'         : 'advAudio'
+               },
+               'samplerate':{
+                       't'             : "Audio Sample Rate",
+                       'type'          : 'select',
+                       'selectVal'     : [{'22050':'22 kHz'}, {'44100':'44 khz'}, {'48000':'48 khz'}],
+                       'formatSelect'  : function(val){
+                                                       return (Math.round(val/100)*10) + ' Hz';
+                                               },
+                       'help'          : "set output samplerate (in Hz)."
+               },
+               'noaudio':{
+                       't'             : "No Audio",           
+                       'type'          : 'boolean',
+                       'group'         : 'advAudio',
+                       'help'          : "disable audio in the output"
+               },
+       
+               //meta tags:
+               'title':{
+                       't'     : "Title",
+                       'type'  : 'string',
+                       'group' : 'meta',
+                       'help'  : "A title for your clip"
+               },
+               'artist':{
+                       't'     : "Artist Name",
+                       'type'  : 'string',
+                       'group' : 'meta',
+                       'help'  : "The artist that created this clip"
+               },
+               'date':{
+                       't'     : "Date",
+                       'group' : 'meta',
+                       'type'  : 'date',
+                       'help'  : "The date the footage was created or released"
+               },
+               'location':{
+                       't'     : "Location",
+                       'type'  : 'string',
+                       'group' : 'meta',
+                       'help'  : "The location of the footage"
+               },
+               'organization':{
+                       't'     : "Organization",
+                       'type'  : 'string',
+                       'group' : 'meta',
+                       'help'  : "Name of organization (studio)"
+               },
+               'copyright':{
+                       't'     : "Copyright",
+                       'type'  : 'string',
+                       'group' : 'meta',
+                       'help'  : "The Copyright of the clip"
+               },
+               'license':{
+                       't'        : "License",
+                       'type'  : 'string',
+                       'group'   : 'meta',
+                       'help'  : "The license of the clip (preferably a creative commons url)"
+               },
+               'contact':{
+                       't'     : "Contact",
+                       'type'  : 'string',
+                       'group' : 'meta',
+                       'help'  : "Contact link"
+               }
+       },
+       init:function( iObj ){                          
+               //setup a "supported" iObj:
+               for(var i in iObj){
+                       if( typeof default_mvAdvFirefogg_config [i] != 'undefined' ){
+                               this[i] = iObj[i];                              
+                       }                       
+               }
+               //inherit the base mvFirefogg class: 
+               var myFogg = new mvFirefogg( iObj );
+               for(var i in myFogg){
+                       if( typeof this[i] != 'undefined'){
+                               this[ 'basefogg_' + i ] = myFogg[i];
+                       }else{
+                               this[ i ] = myFogg[i];
+                       }
+               }               
+       },
+       setupForm:function(){
+               //call base firefogg form setup         
+               basefogg_setupForm();           
+                       
+               //gennerate the control html
+               this.doControlHTML();                                           
+               
+               //setup control bindings: 
+               this.doControlBindings();               
+               
+       },
+       doControlHTML: function(){
+               js_log("adv doControlHTML");
+               var _this = this;
+               //load presets from cookie: 
+               this.loadEncSettings();
+               
+               //add base control buttons:              
+               this.basefogg_doControlHTML();
+               
+               //build the config group outpouts 
+               var gdout ='';
+               $j.each(this.config_groups, function(inx, group_key){
+                       gdout+= '<div> '+
+                               '<h3><a href="#" class="gd_'+group_key+'" >' + gM('fogg-cg-'+group_key) + '</a></h3>'+
+                                       '<div>';
+                       //output that group control options:
+                       gdout+='<table width="' + ($j(_this.selector).width()-60) + '" ><tr><td width="35%"></td><td width="65%"></td></tr>';
+                       //output the special prset output
+                       if(group_key=='preset'){
+                               gdout += _this.proccessPresetControl();
+                       }                        
+                       for(var cK in _this.default_encoder_config){                            
+                               var cConf = _this.default_encoder_config[cK];
+                               if(cConf.group == group_key){
+                                       gdout+= _this.proccessCkControlHTML( cK );                                                      
+                               }
+                       }
+                       gdout+='</table>';
+                       gdout+=         '</div>' + 
+                                '</div>';
+       
+               });             
+               //add the control container:  
+               if(!this.target_control_container){                     
+                       this.target_control_container = this.selector + ' .control_container';
+                       //set the target contorl container to height
+                       $j(this.selector).append( '<p><div class="control_container"></div>' ); 
+               }
+               //hide the container and add the output
+               $j(this.target_control_container).hide();
+               $j(this.target_control_container).html( gdout );
+                               
+       },
+       //custom advanced target rewrites: 
+       getTargetHtml:function(target){         
+               if(     target=='target_btn_select_file' || 
+                       target=='target_btn_select_new_file'||
+                       target=='target_btn_save_local_file'){
+                       var icon = (target=='target_btn_save_local_file')?'ui-icon-video':'ui-icon-folder-open';
+                       return   '<a class="ui-state-default ui-corner-all ui-icon_link '+
+                                               target +'" href="#"><span class="ui-icon ' + icon + '"/>' + 
+                                               gM( 'fogg-' + target.substring(11) ) +
+                                       '</a>';
+               }else if(       target=='target_use_latest_fox' || 
+                                       target=='target_please_install' || 
+                                       target == 'target_passthrough_mode'){
+                       return '<div style="margin-top:1em;padding: 0pt 0.7em;" class="ui-state-error ui-corner-all ' +
+                                       target + '">' + 
+                                       '<p><span style="float: left; margin-right: 0.3em;" class="ui-icon ui-icon-alert"/>'+ 
+                                       gM( 'fogg-' + target.substring(7)) +'</p>'+
+                               '</div>';       
+               }else if( target == 'target_input_file_name'){
+                       return '<input style="" class="text ui-widget-content ui-corner-all ' + target + '" '+
+                                       'type="text" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
+               }else{
+                       js_log('call : basefogg_getTargetHtml');
+                       return this.basefogg_getTargetHtml(target);
+               }
+       },
+       proccessPresetControl:function(){ 
+               var out='';
+               var _this = this;
+               js_log('proccessPresetControl::');              
+               if(typeof this.local_settings.pSet!= 'undefined' ){
+                       out+= '<select class="_preset_select">';                        
+                       $j.each(this.local_settings.pSet, function(pKey, pSet){
+                               var pDesc = (pSet.descKey) ? gM(pSet.descKey) : pSet.desc;
+                               var sel = (_this.local_settings.d == pKey)?' selected':'';                                      
+                               out+='<option value="'+pKey+'" '+sel+'>'+ pDesc+'</option>';                    
+                       });
+                       out+='</select>';
+                       }
+               return out;
+       },
+       proccessCkControlHTML:function( cK ){
+               var cConf =  this.default_encoder_config[cK];
+               var out ='';
+               out+='<tr><td valign="top">'+
+                       '<label for="_' + cK + '">' +                                   
+                        cConf.t + ':' + 
+                        '<span title="' + gM('help-sticky') + '" class="help_'+ cK + ' ui-icon ui-icon-info" style="float:left"></span>'+
+                        '</label></td><td>';
+               //if we don't value for this: 
+               var dv = ( this.default_encoder_config[cK].d ) ? this.default_encoder_config[cK].d : '';                
+               //switch on the config type
+               switch( cConf.type ){                                   
+                       case 'string':
+                       case 'date':
+                       case 'int':
+                               out+= '<input type="text" class="_' + cK + ' text ui-widget-content ui-corner-all" value="' + dv + '" >' ;
+                       break;
+                       case 'boolean':
+                               var checked_attr = (dv===true)?' checked="true"':'';
+                               out+='<input type="checkbox" class="_'+cK+ ' ui-widget-content ui-corner-all" ' + checked_attr + '>';
+                       break;
+                       case 'slider':  
+                               var strMax = this.default_encoder_config[ cK ].range.max + '';                  
+                               maxdigits = strMax.length +1;
+                               out+= '<input type="text" maxlength="'+maxdigits+'" size="' +maxdigits + '" '+          
+                                       'class="_'+cK+ ' text ui-widget-content ui-corner-all" style="display:inline;border:0; color:#f6931f; font-weight:bold;" ' + 
+                                       'value="' + dv + '" >' +                                                                
+                                       '<div class="slider_' + cK + '"></div>';
+                       break;
+                       case 'select':
+                               out+= '<select class="_' + cK + '">'+
+                                               '<option value=""> </option>';                                          
+                               for(var i in cConf.selectVal){                          
+                                       var val = cConf.selectVal[i];
+                                       if(typeof val == 'string'){     
+                                               var sel = (     cConf.selectVal[i] == val)?' selected':'';                                                                      
+                                               out+= '<option value="'+val+'"'+sel+'>'+val+'</option>';
+                                       }else if(typeof val == 'object'){
+                                               for(var key in val){
+                                                       hr_val = val[key];
+                                               }
+                                               var sel = ( cConf.selectVal[i] == key )?' selected':''; 
+                                                       
+                                               out+= '<option value="'+key+'"'+sel+'>'+hr_val+'</option>';
+                                       }
+                               }
+                               out+='</select>';
+                       break;
+               }
+               //output the help row:
+               if(cConf.help){
+                       out+='<div class="helpRow_' + cK + '">'+
+                                       '<span class="helpClose_' + cK + ' ui-icon ui-icon-circle-close" '+ 
+                                       'title="Close Help"'+
+                                       'style="float:left"/>'+
+                                cConf.help +
+                                '</div>';
+               }
+               out+='</td></tr><tr><td colspan="2" height="10"></td></tr>';
+               return out;
+       },       
+       doControlBindings:function(){
+               var _this = this;
+               _this.basefogg_doControlBindings();
+               //hide the base advanced controls untill a file is selected:
+               $j(this.target_control_container).hide();
+               
+               var helpState = {};
+               //do some display tweeks:                        
+               js_log('tw:' + $j(this.selector).width() + 
+                               'ssf:' + $j(this.target_btn_select_new_file).width() + 
+                               'sf:' +  $j(this.target_btn_save_local_file).width() );
+               
+               //set width to 250
+               $j(this.target_input_file_name).width( 250 );
+               
+               //special preset action: 
+               $j(this.selector + ' ._preset_select').change(function(){
+                       _this.updatePresetSelection( $j(this).val() );
+               });
+               
+               //bind control actions
+               for(var cK in this.default_encoder_config){
+                       var cConf =  this.default_encoder_config[cK];
+                       //set up the help for all types: 
+                       if(cConf.help){
+                               //initial state is hidden: 
+                               $j( this.selector + ' .helpRow_' + cK).hide();          
+                               $j(this.selector + ' .help_' + cK).click(function(){                                    
+                                       //get the ckId (assume its the last class)
+                                       var cK = _this.getClassId(this, 'help_'); 
+                                                                       
+                                       if(helpState[cK]){
+                                               $j(_this.selector + ' .helpRow_' + cK).hide('slow');
+                                               helpState[cK] = false;
+                                       }else{                                                  
+                                               $j(_this.selector + ' .helpRow_' + cK).show('slow');
+                                               helpState[cK] = true;
+                                       }                                       
+                                       return false;           
+                               }).hover(
+                                       function(){                                       
+                                               //get the ckId (assume its the last class)
+                                               var cK = _this.getClassId(this, 'help_');                                                       
+                                               $j( _this.selector + ' .helpRow_' + cK).show('slow');
+                                       },function(){
+                                               var cK = _this.getClassId(this, 'help_'); 
+                                               if(!helpState[cK])                                              
+                                                       $j( _this.selector + ' .helpRow_' + cK).hide('slow')                                            
+                                       }
+                               );
+                               $j( _this.selector + ' .helpClose_' + cK).click(function(){
+                                       js_log("close help: " +cK);                        
+                                       //get the ckId (assume its the last class)
+                                       var cK = _this.getClassId(this, 'helpClose_');
+                                       $j(_this.selector + ' .helpRow_' + cK).hide('slow');                    
+                                       helpState[cK] = false;  
+                                       return false;
+                               }).css('cursor', 'pointer');
+                       }else{
+                               $j(this.selector + ' .help_' + cK).hide();
+                       }
+                       
+                       //setup bindings for change values: (validate input)             
+                       
+                       switch( cConf.type ){   
+                               case 'boolean':
+                                       $j(_this.selector + ' ._'+cK).click(function(){
+                                               _this.updateLocalValue(  _this.getClassId(this), $j(this).is(":checked") );
+                                       })
+                               break;
+                               case 'select':
+                               case 'string':
+                                       //@@check if we have a validate function on the string
+                                       $j(_this.selector + ' ._'+cK).change(function(){                                                                
+                                               $j(this).val( _this.updateLocalValue(
+                                                       _this.getClassId(this), 
+                                                       $j(this).val() ));
+                                               _this.updatePresetSelection('custom');
+                                       })
+                               break;
+                               case 'date':
+                                       $j(_this.selector + ' ._'+cK).datepicker({
+                                                       changeMonth: true,
+                                                       changeYear: true,
+                                                       dateFormat: 'd MM, yy',   
+                                                       onSelect: function(dateText) {
+                                                               _this.updateInterfaceValue(_this.getClassId(this), dateText);           
+                                                       }
+                                       });                             
+                               break;
+                               case 'slider':                                                                          
+                                       $j(this.selector + ' .slider_' + cK ).slider({
+                                               range: "min",
+                                               animate: true,
+                                               step: (cConf.step)?cConf.step:1,
+                                               value: $j( this.selector +' ._' + cK ).val(),
+                                               min: this.default_encoder_config[ cK ].range.min,
+                                               max: this.default_encoder_config[ cK ].range.max,
+                                               slide: function(event, ui) {                                                            
+                                                       $j( _this.selector + ' ._' + _this.getClassId(this, 'slider_') ).val( ui.value );
+                                                       
+                                                       //maintain source video aspect ratio:  
+                                                       if(_this.getClassId(this, 'slider_') == 'width'){                                                                                                                                                                                                                                                               
+                                                               var hv = parseInt((_this.sourceFileInfo['height']/_this.sourceFileInfo['width'])* ui.value );
+                                                               //update the height value:        the new hight value is > that orginal the slider: 
+                                                               if(hv > _this.updateInterfaceValue('height', hv))
+                                                                       return false;                                                                                                                                                                                   
+                                                       }
+                                                       if(_this.getClassId(this, 'slider_') == 'height'){
+                                                               var wv = parseInt((_this.sourceFileInfo['width']/_this.sourceFileInfo['height'])* ui.value );
+                                                               //update the height value:        the new hight value is > that orginal the slider: 
+                                                               if(wv > _this.updateInterfaceValue('width', wv))
+                                                                       return false;   
+                                                       }
+                                               },
+                                               change: function(event, ui){                                                                                                    
+                                                       //update the local settings
+                                                       _this.updateLocalValue( _this.getClassId(this, 'slider_'), ui.value);           
+                                                       _this.updatePresetSelection('custom');                                                                          
+                                               }                                       
+                                       })
+                                       $j( this.selector +' ._' + cK).change(function(){       
+                                               var scid = _this.getClassId(this);      
+                                               var valdVal = _this.updateLocalValue(scid.substr(1),$j(this).val() );           
+                                               _this.updatePresetSelection('custom');
+                                               //(validate user form input) 
+                                               $j(this).val(valdVal);
+                                               //update the slider
+                                               js_log("update: " + _this.selector + ' .slider' + scid);
+                                               $j(_this.selector + ' .slider'+ scid).slider('option', 'value', valdVal );                                              
+                                       });                                                                                                                                                             
+                               break           
+                       }
+               }       
+               $j(this.target_control_container).accordion({ 
+                       header: "h3",
+                       collapsible: true, 
+                       active: false,
+                       fillSpace: true
+               });             
+               
+               //do config value updates if any
+               this.updateValuesInHtml();
+       },
+       updatePresetSelection:function( pKey ){
+               //update the local key:
+               this.local_settings.d = pKey;   
+                //js_log('update preset desc: '+ pKey);
+               var pset_desc = '';
+               if(this.local_settings.pSet[ pKey  ].desc){
+                       pset_desc = this.local_settings.pSet[ pKey  ].desc;
+               }else{
+                       pset_desc = gM('fogg-preset-'+ pKey);
+               }
+               //update the preset title:              
+               $j( this.selector + ' .gd_preset' ).html( 
+                       gM('fogg-cg-preset', pset_desc) 
+               );
+               //update the selector
+               $j(this.selector + ' ._preset_select').val(pKey);
+       },
+       /*
+        * updates the interface 
+        */
+       updateInterfaceValue:function(confKey, val){
+               var _this = this;
+               if(!val){
+                       return ;
+               }
+               //js_log('updateInterfaceValue:: ' + confKey + ' v:' + val + ' cv:'+ _this.selector + '._'+ confKey+' len:' + $j(_this.selector + ' ._'+confKey).length );
+               //lookup the type
+               if(typeof this.default_encoder_config[confKey] == 'undefined'){
+                       js_error('error: missing default key: '+ confKey);
+                       return false;
+               }
+                       
+               //update the local value (if not already up-to-date
+               if( this.local_settings.pSet['custom']['conf'][confKey] != val ){
+                       val = this.updateLocalValue(confKey, val);
+               }
+               //update the text filed:
+               $j(_this.selector + ' ._'+confKey).val( val );
+               //update the interaface widget:
+               switch(this.default_encoder_config[confKey].type){
+                       case 'slider':
+                               $j(_this.selector + ' .slider_' + confKey).slider('option', 
+                                               'value', $j(_this.selector + ' ._'+ confKey).val() );
+                       break;
+               }                                       
+               return val;                                     
+       },
+       updateLocalValue:function(confKey, value){      
+               //update the local value (return the value we acutally set)     
+               if(typeof this.default_encoder_config[confKey] == 'undefined'){
+                 js_log("Error:could not update conf key:" + confKey)
+                 return value;
+               }
+               dec = this.default_encoder_config[confKey];
+               if(dec.range){
+                       value = parseInt(value);
+                       var min = ( dec.range.local_min) ? dec.range.local_min  :dec.range.min;
+                       if(value < min)                 
+                               value = min;
+                       var max = ( dec.range.local_max) ? dec.range.local_max : dec.range.max
+                       if(value > max)
+                               value = max;
+               }                       
+               if(dec.type=='int')
+                       value = parseInt(value);
+               
+               //step value: 
+               /*if(dec.step){
+                       if((value % dec.step)!=0){
+                               value = value - (value % dec.step);
+                       }
+               }*/   
+               
+               js_log('update:local_settings:custom:conf:'+ confKey + ' = ' + value); 
+               this.local_settings.pSet['custom']['conf'][confKey] = value;                                            
+               
+               return value;                   
+       },      
+       getLocalValue:function(confKey){
+               return this.local_settings.pSet['custom']['conf'][confKey];
+       },
+       getClassId:function(elm, rmstr){
+               var elmclass = $j(elm).attr("class").split(' ').slice(0,1).toString();
+               if(rmstr){
+                       return elmclass.replace( rmstr, '' );
+               }else{
+                       //strip leading underscore:
+                       return (elmclass[0]=='_')?elmclass.substr(1):elmclass;
+               }               
+       },
+       /*
+        * sets up the autoEncoder settings
+        */     
+       autoEncoderSettings:function(){
+               var _this = this;
+               //do the base encoder settings setup: 
+               this.basefogg_autoEncoderSettings();            
+               //make sure we are "encoding" if not display not a video file eror:
+               if( this.encoder_settings['passthrough'] ){
+                       js_log("in passthrough mode (hide control)");
+                       //hide all controls 
+                       //dispaly not encodable video 
+                       $j(this.target_control_container).hide('slow');
+                       $j(this.target_passthrough_mode).show('slow');
+                       return ;                        
+               }
+               //restore display: 
+               $j(this.target_control_container).show('slow');
+               $j(this.target_passthrough_mode).hide('slow');
+               
+               //do setup settings based on local_settings /default_encoder_config with sourceFileInfo
+               //see: http://firefogg.org/dev/sourceInfo_example.html          
+               for(var i in this.sourceFileInfo){                      
+                       var val = this.sourceFileInfo[i];
+                       var k = false;
+                       var maxVal= false;
+                       switch(i){
+                               //do nothing with these:                                
+                               case 'bitrate': 
+                                       k = 'videoBitrate'; 
+                                       maxVal = (val*2 > this.default_encoder_config[k])?this.default_encoder_config[k]:val*2;
+                               break;  
+                               case 'audio_bitrate': 
+                                       k = 'audioBitrate'; 
+                                       maxVal = (val*2 > this.default_encoder_config[k])?this.default_encoder_config[k]:val*2;
+                               break;                                                          
+                               case 'width': 
+                                       k = 'width';
+                                       maxVal = val;                                                                   
+                               break;                  
+                               case 'height': 
+                                       k = 'height';
+                                       maxVal = val; 
+                               break;                                          
+                       }                       
+                       if( k !== false){
+                               //update the value if unset: 
+                               _this.updateLocalValue(k, val);                                                                                                            
+                       }
+                       if( maxVal ){
+                                //update the local range:
+                               if(this.default_encoder_config[k].range){
+                                       this.default_encoder_config[k].range.local_max = maxVal;
+                               }       
+                       }
+               }                                       
+               //set all values to new default ranges & update slider: 
+               $j.each(this.default_encoder_config, function(inx, val){
+                       if($j(_this.selector + ' ._'+inx).length!=0){
+                               if(typeof val.range != 'undefined'){                                    
+                                       //udate slider range
+                                       var new_max = (val.range.local_max)?val.range.local_max: val.range.max
+                                       $j( _this.selector + ' .slider_'+inx).slider('option', 'max', new_max);
+                                                                               
+                                       //update slider/input value:
+                                       _this.updateInterfaceValue(inx, _this.local_settings.pSet['custom']['conf'][inx]);                                                      
+                               }
+                       }
+               });
+               //update values
+               this.updateValuesInHtml();
+       },
+       doEncode:function(){
+               //update the encoder settings (from local settings)
+               pKey = this.local_settings.d;           
+               this.encoder_settings = this.local_settings.pSet[ pKey ].conf;          
+               this.basefogg_doEncode();
+       },      
+       updateValuesInHtml:function(){
+               js_log('updateValuesInHtml::');
+               var _this = this;               
+               var pKey = this.local_settings.d;               
+               this.updatePresetSelection( pKey );                                                             
+                               
+               //set the actual HTML & widgets based on any local settings values:             
+               $j.each(_this.local_settings.pSet['custom']['conf'], function(inx, val){                                                
+                       if($j(_this.selector + ' ._'+inx).length !=0){
+                               $j(_this.selector + ' ._'+inx).val( val );                              
+                       }
+               });
+       },
+       //restors settings from a cookie if you have them)
+       loadEncSettings:function( force ){              
+               if($j.cookie('fogg_encoder_config')){
+                       js_log("load:fogg_encoder_config from cookie ");                
+                       this.local_settings = JSON.parse( $j.cookie('fogg_settings') );                                 
+               }               
+               //set to default if not loaded yet: 
+               if( this.local_settings &&  this.local_settings.pSet && this.local_settings.pSet['custom']['conf']){
+                       js_log('local settings already populated');
+               }else{                  
+                       this.local_settings  = this.default_local_settings; 
+               }
+                       
+       },
+       //clear preset settings: 
+       clearSettings:function(force){
+               
+       },
+       //save settings to the cookie
+       saveEncSettings:function(){
+               $j.cookie('fogg_settings', JSON.stringify( this.local_settings ) );
+       }
+};
diff --git a/js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js b/js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js
new file mode 100644 (file)
index 0000000..01444ba
--- /dev/null
@@ -0,0 +1,602 @@
+/**
+ * the base Upload Interface for uploading.
+ * 
+ * this base uploader is optionally extended by firefogg
+ */
+loadGM({ 
+       "upload-transcode-in-progress":"Doing Transcode & Upload (do not close this window)",
+       "upload-in-progress": "Upload in Progress (do not close this window)",
+       "upload-transcoded-status": "Transcoded",
+       "uploaded-status": "Uploaded",
+       
+       "wgfogg_wrong_version": "You have firefogg installed but its outdated, <a href=\"http://firefogg.org\">please upgrade</a> ",
+       "upload-stats-fileprogres": "$1 of $2",
+       
+       "mv_upload_completed":  "Your upload is complete",
+       
+       "mv_upload_done"          : "Your upload <i>should be</i> accessible <a href=\"$1\">here</a>",
+       "upload-unknown-size": "Unknown size",  
+       
+       "mv-cancel-confim"       : "Are you sure you want to cancel?",
+       
+       "successfulupload" : "Successful Upload",
+       "uploaderror" : "Upload error",
+       "uploadwarning": "Upload warning",
+       "unknown-error": "Unknown Error",
+       "return-to-form": "Return to form",
+       
+       "file-exists-duplicate" : "This file is a duplicate of the following file",
+       "fileexists" : "A file with this name exists already, please check <b><tt>$1</tt></b> if you are not sure if you want to change it.",
+       "fileexists-thumb": "<center><b>Existing file</b></center>",
+       "ignorewarning" : "Ignore warning and save file anyway",
+       "file-thumbnail-no" :  "The filename begins with <b><tt>$1</tt></b>",
+       "go-to-resource" : "Go to Resource Page",
+
+       "wgfogg_waring_bad_extension" : "You have selected a file with an unsuported extension (<a href=\"http://commons.wikimedia.org/wiki/Commons:Firefogg#Supported_File_Types\">more information</a>).",
+       
+       "cancel-button"  : "Cancel",    
+       "ok-button"       : "OK"
+               
+});
+var default_bui_options = {
+       'api_url':null,
+       'parent_uploader':null,
+       'edit_from':null,
+       'done_upload_cb': null,
+       
+       //upload_mode can be 'post', 'chunks' or autodetect. (autodetect issues an api call)
+       'upload_mode':'autodetect'
+}
+var mvBaseUploadInterface = function( iObj ){
+       return this.init( iObj );
+}
+mvBaseUploadInterface.prototype = {
+       parent_uploader:false,
+       formData:{}, //the form to be submitted    
+       warnings_sessionkey:null,
+       chunks_supported:false,
+       form_post_override:false,
+       action_done:false,
+       //the edit token:
+       etoken:false,
+       init: function( iObj ){
+               if(!iObj)
+                       iObj = {};
+               //inherit iObj properties:
+               for(var i in default_bui_options){
+                       if(iObj[i]){
+                               this[i] = iObj[i];
+                       }else{
+                               this[i] = default_bui_options[i];
+                       }
+               }               
+       },
+       setupForm:function(){   
+               var _this = this;
+               //set up the local pointer to the edit form:
+               _this.editForm = _this.getEditForm();
+
+               if(_this.editForm){
+                       //set up the org_onsubmit if not set: 
+                       if( typeof( _this.org_onsubmit ) == 'undefined' )
+                               _this.org_onsubmit = _this.editForm.onsubmit;
+                       
+                       //have to define the onsubmit function inline or its hard to pass the "_this" instance
+                       _this.editForm.onsubmit = function(){                                                                   
+                               //run the original onsubmit (if not run yet set flag to avoid excessive chaining ) 
+                               if( typeof( _this.org_onsubmit ) == 'function' ){                                                                                 
+                                       if( ! _this.org_onsubmit() ){
+                                               //error in org submit return false;
+                                               return false;                                   
+                                       }
+                               }                               
+                               //check for post action override:                                                                                                                       
+                               if( _this.form_post_override ){
+                                       //alert('will submit here');
+                                       return true;
+                               }                                                                       
+                               //get the input form data in flat json:                                                                                 
+                               var tmpAryData = $j( _this.editForm ).serializeArray();                                 
+                               for(var i=0; i < tmpAryData.length; i++){
+                                       if( tmpAryData[i]['name'] )
+                                               _this.formData[ tmpAryData[i]['name'] ] = tmpAryData[i]['value'];
+                               }                                                       
+                               //put into a try catch so we are sure to return false:          
+                               try{
+                                       //get a clean loader: 
+                                       _this.dispProgressOverlay();                                                                                            
+                                       
+                                       //for some unknown reason we have to drop down the #p-search z-index:
+                                       $j('#p-search').css('z-index', 1);                                                              
+                                       
+                                       //select upload mode:                           
+                                       _this.detectUploadMode();
+                               }catch(e){
+                                       
+                               }
+                                
+                               //don't submit the form we will do the post in ajax
+                               return false;   
+                       };                                                      
+               }
+                                       
+       },      
+       detectUploadMode:function( callback ){
+               var _this = this;               
+               //check the upload mode: 
+               if( _this.upload_mode == 'autodetect' ){
+                       js_log('detectUploadMode::' + _this.upload_mode + ' api:' + _this.api_url);
+                       if( ! _this.api_url )
+                               return js_error( 'Error: can\'t autodetect mode without api url' );
+                       do_api_req( {
+                               'data':{ 'action':'paraminfo','modules':'upload' },
+                               'url' :_this.api_url 
+                       }, function(data){
+                               if( typeof data.paraminfo == 'undefined' || typeof data.paraminfo.modules == 'undefined' )
+                                       return js_error( 'Error: bad api results' );
+                               if( typeof data.paraminfo.modules[0].classname == 'undefined'){
+                                       js_log( 'Autodetect Upload Mode: \'post\' ');
+                                       _this.upload_mode = 'post';
+                               }else{          
+                                       js_log( 'Autodetect Upload Mode: api ' );
+                                       _this.upload_mode = 'api';
+                                       //check to see if chunks are supported:                 
+                                       for( var i in data.paraminfo.modules[0].parameters ){                                           
+                                               var pname = data.paraminfo.modules[0].parameters[i].name;
+                                               if( pname == 'enablechunks' ){
+                                                       js_log( 'this.chunks_supported = true' );
+                                                       _this.chunks_supported = true;                                                  
+                                                       break;
+                                               }
+                                       }                                                                                                                               
+                               }       
+                               js_log("do call: doUploadSwitch");                      
+                               _this.doUploadSwitch();
+                       });
+               }else{
+                       _this.doUploadSwitch();
+               }
+       },
+       doUploadSwitch:function(){              
+               var _this = this;                       
+               js_log('mvUPload:doUploadSwitch():' + _this.upload_mode);                       
+               //issue a normal post request           
+               if( _this.upload_mode == 'post' || //we don't support the upload api
+                       (_this.upload_mode=='api' &&  ( $j('#wpSourceTypeFile').length ==  0 || $j('#wpSourceTypeFile').get(0).checked ) ) // web form uplaod even though we support api                        
+               ){                      
+                       js_log('do original submit form');
+                       //update the status to 100% progress bar: 
+                       $j( '#up-progressbar' ).progressbar('value', parseInt( 100 ) );         
+                                                       
+                       $j('#up-status-container').html( gM('upload-in-progress') );
+                       //do normal post upload no status indicators (also since its a file I think we have to submit the form)
+                       _this.form_post_override = true;
+                       
+                       //trick the browser into thinking the wpUpload button was pressed (there might be a cleaner way to do this)
+                       
+                       $j(_this.editForm).append(
+                               '<input type="hidden" name="wpUpload" value="' + $j('input[name=\'wpUpload\']').val() + '"/>'
+                       );
+                       
+                       //@@todo support firefox 3.0 ajax file upload progress
+                       //http://igstan.blogspot.com/2009/01/pure-javascript-file-upload.html
+                       
+                       //do the submit :                       
+                       _this.editForm.submit();
+                       return true;
+               }else if( _this.upload_mode == 'api' && $j('#wpSourceTypeURL').get(0).checked){ 
+                       js_log('doHttpUpload (no form submit) ');
+                       //if the api is supported.. && source type is http do upload with http status updates
+                       var httpUpConf ={
+                           'url'               : $j('#wpUploadFileURL').val(),
+                           'filename'  : $j('#wpDestFile').val(),
+                           'comment'   : $j('#wpUploadDescription').val()                          
+                       }
+                       //check for editToken
+                       _this.etoken = $j("input[name='wpEditToken']").val();                                           
+                       _this.doHttpUpload( httpUpConf );
+               }else{
+                       js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode );
+               }                               
+               return false;
+       },
+       doHttpUpload:function( opt ){
+               var _this = this;
+               //set the http box to loading (in case we don't get an update for some time) 
+               $j('#dlbox-centered').html( '<h5>' + _this.getProgressTitle() + '</h5>' + 
+                       mv_get_loading_img( 'left:40%;top:20%')
+               );      
+               //setup request:
+               var req = {
+                       'action'                : 'upload',
+                       'asyncdownload' : true  //do a s
+               };
+               //set config from options:
+               for(var i in opt){                      
+                       req[i]= opt[i];
+               }                                               
+                       
+               //else try and get a token:
+               if(!_this.etoken  && _this.api_url){
+                       js_log('Error:doHttpUpload: missing token');
+                       
+               }else{                                  
+                       req['token'] =_this.etoken;
+               }                               
+               //do the api req                
+               do_api_req({
+                       'data': req,
+                       'url' : _this.api_url 
+               }, function( data ){                    
+                       _this.processApiResult( data );         
+               });                             
+       },
+       doAjaxWarningIgnore:function(){
+               var _this = this;
+               if( !_this.upload_session_key )
+                       return js_error('missing upload_session_key (can\'t ignore warnigns');
+               //do the ignore warnings submit to the api:
+               var req = {
+                               'ignorewarnings' : 'true',
+                               'sessionkey'     :!_this.upload_session_key
+                       };
+               //add token if present:                 
+               if(this.etoken)
+                       req['token'] = this.etoken;
+                        
+               do_api_req({
+                       'data':req,
+                       'url': _this.api_url
+               },function(data){
+                       _this.processApiResult(data);
+               });
+       },
+       doAjaxUploadStatus:function() {
+               var _this = this;       
+               
+               //set up the progress display for status updates: 
+               _this.dispProgressOverlay();
+               var req = {
+                                       'action'         : 'upload',
+                                       'httpstatus' : 'true',
+                                       'sessionkey' : _this.upload_session_key
+               };
+               //add token if present:                 
+               if(this.etoken)
+                       req['token'] = this.etoken;
+                       
+               var uploadStatus = function(){
+                       //do the api request: 
+                       do_api_req({
+                               'data':req,
+                               'url' : _this.api_url
+                       }, function( data ){                                                                    
+                               //@@check if we are done
+                               if( data.upload['apiUploadResult'] ){
+                                       //update status to 100%
+                                       _this.updateProgress( 1 );
+                                       if(typeof JSON == 'undefined'){
+                                               //we need to load the jQuery json parser: (older browsers don't have JSON.parse 
+                                               mvJsLoader.doLoad([     
+                                                       '$j.secureEvalJSON'
+                                               ],function(){
+                                                       var  apiResult = $j.secureEvalJSON( data.upload['apiUploadResult'] );
+                                                       _this.processApiResult( apiResult );
+                                               });
+                                       }else{
+                                               var apiResult = {};
+                                               try{
+                                                       apiResult = JSON.parse ( data.upload['apiUploadResult'] ) ;
+                                               }catch (e){
+                                                       //could not parse api result
+                                                       js_log('errro: could not parse apiUploadResult ')                                               
+                                               }
+                                               _this.processApiResult( apiResult );                                            
+                                       }
+                                       return ;                                
+                               }
+                               
+                               //@@ else update status:
+                               if( data.upload['content_length'] &&  data.upload['loaded'] ){
+                                       //we have content length we can show percentage done: 
+                                       var perc =  data.upload['loaded'] / data.upload['content_length'];
+                                       //update the status:
+                                       _this.updateProgress( perc );
+                                       //special case update the file progress where we have data size: 
+                                       $j('#up-status-container').html( 
+                                               gM('upload-stats-fileprogres', [ 
+                                                       formatSize( data.upload['loaded'] ), 
+                                                       formatSize( data.upload['content_length'] )
+                                                       ]  
+                                               )
+                                       );
+                               }else if( data.upload['loaded'] ){              
+                                       _this.updateProgress( 1 );              
+                                       js_log('just have loaded (no cotent length: ' + data.upload['loaded']);
+                                       //for lack of content-length requests: 
+                                       $j('#up-status-container').html( 
+                                               gM('upload-stats-fileprogres', [
+                                                       formatSize( data.upload['loaded'] ),
+                                                       gM('upload-unknown-size')
+                                                       ]
+                                               )
+                                       );
+                               }
+                               //(we got a result) set it to 100ms + your server update interval (in our case 2s)
+                               setTimeout(uploadStatus, 2100);                 
+                       });                     
+               }
+               uploadStatus();
+       },
+       apiUpdateErrorCheck:function( apiRes ){
+               var _this = this;
+               if( apiRes.error || ( apiRes.upload && apiRes.upload.result == "Failure" ) ){
+                       //gennerate the error button:           
+                       var bObj = {};
+                       bObj[ gM('return-to-form') ] =  function(){
+                                       $j(this).dialog('close');
+                        };             
+                        
+                       //@@TODO should be refactored to more specialUpload page type error handling
+                       
+                       //check a few places for the error code: 
+                       var error_code=0;       
+                       var errorReplaceArg='';         
+                       if( apiRes.error && apiRes.error.code ){                                
+                               error_code = apiRes.error.code;
+                       }else if( apiRes.upload.code ){
+                               if(typeof apiRes.upload.code == 'object'){                              
+                                       if(apiRes.upload.code[0]){
+                                               error_code = apiRes.upload.code[0];
+                                       }
+                                       if(apiRes.upload.code['status']){
+                                               error_code = apiRes.upload.code['status'];
+                                               if(apiRes.upload.code['filtered'])
+                                                       errorReplaceArg =apiRes.upload.code['filtered']; 
+                                       }
+                               }else{
+                                       apiRes.upload.code;
+                               }
+                       }       
+                       
+                       var error_msg = '';             
+                       if(typeof apiRes.error == 'string')
+                               error_msg = apiRes.error;               
+                       //error space is too large so we don't front load it
+                       //this upload error space replicates code in: SpecialUpload.php::processUpload()
+                       //would be nice if we refactored that to the upload api.(problem is some need special actions)                  
+                       var error_msg_key = {   
+                               '2' : 'largefileserver',                        
+                               '3' : 'emptyfile',
+                               '4' : 'minlength1',
+                               '5' : 'illegalfilename'                         
+                       };
+                       //@@todo: need to write conditionals that mirror SpecialUpload for handling these error types:  
+                       var error_onlykey = {
+                               '1': 'BEFORE_PROCESSING',
+                               '6': 'PROTECTED_PAGE',
+                               '7': 'OVERWRITE_EXISTING_FILE',
+                               '8': 'FILETYPE_MISSING',
+                               '9': 'FILETYPE_BADTYPE',
+                               '10': 'VERIFICATION_ERROR',
+                               '11': 'UPLOAD_VERIFICATION_ERROR',
+                               '12': 'UPLOAD_WARNING',
+                               '13': 'INTERNAL_ERROR',
+                               '14': 'MIN_LENGHT_PARTNAME'
+                       }                       
+                       //do a remote call to get the error msg:                
+                       if(!error_code || error_code == 'unknown-error'){
+                               if(typeof JSON != 'undefined'){
+                                       js_log('Error: apiRes: ' + JSON.stringify( apiRes) );
+                               }
+                               js_log('should update win::');
+                               _this.updateProgressWin( gM('uploaderror'), gM('unknown-error') + '<br>' + error_msg, bObj );
+                               return false;
+                       }else{
+                               if(apiRes.error && apiRes.error.info ){                                 
+                                       _this.updateProgressWin(  gM('uploaderror'), apiRes.error.info ,bObj);
+                                       return false;
+                               }else{
+                                       if(typeof error_code == 'number' && typeof error_msg_key[error_code] == 'undefined' ){
+                                               if(apiRes.upload.code.finalExt){
+                                                       _this.updateProgressWin(  gM('uploaderror'), gM('wgfogg_waring_bad_extension', apiRes.upload.code.finalExt) , bObj);
+                                               }else{
+                                                       _this.updateProgressWin( gM('uploaderror'), gM('unknown-error') + ' : ' + error_code, bObj);
+                                               }
+                                       }else{
+                                               js_log('get key: ' + error_msg_key[ error_code ])
+                                               gMsgLoadRemote( error_msg_key[ error_code ], function(){                                                                                                
+                                                       _this.updateProgressWin(  gM('uploaderror'), gM(  error_msg_key[ error_code ], errorReplaceArg ), bObj);
+                                               });             
+                                               js_log("api.erorr");            
+                                       }
+                                       return false;   
+                               }
+                       }
+               }                               
+               //check for upload.error type erros.  
+               if( apiRes.upload && apiRes.upload.error){
+                       js_log(' apiRes.upload.error: ' +  apiRes.upload.error );
+                       _this.updateProgressWin( gM('uploaderror'), gM('unknown-error') + '<br>', bObj);
+                       return false;
+               }
+               //check for known warnings: 
+               if(apiRes.upload && apiRes.upload.warnings ){
+                       //debugger;     
+                       var wmsg = '<ul>';
+                       for(var wtype in apiRes.upload.warnings){
+                               var winfo = apiRes.upload.warnings[wtype]
+                               wmsg+='<li>';           
+                               switch(wtype){
+                                       case 'duplicate':
+                                       case 'exists':
+                                               if(winfo[1] && winfo[1].title && winfo[1].title.mTextform){
+                                                       wmsg += gM('file-exists-duplicate') +' '+ 
+                                                                       '<b>' + winfo[1].title.mTextform + '</b>';              
+                                               }else{
+                                                       //misc error (weird that winfo[1] not present
+                                                       wmsg += gM('upload-misc-error') + ' ' + wtype;
+                                               }                                                                                               
+                                       break;
+                                       case 'file-thumbnail-no':
+                                               wmsg += gM('file-thumbnail-no', winfo);
+                                       break;
+                                       default:
+                                               wmsg += gM('upload-misc-error') + ' ' + wtype;
+                                       break;
+                               }                       
+                               wmsg+='</li>';                                                                                                          
+                       }
+                       wmsg+='</ul>';                  
+                       if( apiRes.upload.warnings.sessionkey)
+                               _this.warnings_sessionkey = apiRes.upload.warnings.sessionkey;
+                       var bObj = {};
+                       bObj[ gM('ignorewarning') ] =   function() { 
+                                                                                        js_error('todo: ignore warnings action '); 
+                                                                                       };
+                       _this.updateProgressWin(  gM('uploadwarning'),  '<h3>' + gM('uploadwarning') + '</h3>' +msg + '<p>',bObj);
+                       return false;
+               }                                                       
+               //should be "OK"                
+               return true;    
+       },
+       processApiResult: function( apiRes ){   
+               var _this = this;                       
+               js_log('processApiResult::');
+               //check for upload api error:
+               // {"upload":{"result":"Failure","error":"unknown-error","code":{"status":5,"filtered":"NGC2207%2BIC2163.jpg"}}}
+               if( _this.apiUpdateErrorCheck(apiRes) === false){
+                       //error returned false (updated and 
+                       return false;
+               }else{
+                       //check for upload_session key for async upload:
+                       if( apiRes.upload && apiRes.upload.upload_session_key ){                                                        
+                               //set the session key
+                               _this.upload_session_key = apiRes.upload.upload_session_key;
+                               
+                               //do ajax upload status: 
+                               _this.doAjaxUploadStatus();             
+                               js_log("set upload_session_key: " + _this.upload_session_key);  
+                               return ;
+                       }               
+                       
+                       if( apiRes.upload.imageinfo &&  apiRes.upload.imageinfo.descriptionurl ){       
+                               var url = apiRes.upload.imageinfo.descriptionurl;
+                               //check done action: 
+                               if(_this.done_upload_cb){
+                                       //close up shop: 
+                                       $j('#upProgressDialog').dialog('close');        
+                                       //call the callback:                    
+                                       _this.done_upload_cb( url );
+                               }else{             
+                                       var bObj = {};
+                                       bObj[ gM('go-to-resource') ] = function(){
+                                                       window.location = url;
+                                       };
+                                       _this.updateProgressWin( gM('successfulupload'),  gM( 'mv_upload_done', url), bObj);
+                                       js_log('apiRes.upload.imageinfo::'+url);
+                               }
+                               return ;        
+                       }
+               }                       
+       },
+       updateProgressWin:function(title_txt, msg, buttons){
+               var _this = this;
+                if(!title_txt)
+                  title_txt = _this.getProgressTitle();
+                if(!msg)
+                  msg = mv_get_loading_img( 'left:40%;top:40px;');
+                $j( '#upProgressDialog' ).dialog('option', 'title',  title_txt );
+                $j( '#upProgressDialog' ).html( msg );
+                if(buttons){              
+                        $j('#upProgressDialog').dialog('option','buttons', buttons);
+                }else{                  
+                        //@@todo should convice the jquery ui people to not use object keys as user msg's
+                        var bObj = {};
+                        bObj[ gM('ok-button') ] =  function(){
+                                 $j(this).dialog('close');
+                        }; 
+                        $j('#upProgressDialog').dialog('option','buttons', bObj);
+                }               
+       },              
+       getProgressTitle:function(){
+               return gM('upload-in-progress');
+       },      
+       getEditForm:function(){
+               if(this.target_edit_from){
+                       return $j(this.target_edit_from).get(0);
+               }
+               //just return the first form fond on the page. 
+               return $j('form :first').get(0);
+       },
+       updateProgress:function( perc ){                
+               //js_log('update progress: ' + perc);
+               $j( '#up-progressbar' ).progressbar('value', parseInt( perc * 100 ) );  
+               $j( '#up-pstatus' ).html( parseInt( perc * 100 ) + '% - ' );
+       },
+       /*update to jQuery.ui progress display type */
+       dispProgressOverlay:function(){
+         var _this = this;
+         //remove old instance: 
+         if($j('#upProgressDialog').length!=0){
+                $j('#upProgressDialog').dialog( 'destroy' ).remove();
+         }
+         //re add it: 
+         $j('body').append('<div id="upProgressDialog" ></div>');
+               
+         $j('#upProgressDialog').dialog({
+                 title:_this.getProgressTitle(), 
+                 bgiframe: true,
+                 modal: true,
+                 width:400,
+                 heigh:200,
+                 beforeclose: function(event, ui) {                                       
+                         if( event.button==0 && _this.action_done === false){                                                                                   
+                               return _this.cancel_action();
+                         }else{
+                                //click on button (dont do close action);
+                                return true; 
+                         }
+                 },              
+                 buttons: _this.cancel_button()          
+         });     
+         $j('#upProgressDialog').html(
+         //set initial content: 
+               '<div id="up-pbar-container" style="width:90%;height:15px;" >' +
+                       '<div id="up-progressbar" style="height:15px;"></div>' +
+                       '<div id="up-status-container">'+
+                               '<span id="up-pstatus">0% - </span> ' +                                          
+                               '<span id="up-status-state">' + gM('uploaded-status') + '</span> ' +
+                       '</div>'+               
+               '</div>' 
+         )
+         //setup progress bar: 
+          $j('#up-progressbar').progressbar({ 
+                  value:0 
+          });    
+          //just display an empty progress window
+          $j('#upProgressDialog').dialog('open');
+       },
+       cancel_button:function(){
+          var _this = this;
+          var cancelBtn = new Array();
+          cancelBtn[ gM('cancel-button') ] =  function(){  
+                       return _this.cancel_action(this) 
+          };
+          return cancelBtn;
+       },      
+       cancel_action:function(dlElm){
+               //confirm:      
+               if( confirm( gM('mv-cancel-confim') )){
+                       alert("do dialog close:: cancel_action mvbase");
+                       //@@todo (cancel the encode / upload)
+                       $j(dlElm).dialog('close');
+                       return false;                   
+               }else{
+                       return true;
+               }  
+       }
+};
diff --git a/js2/mwEmbed/libAddMedia/mvFirefogg.js b/js2/mwEmbed/libAddMedia/mvFirefogg.js
new file mode 100644 (file)
index 0000000..f1c019c
--- /dev/null
@@ -0,0 +1,664 @@
+/* adds firefogg support. 
+* autodetects: new upload api or old http POST.  
+ */
+
+loadGM({ 
+       "fogg-select_file"                      : "Select File", 
+       "fogg-select_new_file"          : "Select New File",
+       "fogg-save_local_file"          : "Save Ogg",
+       "fogg-check_for_fogg"           : "Checking for Firefogg <blink>...</blink>",
+       "fogg-installed"                        : "Firefogg is Installed",
+       "fogg-for_improved_uplods"      : "For Improved uploads: ",
+       "fogg-please_install"           : "<a href=\"$1\">Install Firefogg</a>. More <a href=\"http://commons.wikimedia.org/wiki/Commons:Firefogg\">about firefogg</a>",        
+       "fogg-use_latest_fox"           : "Please first install <a href=\"http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg\">Firefox 3.5</a>. <i>then revisit this page to install the <b>firefogg</b> extention</i>",   
+       "fogg-passthrough_mode"     : "Your selected file is already ogg or not a video file",
+       "fogg-transcoding"                      : "Encoding Video to Ogg",
+       "fogg-encoding-done"            : "Encoding Done"
+});
+
+var firefogg_install_links =  {
+       'macosx':       'http://firefogg.org/macosx/Firefogg.xpi',
+       'win32' :       'http://firefogg.org/win32/Firefogg.xpi',
+       'linux' :       'http://firefogg.org/linux/Firefogg.xpi'
+};
+
+var default_firefogg_options = {
+       'upload_done_action':'redirect',
+       'fogg_enabled':false,
+       'api_url':null,
+       'passthrough': false,
+       'encoder_interface': false,
+       
+       //callbacks:
+       'new_source_cb': false, //called on source name update passes along source name
+       
+       //target control container or form (can't be left null)
+       'selector'                      : '',
+       
+       //if not rewriting a form we are encoding local.
+       'form_rewrite'          : false, 
+       
+       //taget buttons: 
+       'target_btn_select_file'        : false,
+       'target_btn_select_new_file': false,    
+       'target_input_file_name'        : false,
+       'target_btn_save_local_file': false,    
+       
+       
+       //target install descriptions 
+       'target_check_for_fogg'         : false,
+       'target_installed'      : false,
+       'target_please_install' : false,
+       'target_use_latest_fox': false,
+       //status: 
+       'target_passthrough_mode':false,
+       
+       //if firefogg should take over the form submit action
+       'firefogg_form_action':true
+}      
+
+
+var mvFirefogg = function(iObj){
+       return this.init( iObj );
+}
+mvFirefogg.prototype = { //extends mvBaseUploadInterface
+
+       min_firefogg_version : '0.9.8', 
+       fogg_enabled : false,            //if firefogg is enabled or not.        
+       encoder_settings:{                      //@@todo allow server to set this 
+               'maxSize': 400, 
+               'videoBitrate': 400,
+               'noUpscaling':true
+       },      
+       sourceFileInfo:{},
+       ogg_extensions: ['ogg', 'ogv', 'oga'],
+       video_extensions: ['avi', 'mov', 'mp4', 'mp2', 'mpeg', 'mpeg2', 'mpeg4', 'dv', 'wmv'],
+       
+       passthrough: false,
+
+       init: function( iObj ){
+               if(!iObj)
+                       iObj = {};
+                       
+               //if we have no api_url set upload to "post" 
+               if(!iObj.api_url)
+                       iObj.upload_mode = 'post'; 
+                       
+               //inherit iObj properties:
+               for(var i in default_firefogg_options){
+                       if(iObj[i]){
+                               this[i] = iObj[i];
+                       }else{
+                               this[i] = default_firefogg_options[i];
+                       }
+               }
+               
+               var myBUI = new mvBaseUploadInterface( iObj );
+               //standard extends code: 
+               for(var i in myBUI){                    
+                       if(this[i]){
+                               this['pe_'+ i] = myBUI[i];
+                       }else{
+                               this[i] =  myBUI[i];
+                       }
+               }
+               if(!this.selector){
+                       js_log('Error: firefogg: missing selector ');
+               }
+               //if detect 
+               
+       },
+       doRewrite:function( callback ){
+               var _this = this;
+               js_log('sel len: ' + this.selector + '::' + $j(this.selector).length + ' tag:'+ $j(this.selector).get(0).tagName);
+               if( $j(this.selector).length >=0 ){
+                       
+                       if( $j(this.selector).get(0).tagName.toLowerCase() == 'input' ){                                        
+                               _this.form_rewrite = true;                                                                              
+                       }               
+               }
+               //check if we are rewriting an input or a form:
+               if( this.form_rewrite ){
+                       this.setupForm();
+               }else{
+                       this.doControlHTML();    
+                       this.doControlBindings();       
+               }
+               
+               //doRewrite is done: 
+               if(callback)
+                       callback();
+       },
+       doControlHTML: function( ){             
+               var _this = this;               
+               var out = '';           
+               $j.each(default_firefogg_options, function(target, na){                 
+                       if(target.substring(0, 6)=='target'){
+                               //check for the target if missing add to the output: 
+                               if( _this[target] === false){                                   
+                                       out+= _this.getTargetHtml(target) + ' ';
+                                       //update the target selector 
+                                   _this[target] = _this.selector + ' .' + target;
+                               }                                                                                       
+                       }
+               });             
+               $j( this.selector ).append( out ).hide();
+       },
+       getTargetHtml:function(target){                                     
+               if( target.substr(7,3)=='btn'){
+                       return '<input style="" class="' + target + '" type="button" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
+               }else if(target.substr(7,5)=='input'){
+                       return '<input style="" class="' + target + '" type="text" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
+               }else{                                                          
+                       return '<div style="" class="' + target + '" >'+ gM('fogg-'+ target.substring(7)) + '</div> ';
+               }
+       },
+       doControlBindings: function(){
+               var _this = this;                       
+               
+               //hide all targets:
+               var hide_target_list='';
+               var coma='';
+               $j.each(default_firefogg_options, function(target, na){ 
+                       if(target.substring(0, 6)=='target'){
+                               hide_target_list+=coma + _this[target];
+                               coma=',';
+                       }                       
+               });                             
+               $j( hide_target_list ).hide();                          
+               //now that the proper set of items has been hiiden show: 
+               $j( this.selector ).show();
+                       
+                               
+               //hide all but check-for-fogg
+               //check for firefogg
+               if( _this.firefoggCheck() ){
+                       
+                       //if rewriting the form lets keep the text input around:                                                 
+                       if( _this.form_rewrite )
+                               $j(this.target_input_file_name).show();
+                       
+                       //show select file: 
+                       $j( this.target_btn_select_file ).unbind(
+                               ).attr('disabled', false
+                               ).css({'display':'inline'}
+                               ).click(function(){                                     
+                                       _this.selectFogg();
+                               });                             
+                   //also setup the text file display on Click to select file:  
+                   $j(this.target_input_file_name).unbind().attr('readonly', 'readonly').click(function(){                     
+                       _this.selectFogg();
+                   })          
+                       
+               }else{
+                       //first check firefox version:           
+                       if(!($j.browser.mozilla && $j.browser.version >= '1.9.1')) {
+                               js_log('show use latest::' + _this.target_use_latest_fox);
+                               if(_this.target_use_latest_fox){
+                                       if(_this.form_rewrite)
+                                               $j(_this.target_use_latest_fox).prepend( gM('fogg-for_improved_uplods') );
+                                                        
+                                       $j(_this.target_use_latest_fox).show();
+                               }
+                               return ;
+                       }
+                       //if they have the right version of mozilla provide install link: 
+                       var os_link = false;
+                       if(navigator.oscpu){
+                               if(navigator.oscpu.search('Linux') >= 0)
+                                       os_link = firefogg_install_links['linux'];
+                               else if(navigator.oscpu.search('Mac') >= 0)
+                                         os_link = firefogg_install_links['macosx'];
+                               else if(navigator.oscpu.search('Win') >= 0)
+                                         os_link = firefogg_install_links['win32'];
+                       }                                                                                       
+                       //if rewriting form use upload msg text
+                       var upMsg = (_this.form_rewrite) ? gM('fogg-for_improved_uplods') : '';                 
+                       $j(_this.target_please_install).html( upMsg + gM('fogg-please_install',os_link )).css('padding', '10px').show();                        
+               }
+               //setup the target save local file bindins: 
+               $j( _this.target_btn_save_local_file ).unbind().click(function(){
+                       _this.saveLocalFogg();
+               });
+       },
+       firefoggCheck:function(){                                  
+               if(typeof(Firefogg) != 'undefined' && Firefogg().version >= '0.9.9'){                                           
+                  this.fogg = new Firefogg();  
+                  this.fogg_enabled = true;
+                  return true;
+               }else{                                                          
+                       return false;
+               }
+       },
+       //assume input target
+       setupForm: function(){          
+               js_log('firefogg::setupForm::');
+               //to parent form setup if we want http updates 
+               if( this.form_rewrite ){
+                       //do parent form setup: 
+                       this.pe_setupForm();            
+               }
+               
+               //check if we have firefogg (if not just add a link and stop proccessing) 
+               if( !this.firefoggCheck() ){
+                       //add some status indicators if not provided: 
+                       if(!this.target_please_install){                                
+                               $j(this.selector).after ( this.getTargetHtml('target_please_install') );                                                                
+                               this.target_please_install = this.selector + ' ~ .target_please_install';
+                       }
+                       if(!this.target_use_latest_fox){                
+                               $j(this.selector).after ( this.getTargetHtml('target_use_latest_fox') );        
+                               this.target_use_latest_fox = this.selector + ' ~ .target_use_latest_fox';                       
+                       }
+                       //update download link:
+                       this.doControlBindings();               
+                       return ;
+               }
+               
+               //change the file browser to type text: (can't directly change input from "file" to "text" so longer way:
+               var inTag = '<input ';
+               $j.each($j(this.selector).get(0).attributes, function(i, attr){
+                       var val = attr.value;
+                       if( attr.name == 'type')
+                               val = 'text';
+                       inTag += attr.name + '="' + val + '" ';
+               });
+               if(!$j(this.selector).attr('style'))
+                       inTag += 'style="display:inline" ';
+                       
+               inTag+= '/><span id="' + $j(this.selector).attr('name') + '_fogg-control"></span>';
+                                                                               
+               js_log('set input: ' + inTag);
+               $j(this.selector).replaceWith(inTag);                   
+               
+               this.target_input_file_name = 'input[name=' + $j(this.selector).attr('name') + ']';
+               //update the selector to the control target: 
+               this.selector = '#' + $j(this.selector).attr('name') +  "_fogg-control";
+               
+               this.doControlHTML();
+               //check for the other inline status indicator targets:           
+               
+               //update the bindings: 
+               this.doControlBindings();
+       },
+       getEditForm:function(){
+               js_log('get form: action=' + $j(this.selector).parents().find("form").attr('action'));
+               return $j(this.selector).parents().find("form").get(0);
+       },   
+       selectFogg:function(){                  
+               var _this = this;
+               if( _this.fogg.selectVideo() ) {                                        
+                       js_log('videoSelectReady');
+                       //if not already hidden hide select file and show "select new": 
+                       $j(_this.target_btn_select_file).hide();
+                       //show and setup binding for select new file: 
+                       $j(_this.target_btn_select_new_file).show().unbind().click(function(){
+                               //create new fogg instance:                              
+                               _this.fogg = new Firefogg();
+                               _this.selectFogg();
+                       });
+                       //update if we are in passthrough mode or going to encode                                       
+                       if( _this.fogg.sourceInfo && _this.fogg.sourceFilename ){                                                                       
+                               //update the source status
+                               try{
+                                       _this.sourceFileInfo = JSON.parse( _this.fogg.sourceInfo ) ;
+                               }catch (e){
+                                       js_error('error could not parse fogg sourceInfo');
+                               }                                       
+                                               
+                               //now setup encoder settings based source type:
+                               _this.autoEncoderSettings();                                    
+                               
+                               //if set to passthough update the interface:
+                               if(_this.encoder_settings['passthrough']==true){
+                                       $j(_this.target_passthrough_mode).show();
+                               }else{                                  
+                                       $j(_this.target_passthrough_mode).hide();       
+                                       //if set to encoder expose the encode button: 
+                                       if( !_this.form_rewrite ){
+                                               $j(_this.target_btn_save_local_file).show();
+                                       }
+                               }
+                               //~otherwise the encoding will be triggered by the form~
+                               
+                               //do source name update callback:       
+                               js_log(" should update: " + _this.target_input_file_name + ' to: ' + _this.fogg.sourceFilename );                                
+                               $j(_this.target_input_file_name).val(_this.fogg.sourceFilename).show();
+                               
+                               if(_this.new_source_cb){                                                                                                
+                                       if(_this.encoder_settings['passthrough']){
+                                               var fName = _this.fogg.sourceFilename
+                                       }else{  
+                                           var oggExt = (_this.isSourceAudio())?'oga':'ogg';
+                           oggExt = (_this.isSourceVideo())?'ogv':oggExt;
+                           oggExt = (_this.isUnknown())?'ogg':oggExt;
+                                           oggName = _this.fogg.sourceFilename.substr(0,
+                                                         _this.fogg.sourceFilename.lastIndexOf('.'));
+                                           var fName = oggName +'.'+ oggExt              
+                                       }
+                                       _this.new_source_cb( _this.fogg.sourceFilename , fName);
+                               }
+                       }                                                                                                       
+               }else{
+                       //js_error("Firefogg error selecting file");
+               }
+       },
+       saveLocalFogg:function(){
+          //request target location:
+          if(this.fogg){
+                  if(!this.fogg.saveVideoAs() )
+                          return false;
+                  
+                  //we have set a target now call the encode: 
+                 this.doEncode();                 
+          }  
+       },
+       //simple auto encoder settings just enable passthough if file is not video or > 480 pixles tall 
+       autoEncoderSettings:function(){         
+               var _this = this;
+               //grab the extension:
+               var sf = _this.fogg.sourceFilename;                                             
+               var ext = '';
+               if(     sf.lastIndexOf('.') != -1){
+                       ext = sf.substring( sf.lastIndexOf('.')+1 ).toLowerCase();
+               }       
+                                 
+               //set to passthrough to true by default (images, arbitrary files that we want to send with http chunks) 
+               this.encoder_settings['passthrough'] = true;
+               
+               //see if we have video or audio:  
+               if(  _this.isSourceAudio() || _this.isSourceVideo() ){
+                        _this.encoder_settings['passthrough'] = false; 
+               }
+                                                       
+               //special case see if we already have ogg video: 
+               if( _this.isOggFormat() ){
+                       _this.encoder_settings['passthrough'] = true;
+               }               
+                                
+               js_log('base autoEncoderSettings::' + _this.sourceFileInfo.contentType  + ' passthrough:' + _this.encoder_settings['passthrough']);
+       },
+       isUnknown:function(){
+               return (this.sourceFileInfo.contentType.indexOf("unknown") != -1);
+       },
+       isSourceAudio:function(){
+          return (this.sourceFileInfo.contentType.indexOf("audio/") != -1);
+       },
+       isSourceVideo:function(){
+           return (this.sourceFileInfo.contentType.indexOf("video/") != -1);
+       },      
+       isOggFormat:function(){
+          return ( this.sourceFileInfo.contentType.indexOf("video/ogg") != -1 || 
+                       this.sourceFileInfo.contentType.indexOf("application/ogg") != -1   ); 
+       },
+       getProgressTitle:function(){
+               js_log("fogg:getProgressTitle f:" + this.fogg_enabled  + ' rw:' + this.form_rewrite);
+               //return the parent if we don't have fogg turned on: 
+               if(! this.fogg_enabled )
+                       return this.pe_getProgressTitle();                                 
+               if( !this.form_rewrite )
+                 return gM('fogg-transcoding');
+               //else return our upload+transcode msg:                         
+               return gM('upload-transcode-in-progress');
+       },      
+       doUploadSwitch:function(){                              
+               var _this = this;
+               js_log("firefogg: doUploadSwitch:: " + this.fogg_enabled);
+               //make sure firefogg is enabled otherwise do parent UploadSwich:                
+               if( !this.fogg_enabled || !this.firefogg_form_action )
+                       return _this.pe_doUploadSwitch();
+               
+               //check what mode to use firefogg in: 
+               if( _this.upload_mode == 'post' ){
+                       _this.doEncode();
+               }else if( _this.upload_mode == 'api' && _this.chunks_supported){ //if api mode and chunks supported do chunkUpload
+                       _this.doChunkUpload();
+               }else{
+                       js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode );
+               }               
+       },
+       //doChunkUpload does both uploading and encoding at the same time and uploads one meg chunks as they are ready
+       doChunkUpload : function(){
+               var _this = this;                       
+               _this.action_done = false;                      
+               
+               //extension should already be ogg but since its user editable,
+               //check again
+               //we are transcoding so we know it will be an ogg
+               //(should not be done for passthrough mode)
+               var sf = _this.formData['wpDestFile'];
+               var ext = '';
+               if(     sf.lastIndexOf('.') != -1){
+                       ext = sf.substring( sf.lastIndexOf('.') ).toLowerCase();
+               }
+               if(!_this.encoder_settings['passthrough'] && $j.inArray(ext.substr(1), _this.ogg_extensions) == -1 ){           
+                       var extreg = new RegExp(ext + '$', 'i');
+                       _this.formData['wpDestFile'] = sf.replace(extreg, '.ogg');
+               }
+               //add chunk response hook to build the resultURL when uploading chunks          
+               
+               //build the api url: 
+               var aReq ={
+                       'action'        : 'upload',
+                       'format'        : 'json',
+                       'filename'      : _this.formData['wpDestFile'],
+                       'comment'       : _this.formData['wpUploadDescription'],
+                       'enablechunks': true
+               };
+               //check for editToken:
+               if(!this.etoken)
+                       this.etoken = _this.formData['wpEditToken'];
+                       
+               if(this.etoken)
+                       aReq['token'] = this.etoken;
+               
+               if( _this.formData['wpWatchthis'] )
+                       aReq['watch'] =  _this.formData['wpWatchthis'];
+               
+               if(  _this.formData['wpIgnoreWarning'] )
+                       aReq['ignorewarnings'] = _this.formData['wpIgnoreWarning'];
+               
+               js_log('do fogg upload/encode call: '+ _this.api_url + ' :: ' + JSON.stringify( aReq ) );                       
+               js_log('foggEncode: '+ JSON.stringify( _this.encoder_settings ) );                      
+               _this.fogg.upload( JSON.stringify( _this.encoder_settings ),  _this.api_url ,  JSON.stringify( aReq ) );                
+                       
+               //update upload status:                                         
+               _this.doUploadStatus();
+       },
+       //doEncode and monitor progress:
+       doEncode : function(){  
+               var _this = this;
+               _this.action_done = false;
+               _this.dispProgressOverlay();                            
+               js_log('doEncode: with: ' +  JSON.stringify( _this.encoder_settings ) );
+               _this.fogg.encode( JSON.stringify( _this.encoder_settings ) );                    
+               
+               
+                //show transcode status:
+               $j('#up-status-state').html( gM('upload-transcoded-status') );
+               
+               //setup a local function for timed callback:
+               var encodingStatus = function() {
+                       var status = _this.fogg.status();
+                       
+                       //update progress bar
+                       _this.updateProgress( _this.fogg.progress() );                  
+                       
+                       //loop to get new status if still encoding
+                       if( _this.fogg.state == 'encoding' ) {
+                               setTimeout(encodingStatus, 500);
+                       }else if ( _this.fogg.state == 'encoding done' ) { //encoding done, state can also be 'encoding failed                                                                                                                          
+                               _this.encodeDone();
+                       }else if(_this.fogg.state == 'encoding fail'){
+                               //@@todo error handling: 
+                               js_error('encoding failed');
+                       }
+               }
+               encodingStatus();                                         
+       },      
+       encodeDone:function(){
+               var _this = this;
+               js_log('::encodeDone::');
+               _this.action_done = true;
+               //send to the post url:                          
+               if( _this.form_rewrite && _this.upload_mode == 'post' ){
+                       js_log('done with encoding do POST upload:' + _this.editForm.action);                                                           
+                       // ignore warnings & set source type 
+                       //_this.formData[ 'wpIgnoreWarning' ]='true';
+                       _this.formData[ 'wpSourceType' ] = 'upload';            
+                       _this.formData[ 'action' ]               = 'submit';
+                       //wpUploadFile is set by firefogg
+                       delete _this.formData[ 'wpUploadFile' ];           
+
+                       _this.fogg.post( _this.editForm.action, 'wpUploadFile', JSON.stringify( _this.formData ) );                             
+                       //update upload status:                                         
+                       _this.doUploadStatus();
+               }else{
+                       js_log("done with encoding (no upload) ");
+                       //set stuats to 100% for one second:
+                       _this.updateProgress( 1 );              
+                       setTimeout(function(){
+                               _this.updateProgressWin(gM('fogg-encoding-done'), gM('fogg-encoding-done'));
+                       }, 1000);       
+               }
+       },
+       doUploadStatus:function() {     
+               var _this = this;
+               $j('#up-status-state').html( gM('uploaded-status')  );
+               
+               _this.oldResponseText = '';
+               //setup a local function for timed callback:                             
+               var uploadStatus = function(){                  
+                       //get the response text: 
+                       var response_text =  _this.fogg.responseText;
+                       if(!response_text){
+                                  try{
+                                          var pstatus = JSON.parse( _this.fogg.uploadstatus() );
+                                          response_text = pstatus["responseText"];
+                                  }catch(e){
+                                          js_log("could not parse uploadstatus / could not get responseText");
+                                  }
+                       }
+                                          
+                       if( _this.oldResponseText != response_text){                                                                                                                                                                                                                      
+                               js_log('new result text:' + response_text + ' state:' + _this.fogg.state);
+                               _this.oldResponseText = response_text;                          
+                               //try and parse the response text and check for errors                  
+                               try{
+                                       var apiResult = JSON.parse( response_text );                                    
+                               }catch(e){
+                                       js_log("could not parse response_text::" + response_text + ' ...for now try with eval...');
+                                       try{
+                                               var apiResult = eval( response_text );
+                                       }catch(e){
+                                               var apiResult = null;
+                                       }
+                               }                                               
+                               if(apiResult && _this.apiUpdateErrorCheck( apiResult ) === false){                                      
+                                       //stop status update we have an error
+                                       _this.action_done = true;
+                                       _this.fogg.cancel();
+                                       return false; 
+                               }               
+                       }       
+                       //update progress bar
+                       _this.updateProgress( _this.fogg.progress() );
+                                               
+                       //loop to get new status if still uploading (could also be encoding if we are in chunk upload mode) 
+                       if( _this.fogg.state == 'encoding' || _this.fogg.state == 'uploading') {
+                               setTimeout(uploadStatus, 100);
+                               
+                       }//check upload state
+                       else if( _this.fogg.state == 'upload done' || 
+                                                _this.fogg.state == 'done' ||
+                                                _this.fogg.state == 'encoding done' ) {        
+                                  js_log( 'firefogg:upload done: ');                                                                                                                                                                                                                                              
+                                  //if in "post" upload mode read the html response (should be depricated): 
+                                       if( _this.upload_mode == 'post' && _this.api_url ) {                                                                              
+                                          _this.procPageResponse( response_text );                                                
+                                       }else if( _this.upload_mode == 'api'){                                                                            
+                                          if( _this.fogg.resultUrl ){  
+                                                       var buttons ={}; 
+                                                       buttons[gM('go-to-resource')] =  function(){
+                                                               window.location = _this.fogg.resultUrl;
+                                                       }
+                                                       var go_to_url_txt = gM('go-to-resource');                          
+                                                  //should have an json result:
+                                                  _this.updateProgressWin( gM('successfulupload'),  gM( 'mv_upload_done', _this.fogg.resultUrl),buttons);      
+                                          }else{
+                                                  //done state with error? ..not really possible given how firefogg works
+                                                  js_log(" upload done, in chunks mode, but no resultUrl!");
+                                          }                                                                                                                                                                                                               
+                                  }                                                                                                    
+                       }else{  
+                               //upload error: 
+                               js_log('Error:firefogg upload error: ' + _this.fogg.state );            
+                  }
+          }
+          uploadStatus();
+       },      
+       cancel_action:function( dlElm ){
+               if(!this.fogg_enabled){
+                       return this.pe_cancel_action();
+               }
+               js_log('firefogg:cancel')
+               if( confirm( gM('mv-cancel-confim') )){
+                   if(navigator.oscpu && navigator.oscpu.search('Win') >= 0){
+                        alert( 'sorry we do not yet support cancel on windows' );
+                   }else{
+                       this.action_done = true;
+                       this.fogg.cancel();
+                       $j(dlElm).dialog('close');
+                   }
+               } else{                         
+                       return false;
+               } 
+       },
+       /**
+       * procPageResponse should be faded out in favor of the upload api soon.. 
+       * its all very fragile to read the html output and guess at stuff
+       */
+       procPageResponse:function( result_page ){
+               var _this = this;
+               js_log('f:procPageResponse');
+               var sstring = 'var wgTitle = "' + this.formData['wpDestFile'].replace('_',' ');         
+               
+               if(wgArticlePath){
+                       var result_txt = gM('mv_upload_done', wgArticlePath.replace(/\$1/, 'File:' + this.formData['wpDestFile'] ) );
+               }else{
+                       result_txt = 'File has uploaded but api "done" url was provided. Check the log for result page output';
+               }               
+               
+               //set the error text in case we dont' get far along in processing the response 
+               _this.updateProgressWin( gM('mv_upload_completed'), result_txt );
+                                                                                               
+               if( result_page && result_page.toLowerCase().indexOf( sstring.toLowerCase() ) != -1){   
+                       js_log( 'upload done got redirect found: ' + sstring + ' r:' + _this.upload_done_action );                                                                              
+                       if( _this.upload_done_action == 'redirect' ){
+                               $j( '#dlbox-centered' ).html( '<h3>Upload Completed:</h3>' + result_txt + '<br>' + form_txt);
+                               window.location = wgArticlePath.replace( /\$1/, 'File:' + formData['wpDestFile'] );
+                       }else{
+                               //check if the add_done_action is a callback:
+                               if( typeof _this.upload_done_action == 'function' )
+                                       _this.upload_done_action();
+                       }                                                                       
+               }else{                                                          
+                       //js_log( 'upload page error: did not find: ' +sstring + ' in ' + "\n" + result_page );                                 
+                       var form_txt = '';              
+                       if( !result_page ){
+                               //@@todo fix this: 
+                               //the mediaWiki upload system does not have an API so we can\'t read errors                                                     
+                       }else{
+                               var res = grabWikiFormError( result_page );
+                                                       
+                               if(res.error_txt)
+                                       result_txt = res.error_txt;
+                                       
+                               if(res.form_txt)
+                                       form_txt = res.form_txt;
+                       }               
+                       js_log( 'error text is: ' + result_txt );               
+                       $j( '#dlbox-centered' ).html( '<h3>' + gM('mv_upload_completed') + '</h3>' + result_txt + '<br>' + form_txt);
+               }
+       }
+};
diff --git a/js2/mwEmbed/libAddMedia/remoteSearchDriver.js b/js2/mwEmbed/libAddMedia/remoteSearchDriver.js
new file mode 100644 (file)
index 0000000..3238036
--- /dev/null
@@ -0,0 +1,1641 @@
+/*
+* a library for doing remote media searches
+* 
+* initial targeted archives are:
+       the local wiki
+       wikimedia commons
+       metavid
+       and archive.org
+*/
+loadGM({
+       "add_media_wizard": "Add Media Wizard",
+       "mv_media_search" : "Media Search",
+       "rsd_box_layout" : "Box layout",
+       "rsd_list_layout" : "List Layout",
+       "rsd_results_desc" : "Results ",
+       "rsd_results_next" : "next ",
+       "rsd_results_prev" : "previous ",
+       "rsd_no_results"   : "No search results for <b>$1</b>",
+
+       "mv_upload" : "Upload",
+       "rsd_layout" : "Layout:",
+       "rsd_resource_edit" : "Edit Resource: $1",
+       "resource_description_page": "Resource Description Page",
+       "rsd_local_resource_title": "Local Resource Title",
+       "rsd_do_insert": "Do Insert",
+
+       "cc_title": "Creative Commons",
+       "cc_by_title": "Attribution",
+       "cc_nc_title": "Noncommercial",
+       "cc_nd_title": "No Derivative Works",
+       "cc_sa_title": "Share Alike",
+       "cc_pd_title": "Public Domain",
+       "unknown_license": "Unknown License",   
+       "no_import_by_url": "This User or Wiki <b>can not</b> import assets from remote URLs. </p><p> Do you need to Login? </p><p> If permissions are set you may have to enable $wgAllowCopyUploads, <a href=\"http://www.mediawiki.org/wiki/Manual:$wgAllowCopyUploads\">more info</a></p>",
+       "results_from": "Results from <a href=\"$1\" target=\"_new\" >$2</a>"
+});
+var default_remote_search_options = {
+       'profile':'mediawiki_edit',
+       'target_container':null, //the div that will hold the search interface
+       //if using a modeal dialog (instead of target_container) how close to the edge of the window should we go:       
+       'modal_edge_padding':'20px',
+       
+       'target_invocation': null, //the button or link that will invoke the search interface
+
+       'default_provider_id':'all', //all or one of the content_providers ids
+
+       'caret_pos':null,
+       'local_wiki_api_url':null,
+
+       //can be 'api', 'form', 'autodetect', 'remote_link'
+       'import_url_mode': 'autodetect', 
+
+       'target_title':null,
+
+       'target_textbox':null,
+       'target_render_area': null, //where output render should go:  
+       'instance_name': null, //a globally accessible callback instance name
+       'default_query':null, //default search query
+       //specific to sequence profile
+       'p_seq':null,
+       'cFileNS':'File', //what is the cannonical namespace for images
+                                         //@@todo (should get that from the api or inpage vars)
+                                        
+       'enable_upload_tab':true // if we want to enable an uploads tab:        
+}
+if(typeof wgServer == 'undefined')
+       wgServer = '';
+if(typeof wgScriptPath == 'undefined')
+       wgScriptPath = '';
+if(typeof stylepath == 'undefined')
+       stylepath = '';
+
+/*
+*      base remoteSearch Driver interface
+*/
+var remoteSearchDriver = function(iObj){
+       return this.init( iObj );
+}
+remoteSearchDriver.prototype = {
+       results_cleared:false,
+       //here we define the set of possible media content providers:
+       main_search_options:{
+               'selprovider':{
+                       'title': 'Select Providers'             
+               },
+               'advanced_search':{
+                       'title': 'Advanced Options'
+               }       
+       },      
+       /*
+        * sets the default display item:
+        * can be any content_providers key or 'all'
+        */
+       disp_item : 'wiki_commons',
+       /** the default content providers list. 
+        *
+        * (should be note that special tabs like "upload" and "combined" don't go into the content proviers list:
+        *
+        * @@todo we will want to load more per user-preference and per category lookup
+        */
+       content_providers:{                     
+               /*content_providers documentation:                      
+                *  @@todo we should move the bulk of the configuration to each file
+                *       
+               
+                       @enabled: whether the search provider can be selected
+                       @checked: whether the search provider will show up as seleatable tab (todo: user prefrence)
+                       @d:        default: if the current cp should be displayed (only one should be the default)
+                       @title:   the title of the search provider
+                       @desc:     can use html... todo: need to localize
+                       @api_url: the url to query against given the library type:
+                       @lib:      the search library to use corresponding to the
+                                               search object ie: 'mediaWiki' = new mediaWikiSearchSearch()
+                       @tab_img: the tab image (if set to false use title text)
+                                               if === "ture" use standard location skin/images/{cp_id}_tab.png
+                                               if === string use as url for image
+                                               
+                       @linkback_icon default is: /wiki/skins/common/images/magnify-clip.png
+               
+                       //domain insert: two modes: simple config or domain list:
+                       @local : if the content provider assets need to be imported or not.
+                       @local_domains : sets of domains for which the content is local  
+                       //@@todo should query wgForeignFileRepos setting maybe interwikimap from the api
+               */                               
+               'this_wiki':{
+                       'enabled': 0,
+                       'checked': 0,                   
+                       'title'  : 'This Wiki',
+                       'desc'   : '(should be updated with the proper text) maybe import from some config value',
+                       'api_url':  wgServer + wgScriptPath + '/api.php',
+                       'lib'    : 'mediaWiki', 
+                       'local'  : true,
+                       'tab_img': false
+               },      
+               'wiki_commons':{
+                       'enabled': 1,
+                       'checked': 1,                   
+                       'title'  :'Wikimedia Commons',          
+                       'desc'   : 'Wikimedia Commons is a media file repository making available public domain '+
+                                        'and freely-licensed educational media content (images, sound and video clips) to all.',
+                       'homepage': 'http://commons.wikimedia.org/wiki/Main_Page',      
+                       'api_url':'http://commons.wikimedia.org/w/api.php',
+                       'lib'   :'mediaWiki',           
+                       'resource_prefix': 'WC_', //prefix on imported resources (not applicable if the repository is local)
+               
+                       //list all the domains where commons is local?
+                       // probably should set this some other way by doing an api query
+                       // or by seeding this config when calling the remote search?                    
+                       'local_domains': ['wikimedia','wikipedia','wikibooks'],
+                       //specific to wiki commons config:
+                       'search_title':false, //disable title search
+                       //set up default range limit
+                       'offset'                        : 0,
+                       'limit'                         : 30,
+                       'tab_img':true          
+               },
+               'archive_org':{
+                       'enabled':1,
+                       'checked':1,
+                       'title' : 'Archive.org',
+                       'desc'  : 'The Internet Archive, a digital library of cultural artifacts',
+                       'homepage':'http://www.archive.org/about/about.php',
+               
+                       'api_url':'http://homeserver7.us.archive.org:8983/solr/select',
+                       'lib'   : 'archiveOrg',
+                       'local' : false,
+                       'resource_prefix': 'AO_',
+                       'tab_img':true
+               },
+               'metavid':{
+                       'enabled':1,
+                       'checked':1,
+                       'title' :'Metavid.org',
+                       'homepage':'http://metavid.org',
+                       'desc'  : 'Metavid hosts thousands of hours of US house and senate floor proceedings',
+                       'api_url':'http://metavid.org/w/index.php?title=Special:MvExportSearch',
+                       'lib'   : 'metavid',
+                       'local' :false,                 //if local set to true we can use local
+                       'resource_prefix': 'MV_', //what prefix to use on imported resources
+               
+                       'local_domains': ['metavid'], // if the domain name contains metavid
+                                                                          // no need to import metavid content to metavid sites
+                                                                         
+                       'stream_import_key': 'mv_ogg_low_quality', // which stream to import, could be mv_ogg_high_quality
+                                                                                                         //or flash stream, see ROE xml for keys
+                                                                                                        
+                       'remote_embed_ext': false, //if running the remoteEmbed extension no need to copy local
+                                                                          //syntax will be [remoteEmbed:roe_url link title]    
+                       'tab_img':true                                                  
+               }
+       },
+       //define the licenses
+       // ... this will get complicated quick...
+       // (just look at complexity for creative commons without exessive "duplicate data")
+       // ie cc_by could be "by/3.0/us/" or "by/2.1/jp/" to infinitum...
+       // some complexity should be negated by license equivalances.   
+
+       // but we will have to abstract into another class let content providers provide license urls
+       // and we have to clone the license object and allow local overrides
+
+       licenses:{      
+               //for now only support creative commons type licenses
+               //used page: http://creativecommons.org/licenses/
+               'cc':{
+                       'base_img_url':'http://upload.wikimedia.org/wikipedia/commons/thumb/',
+                       'base_license_url': 'http://creativecommons.org/licenses/',
+                       'licenses':{
+                               'by': 'by/3.0/',
+                               'by-sa': 'by-sa/3.0/',                                  
+                               'by-nc-nd': 'by-nc-nd/3.0/',
+                               'by-nc': 'by-nc/3.0/',
+                               'by-nd': 'by-nd/3.0/',
+                               'by-nc-sa': 'by-nc-sa/3.0/',
+                               'by-sa': 'by-nc/3.0',
+                               'pd': 'publicdomain/'
+                       },
+                       'license_img':{
+                               'by':{
+                                       'im':'1/11/Cc-by_new_white.svg/20px-Cc-by_new_white.svg.png'
+                               },
+                               'nc':{
+                                       'im':'2/2f/Cc-nc_white.svg/20px-Cc-nc_white.svg.png'
+                               },
+                               'nd':{
+                                       'im':'b/b3/Cc-nd_white.svg/20px-Cc-nd_white.svg.png'
+                               },
+                               'sa':{
+                                       'im':'d/df/Cc-sa_white.svg/20px-Cc-sa_white.svg.png'
+                               },
+                               'pd':{
+                                       'im':'5/51/Cc-pd-new_white.svg/20px-Cc-pd-new_white.svg.png'                    
+                               }
+                       }
+               }
+       },
+       /*
+       * getlicenseImgSet
+       * @param license_key  the license key (ie "by-sa" or "by-nc-sa" etc)
+       */
+       getlicenseImgSet: function( licenseObj ){       
+               //js_log('output images: '+ imgs);
+               return '<div class="rsd_license" title="'+ licenseObj.title + '" >' +
+                                       '<a target="_new" href="'+ licenseObj.lurl +'" ' +
+                                       'title="' + licenseObj.title + '">'+
+                                                       licenseObj.img_html +
+                                       '</a>'+
+                                 '</div>';
+       },
+       /*
+       * getLicenceKeyFromKey
+       * @param license_key the key of the license (must be defined in: this.licenses.cc.licenses)
+       */
+       getLicenceFromKey:function( license_key , force_url){
+               if( typeof( this.licenses.cc.licenses[ license_key ]) == 'undefined')
+                       return js_error('could not find:' + license_key);
+               //set the current license pointer:
+               var cl = this.licenses.cc;
+               var title = gM('cc_title');
+               var imgs = '';  
+               var license_set = license_key.split('-');       
+               for(var i=0;i < license_set.length; i++){               
+                       lkey =   license_set[i];                                                        
+                       title += ' ' + gM( 'cc_' + lkey + '_title');
+                       imgs +='<img class="license_desc" width="20" src="' + cl.base_img_url +
+                               cl.license_img[ lkey ].im + '">';
+               }
+               var url = (force_url) ? force_url : cl.base_license_url + cl.licenses[ license_key ];
+               return {
+                       'title'         : title,
+                       'img_html'      : imgs,
+                       'key'            : license_key,
+                       'lurl'           : url
+               };
+       },
+       /*
+       * getLicenceKeyFromUrl
+       * @param licence_url the url of the license
+       */
+       getLicenceFromUrl: function( license_url ){
+               js_log("getLicenceFromUrl::" + license_url);
+               //first do a direct lookup check:
+               for(var i in this.licenses.cc.licenses){
+                       var lkey = this.licenses.cc.licenses[i].split('/')[0];
+                       //guess by url trim
+                       if( parseUri(license_url).path.indexOf('/'+ lkey +'/') != -1){          
+                               return this.getLicenceFromKey( i , license_url);
+                       }
+               }
+               //could not find it return unknown_license
+               return {
+                       'title'         : gM('unknown_license'),
+                       'img_html'      : '<span>' + gM('unknown_license') + '</span>',         
+                       'lurl'          : license_url
+               };
+       },
+       //some default layout values:   
+       thumb_width              : 80,
+       image_edit_width        : 400,
+       video_edit_width        : 400,
+       insert_text_pos         : 0,      //insert at the start (will be overwritten by the user cursor pos)
+       result_display_mode : 'box', //box or list
+
+       cUpLoader                       : null,
+       cEdit                           : null,
+       dmodalCss                       : {},
+
+       init: function( iObj ){
+               var _this = this;
+               js_log('remoteSearchDriver:init');              
+               for( var i in default_remote_search_options ) {
+                       if( iObj[i]){
+                               this[ i ] = iObj[i];
+                       }else{
+                               this[ i ] = default_remote_search_options[i];
+                       }               
+               }       
+               //update the base text:
+               if(_this.target_textbox)
+                  _this.getTexboxSelection();
+                               
+               //set up the content provider config:
+               if(this.cpconfig){
+                       for(var cpc in cpconfig){
+                               for(var cinx in this.cpconfig[cpc]){
+                                       if( this.content_providers[cpc] )                                       
+                                               this.content_providers[ cpc ][ cinx ] = this.cpconfig[cpc][ cinx];                              
+                               }
+                       }
+               }
+               //set up the default model config: 
+               this.dmodalCss = {
+                       'width':'auto',
+                       'height':'auto',
+                       'top'   : this.modal_edge_padding,
+                       'left'  : this.modal_edge_padding,
+                       'right' : this.modal_edge_padding,
+                       'bottom': this.modal_edge_padding
+               }
+               
+               
+               //set up the target invocation:
+               if( $j(this.target_invocation).length==0 ){
+                       js_log("RemoteSearchDriver:: no target invocation provided (will have to run your own doInitDisplay() )");
+               }else{
+                       $j(this.target_invocation).css('cursor','pointer').attr('title', gM('add_media_wizard')).click(function(){
+                               _this.doInitDisplay();
+                       });             
+               }                                                               
+       },
+       doInitDisplay:function(){       
+               var _this = this;                       
+               //setup the parent container:
+               this.init_modal();
+               //fill in the html:
+               this.init_interface_html();
+               //bind actions:
+               this.add_interface_bindings();
+       
+               //update the target bining to just unhide the dialog:
+               $j(this.target_invocation).unbind().click(function(){
+                         js_log("re-open");
+                         //update the base text:
+                         if(_this.target_textbox)
+                                       _this.getTexboxSelection();
+               
+                         $j(_this.target_container).dialog('open').parent('.ui-dialog').css( _this.dmodalCss );
+                });    
+       },
+       //gets the in and out points for insert position or grabs the selected text for search
+       getTexboxSelection:function(){
+               //update the caretPos
+               this.getCaretPos();                     
+       
+               //if we have highlighted text use that as the query: (would be fun to add context menu once we have rich editor in-place)
+               if( this.caret_pos.selection )
+                       this.default_query = this.caret_pos.selection
+       
+       },
+       getCaretPos:function(){
+               this.caret_pos={};
+               var txtarea = $j(this.target_textbox).get(0);
+               var getTextCusorStartPos = function (o){        
+                       if (o.createTextRange) {
+                                       var r = document.selection.createRange().duplicate()
+                                       r.moveEnd('character', o.value.length)
+                                       if (r.text == '') return o.value.length
+                                       return o.value.lastIndexOf(r.text)
+                               } else return o.selectionStart
+               }
+               var getTextCusorEndPos = function (o){
+                       if (o.createTextRange) {
+                               var r = document.selection.createRange().duplicate();
+                               r.moveStart('character', -o.value.length);
+                               return r.text.length;
+                       } else{
+                               return o.selectionEnd
+                       }
+               }
+               this.caret_pos.s = getTextCusorStartPos( txtarea );
+               this.caret_pos.e = getTextCusorEndPos( txtarea );       
+               this.caret_pos.text = txtarea.value;
+               if(this.caret_pos.s && this.caret_pos.e &&
+                               (this.caret_pos.s != this.caret_pos.e))
+                       this.caret_pos.selection = this.caret_pos.text.substring(this.caret_pos.s, this.caret_pos.e).replace(/ /g, '\xa0') || '\xa0';
+                       
+               js_log('got caret_pos:' + this.caret_pos.s);                    
+               //restore text value: (creating textRanges sometimes screws with the text content)
+               $j(this.target_textbox).val(this.caret_pos.text);
+       },
+       init_modal:function(){
+               js_log("init_modal");
+               var _this = this;
+               //add the parent target_container if not provided or missing
+               if(!_this.target_container || $j(_this.target_container).length==0){
+                       $j('body').append('<div id="rsd_modal_target" style="position:absolute;top:30px;left:0px;bottom:45px;right:0px" title="' + gM('add_media_wizard') + '" ></div>');
+                       _this.target_container = '#rsd_modal_target';
+                       js_log('appended: #rsd_modal_target' + $j(_this.target_container).attr('id'));
+                               js_log('added target id:' + $j(_this.target_container).attr('id'));
+                       //get layout                    
+                       //layout = _this.getMaxModalLayout();                   
+                       $j(_this.target_container).dialog({
+                               bgiframe: true,
+                               autoOpen: true,           
+                               modal: true,
+                               buttons: {              
+                                       '_': function() {
+                                               //just a place-holder
+                                       }
+                               },
+                               close: function() {
+                                       js_log('closed modal');
+                               }               
+                       }).css({'height':'100%'}).parent('.ui-dialog').css( _this.dmodalCss )
+                       //@@bind on resize to disable css dialog to update dmodelCss 
+                       .bind('resizestart', function(event, ui) {
+                                _this.dmodalCss = {};
+                                $j(this).css({});
+                       })
+                       //bind on drag to remove preset style as well
+                       .bind('dragstart', function(event, ui) {
+                                _this.dmodalCss = {};
+                                $j(this).css({});                      
+                       });
+                       //update the child position: (some of this should be pushed up-stream via dialog config options 
+                       $j(_this.target_container +'~ .ui-dialog-buttonpane').css({             
+                               'position':'absolute',          
+                               'left':'0px',
+                               'right':'0px',
+                               'bottom':'0px'
+                       });
+                       //re add cancel button 
+                       _this.cancelClipEditCB();
+                       js_log('done setup of target_container: ' + $j(_this.target_container +'~ .ui-dialog-buttonpane').length);
+                       
+                       
+                       /*var resizeTimer = false;
+                       $j(window).bind('resize', function() {
+                               var adjustModal = function(){
+                                       var layout = _this.getMaxModalLayout();
+                                       //js_log("should adjust: h " + layout.h + ' width:' + layout.w);
+                                       $j(_this.target_container).dialog('option', 'width', layout.w);
+                                       $j(_this.target_container).dialog('option', 'height', layout.h);                                
+                               }
+                               if (resizeTimer) clearTimeout(resizeTimer);
+                               var resizeTimer = setTimeout(adjustModal, 100);
+                       });*/
+               }
+       },
+       getMaxModalLayout:function(border){
+               if(!border)
+                       border = 50;
+               //js_log('setting h:' + (parseInt( $j(document).height() ) - parseInt(border*2)) + ' from:' + $j(document).height() );
+               return { 
+                       'h': parseInt( $j(document).height() ) - parseInt(border*4),
+                       'w': parseInt( $j(document).width() ) - parseInt(border*2),
+                       'r': border,
+                       't': border
+               }       
+       },
+       //sets up the initial html interface
+       init_interface_html:function(){
+               js_log('init_interface_html');
+               var _this = this;
+               var dq = (this.default_query)? this.default_query : '';
+               js_log('f::init_interface_html');
+       
+               var o = '<div class="rsd_control_container" style="width:100%">' +
+                                       '<form id="rsd_form" action="javascript:return false;" method="GET">'+                                                                          
+                                               '<input class="ui-widget-content ui-corner-all" type="text" tabindex="1" value="' + dq + '" maxlength="512" id="rsd_q" name="rsd_q" '+
+                                                       'size="20" autocomplete="off"/> '+                                      
+                                               $j.btnHtml( gM('mv_media_search'), 'rms_search_button', 'search') +                                                                                     
+                                       '</form>';                                                                                      
+               //close up the control container:
+               o+='</div>';
+       
+               //search provider tabs based on "checked" and "enabled" and "combined tab"
+               o+='<div id="rsd_results_container" style="top:0px;bottom:0px;left:0px;right:0px;"></div>';                             
+               $j(this.target_container).html( o );
+                               
+               //add simple styles:
+               $j(this.target_container + ' .rms_search_button').btnBind().click(function(){
+                       _this.runSearch();
+               });
+       
+               //draw the tabs:
+               this.drawTabs();
+               //run the default search:
+               if( this.default_query )
+                       this.runSearch();
+       },
+       add_interface_bindings:function(){
+               var _this = this;
+               js_log("f:add_interface_bindings:");                                    
+       
+
+               $j('#mso_selprovider,#mso_selprovider_close').unbind().click(function(){
+                       if($j('#rsd_options_bar:hidden').length !=0 ){
+                               $j('#rsd_options_bar').animate({
+                                       'height':'110px',
+                                       'opacity':1
+                               }, "normal");
+                       }else{
+                               $j('#rsd_options_bar').animate({
+                                       'height':'0px',
+                                       'opacity':0                             
+                               }, "normal", function(){
+                                       $j(this).hide();
+                               });
+                       }
+               });                                                     
+               //set form bindings
+               $j('#rsd_form').unbind().submit(function(){                                     
+                       _this.runSearch();
+                       //don't submit the form
+                       return false;
+               });     
+       },
+       doUploadInteface:function(){
+               var _this = this;
+               mv_set_loading('#tab-upload');
+               $j('#tab-upload').html('upload interface goes here ;)');
+       
+               //todo include firefogg support:
+               /*mvJsLoader.doLoad( [
+                               'mvUploader'
+                       ],function(){                   
+                               _this.cUpLoader = new mvUploader({
+                                       'target_div': '#tab-upload',
+                                       'upload_done_action:': function( rTitle){
+                                               //set to loading:
+                                               mv_set_loading('#tab-upload');
+                                               //do a direct api query for resource info (to build rObj
+                                               _this.getResourceFromTitle( rTitle, function(rObj){
+                                                       //call resource Edit:
+                                                       _this.resourceEdit( rObj );
+                                               });
+                                       }                                                                                       
+                       });
+               }); */
+       },
+       runSearch: function(){          
+               js_log("f:runSearch::" + this.disp_item);
+               //draw_direct_flag
+               var draw_direct_flag = true;                                    
+               if(!this.content_providers[this.disp_item])     {
+                       js_log("can't run search for:" + this.disp_item);
+                       return false;
+               }                       
+               cp = this.content_providers[this.disp_item];    
+       
+               //check if we need to update:
+               if( typeof cp.sObj != 'undefined' ){
+                       if(cp.sObj.last_query == $j('#rsd_q').val() && cp.sObj.last_offset == cp.offset){
+                               js_log('last query is: ' + cp.sObj.last_query + ' matches: ' +  $j('#rsd_q').val() );                           
+                       }else{
+                               js_log('last query is: ' + cp.sObj.last_query + ' not match: ' +  $j('#rsd_q').val() );
+                               draw_direct_flag = false;
+                       }
+               }else{
+                       draw_direct_flag = false;
+               }
+               if( !draw_direct_flag ){                
+                       //set the content to loading while we do the search:
+                       $j('#tab-' + this.disp_item).html( mv_get_loading_img() );
+       
+                       //make sure the search library is loaded and issue the search request
+                       this.getLibSearchResults( cp );
+               }                                       
+       },
+       //issue a api request & cache the result
+       //this check can be avoided by setting the this.import_url_mode = 'api' | 'form' | insted of 'autodetect' or 'none'
+       checkForCopyURLSupport:function ( callback ){
+               var _this = this;
+               js_log('checkForCopyURLSupport:: ');
+               //see if we already have the import mode: 
+               if( this.import_url_mode != 'autodetect'){
+                       js_log('import mode: ' + _this.import_url_mode);
+                       callback();
+               }
+               //if we don't have the local wiki api defined we can't auto-detect use "link"
+               if(!_this.local_wiki_api_url){
+                       js_log('import mode: remote link (no import_wiki_api_url)');
+                       _this.import_url_mode = 'remote_link';  
+                       callback();
+               }
+               if( this.import_url_mode == 'autodetect' ){
+                       do_api_req( {
+                               'data': { 'action':'paraminfo', 'modules':'upload' },
+                               'url': _this.local_wiki_api_url
+                       }, function(data){                                      
+                               if( typeof data.paraminfo.modules[0].classname == 'undefined'){                                                                 
+                                       //@@todo would be nice if API permission on: action=query&meta=userinfo&uiprop=rights
+                                       // upload_by_url property reflected if $wgAllowCopyUploads config value .. oh well.                                                             
+                                       $j.ajax({
+                                               type: "GET",
+                                               dataType: 'html',
+                                               url: wgArticlePath.replace( '$1', 'Special:Upload' ), //@@todo may have problems in localized special pages
+                                                                                                                          //(could hit meta=siteinfo & specialpagealiases )
+                                                                                                                          // but might be overkill for now cuz we want to switch to new-upload branch soon. 
+                                               success: function( form_html ){                                         
+                                                       if( form_html.indexOf( 'wpUploadFileURL' ) != -1){
+                                                               _this.import_url_mode = 'form';                                                                         
+                                                       }else{
+                                                               _this.import_url_mode = 'none';                                         
+                                                       }
+                                                       js_log('import mode: ' + _this.import_url_mode);
+                                                       callback();
+                                               },
+                                               error: function(){
+                                                       js_log('error in getting Special:Upload page');
+                                                       _this.import_url_mode = 'none';
+                                               
+                                                       js_log('import mode: ' + _this.import_url_mode);
+                                                       callback();
+                                               }
+                                       });
+                               }else{                          
+                                       for( var i in data.paraminfo.modules[0].parameters ){                                   
+                                               var pname = data.paraminfo.modules[0].parameters[i].name;                                       
+                                               if( pname == 'url' ){
+                                                       js_log( 'Autodetect Upload Mode: api: copy by url:: ' );                                                
+                                                       //check permission  too:
+                                                       _this.checkForCopyURLPermission(function( canCopyUrl ){
+                                                               if(canCopyUrl){
+                                                                       _this.import_url_mode = 'api';
+                                                                       js_log('import mode: ' + _this.import_url_mode);
+                                                                       callback();                                                     
+                                                               }else{
+                                                                       _this.import_url_mode = 'none';
+                                                                       js_log('import mode: ' + _this.import_url_mode);
+                                                                       callback();
+                                                               }
+                                                       });
+                                                       break;                                  
+                                               }
+                                       }                       
+                               }
+                       });             
+               }
+       },
+       /*
+       * checkForCopyURLPermission:
+       * not really nessesary the api request to upload will return apopprirate error if the user lacks permission. or $wgAllowCopyUploads is set to false
+       * (use this function if we want to issue a warning up front)
+       */ 
+       checkForCopyURLPermission:function( callback ){
+               var _this = this;
+               //do api check:         
+               do_api_req( {
+                               'data':{ 'action' : 'query', 'meta' : 'userinfo', 'uiprop' : 'rights' },
+                               'url': _this.local_wiki_api_url,
+                               'userinfo' : true
+               }, function(data){                      
+                       for( var i in data.query.userinfo.rights){      
+                               var right = data.query.userinfo.rights[i];
+                               //js_log('checking: ' + right ) ;               
+                               if(right == 'upload_by_url'){
+                                       callback( true );                       
+                                       return true; //break out of the function
+                               }
+                       }
+                       callback( false );                              
+               });
+       },
+       getLibSearchResults:function( cp ){
+               var _this = this;       
+       
+               //first check if we should even run the search at all (can we import / insert into the page? )
+               if( !this.checkRepoLocal( cp ) && this.import_url_mode == 'autodetect' ){
+                       //cp is not local check if we can support the import mode:
+                       this.checkForCopyURLSupport( function(){
+                               _this.getLibSearchResults( cp );
+                       });
+                       return false;
+               }else if( !this.checkRepoLocal( cp ) && this.import_url_mode == 'none'){
+                       if(  this.disp_item == 'combined' ){
+                               //combined results are harder to error handle just ignore that repo
+                               cp.sObj.loading = false;
+                       }else{                  
+                               alert("should set tab to no-good");
+                               $j('#tab-' + this.disp_item).html( '<div style="padding:10px">'+ gM('no_import_by_url') +'</div>');                     
+                       }
+                       return false;
+               }
+               //set up the library req:               
+               mvJsLoader.doLoad( [
+                       'baseRemoteSearch',  
+                       cp.lib +'Search' 
+               ], function(){
+                       js_log("loaded .. disp is: " + _this.disp_item);        
+                       //else we need to run the search:
+                       var iObj = {'cp':cp, 'rsd':_this};              
+                       eval('cp.sObj = new '+cp.lib+'Search( iObj );');
+                       if(!cp.sObj)
+                               js_log('Error: could not find search lib for ' + cp_id);
+               
+                       //inherit defaults if not set:
+                       cp.limit = (cp.limit) ? cp.limit : cp.sObj.limit;
+                       cp.offset = (cp.offset) ? cp.offset : cp.sObj.offset;
+                                       
+                       //do search     
+                       cp.sObj.getSearchResults();                     
+                       _this.checkResultsDone();                       
+               });
+       },
+       /* check for all the results to finish */
+       checkResultsDone: function(){           
+               //js_log('rsd:checkResultsDone');
+               var _this = this;
+               var loading_done = true;                                
+               
+               for(var cp_id in  this.content_providers){
+                       var cp = this.content_providers[ cp_id ];
+                       if(typeof cp['sObj'] != 'undefined'){
+                               if( cp.sObj.loading )
+                                       loading_done=false;
+                       }
+               }               
+               if( loading_done ){                     
+                       this.drawOutputResults();
+               }else{                  
+                       //make sure the instance name is up-to-date refrence to _this;
+                       eval( _this.instance_name + ' = _this');
+                       setTimeout( _this.instance_name + '.checkResultsDone()', 50);
+               }               
+       },
+       drawTabs: function(){
+               var _this = this;       
+               //add the tabs to the rsd_results container:
+               var o='<div id="rsd_tabs_container" style="width:100%;">';
+               var selected_tab = 0;
+               var inx =0;
+               o+= '<ul>';                             
+                       var tabc = '';          
+                       for(var cp_id in  this.content_providers){
+                                       var cp = this.content_providers[cp_id];
+                                       if( cp.enabled && cp.checked){                                  
+                                               //add selected default if set
+                                               if( this.disp_item == cp_id)
+                                                       selected_tab=inx;
+                                                                               
+                                               o+='<li class="rsd_cp_tab">';
+                                               o+='<a id="rsd_tab_' + cp_id + '" href="#tab-' + cp_id + '">';
+                                                       if(cp.tab_img === true){
+                                                               o+='<img alt="' + cp.title +'" src="' + mv_skin_img_path + 'remote_cp/' + cp_id + '_tab.png">';                 
+                                                       }else{
+                                                               o+= cp.title;
+                                                       }
+                                               o+='</a>';
+                                               o+='</li>';
+                                               inx++;
+                                       }                                       
+                                       tabc+='<div id="tab-'+ cp_id +'" class="rsd_results"/>';
+                                                                                       
+                       }
+                       //do an upload tab if enabled:
+                       if( this.enable_upload_tab ){                   
+                               o+='<li class="rsd_cp_tab" ><a id="rsd_tab_upload" href="#tab-upload">' + gM('upload') + '</a></li>';
+                               tabc+='<div id="tab-upload" />';                
+                       }
+                       o+='</ul>';
+                       //output the tab content containers:
+                       o+=tabc;
+               o+='</div>'; //close tab container
+       
+               //output the respective results holders         
+               $j('#rsd_results_container').html(o);   
+               //setup bindings for tabs make them sortable: (@@todo remember order)
+               js_log('selected tab is: ' + selected_tab);     
+               $j("#rsd_tabs_container").tabs({
+                       selected:selected_tab,
+                       select: function(event, ui) {                                                                   
+                               _this.selectTab( $j(ui.tab).attr('id').replace('rsd_tab_', '') );
+                       }               
+               //add sorting
+               }).find(".ui-tabs-nav").sortable({axis:'x'});
+               
+               /*$j('.rsd_cp_tab').click(function(){
+                       _this.selectTab( $j(this).attr('id').replace(/rsd_tab_/, '') );
+               });*/
+       
+               //setup key binding (no longer nessesary tabs provide this functionality)
+               /*$j().keyup(function(e){
+                       js_log('keyup on : ' +e.which );                        
+                       //if escape pressed clear the interface:
+                       if(e.which == 27)
+                               _this.closeAll();               
+               });*/ 
+       
+       },
+       //resource title                
+       getResourceFromTitle:function( rTitle , callback){
+               var _this = this;
+               reqObj={
+                       'action':'query',
+                       'titles': _this.cFileNS + ':' + rTitle
+               };                                                      
+               do_api_req( {
+                       'data':reqObj,
+                       'url':this.local_wiki_api_url
+                       }, function(data){
+                               //@@todo propogate the rObj
+                               var rObj = {};
+                       }
+               );
+       },
+       //@@todo we could load the id with the content provider id to find the object faster...
+       getResourceFromId:function( rid ){
+               //js_log('getResourceFromId:' + rid );
+               //strip out /res/ if preset:
+               rid = rid.replace(/res_/, '');
+               for(var cp_id in  this.content_providers){
+                       cp = this.content_providers[ cp_id ];
+                       if(rid.indexOf( cp_id ) != -1){
+                               rid = rid.replace( cp_id + '_','');             
+                               if(     cp['sObj']){
+                                       for(var rInx in cp.sObj.resultsObj){                    
+                                               if( rInx == rid )
+                                                       return cp.sObj.resultsObj[rInx];
+                                       };
+                               }
+                       }
+               }
+               js_log("ERROR: could not find " + rid);
+               return false;
+       },
+       drawOutputResults: function(){  
+               js_log('f:drawOutputResults::' + this.disp_item);                               
+               var _this = this;               
+               var o='';
+       
+               var cp_id = this.disp_item;
+               var cp = this.content_providers[this.disp_item];
+               
+               //empty the existing results:
+               $j('#tab-' + cp_id).empty();
+       
+               //output the results bar / controls
+               _this.setResultBarControl();
+                       
+               var drawResultCount     =0;
+       
+               //output all the results for the current disp_item              
+               if( typeof cp['sObj'] != 'undefined' ){                         
+                       $j.each(cp.sObj.resultsObj, function(rInx, rItem){                                                                                                      
+                               if( _this.result_display_mode == 'box' ){
+                                       o+='<div id="mv_result_' + rInx + '" class="mv_clip_box_result" style="width:' +
+                                                       _this.thumb_width + 'px;height:'+ (_this.thumb_width-20) +'px;position:relative;">';
+                                               //check for missing poster types for audio
+                                               if( rItem.mime=='audio/ogg' && !rItem.poster ){
+                                                       rItem.poster = mv_skin_img_path + 'sound_music_icon-80.png';                                                            
+                                               }
+                                               //get a thumb with proper resolution transform if possible:
+                                               o+='<img title="'+rItem.title+'" class="rsd_res_item" id="res_' + cp_id + '_' + rInx +
+                                                               '" style="width:' + _this.thumb_width + 'px;" src="' +
+                                                               cp.sObj.getImageTransform( rItem, {'width':_this.thumb_width } )
+                                                               + '">';
+                                               //add a linkback to resource page in upper right:
+                                               if( rItem.link )
+                                                       o+='<a target="_new" style="position:absolute;top:0px;right:0px" title="' +
+                                                                gM('resource_description_page') +
+                                                               '" href="' + rItem.link + '"><img src="http://upload.wikimedia.org/wikipedia/commons/6/6b/Magnify-clip.png"></a>';
+                                               //add license icons if present                  
+                                               if( rItem.license )
+                                                       o+= _this.getlicenseImgSet( rItem.license );                                                                                                                                                                                                                            
+                                       o+='</div>';
+                               }else if(_this.result_display_mode == 'list'){
+                                       o+='<div id="mv_result_' + rInx + '" class="mv_clip_list_result" style="width:90%">';                           
+                                               o+='<img title="'+rItem.title+'" class="rsd_res_item" id="res_' + cp_id + '_' + rInx +'" style="float:left;width:' +
+                                                                _this.thumb_width + 'px;" src="' +
+                                                                cp.sObj.getImageTransform( rItem, {'width':_this.thumb_width } )
+                                                                 + '">';                                                               
+                                               //add license icons if present                  
+                                               if( rItem.license )
+                                                       o+= _this.getlicenseImgSet( rItem.license );                                                    
+                                       
+                                               o+= rItem.desc ;                                
+                                       o+='<div style="clear:both" />';                
+                                       o+='</div>';                                    
+                               }                       
+                               drawResultCount++;                                              
+                       });             
+                       js_log('append to: ' + '#tab-' + cp_id);
+                       //put in the tab output (plus clear the output)
+                       $j('#tab-' + cp_id).append( o + '<div style="clear:both"/>');                                           
+               }
+       
+               js_log( ' drawResultCount :: ' + drawResultCount + ' append: ' + $j('#rsd_q').val() );
+       
+               //remove any old search res
+               $j('#rsd_no_search_res').remove();
+               if( drawResultCount == 0 )
+                       $j('#tab-' + cp_id).append( '<span style="padding:10px">' + gM( 'rsd_no_results', $j('#rsd_q').val() ) + '</span>');                                    
+                                                       
+               this.addResultBindings();
+       },
+       addResultBindings:function(){
+               var _this = this;                               
+               $j('.mv_clip_'+_this.result_display_mode+'_result').hover(function(){
+                       $j(this).addClass('mv_clip_'+_this.result_display_mode+'_result_over');
+                       //also set the animated image if avaliable
+                       var res_id = $j(this).children('.rsd_res_item').attr('id');
+                       var rObj = _this.getResourceFromId( res_id );
+                       if( rObj.poster_ani )                   
+                               $j('#' + res_id ).attr('src', rObj.poster_ani);         
+               },function(){
+                       $j(this).removeClass('mv_clip_'+_this.result_display_mode+'_result_over');
+                       var res_id = $j(this).children('.rsd_res_item').attr('id');
+                       var rObj = _this.getResourceFromId( res_id );
+                       //restore the original (non animated)
+                       if( rObj.poster_ani )
+                               $j('#' + res_id ).attr('src', rObj.poster);
+               });                     
+               //resource click action: (bring up the resource editor)         
+               $j('.rsd_res_item').unbind().click(function(){
+                       var rObj = _this.getResourceFromId( $j(this).attr("id") );                                                                                              
+                       _this.resourceEdit( rObj, this );                                                                       
+               });
+       },
+       resourceEdit:function( rObj, rsdElement){
+               js_log('f:resourceEdit:' + rObj.title); 
+               var _this = this;
+               //remove any existing resource edit interface:
+               $j('#rsd_resource_edit').remove();                      
+               //set the media type:
+               if(rObj.mime.indexOf('image')!=-1){                             
+                       //set width to default image_edit_width
+                       var maxWidth = _this.image_edit_width;  
+                       var mediaType = 'image';                                                                                                
+               }else if(rObj.mime.indexOf('audio')!=-1){
+                       var maxWidth = _this.video_edit_width;
+                       var mediaType = 'audio';
+               }else{
+                       //set to default video size:
+                       var maxWidth = _this.video_edit_width;
+                       var mediaType = 'video';
+               }       
+               //so that transcripts show ontop
+               var overflow_style = ( mediaType =='video' )?'':'overflow:auto;';
+               //append to the top level of model window:
+               $j( _this.target_container ).append('<div id="rsd_resource_edit" '+
+                       'style="position:absolute;top:0px;left:0px;bottom:85px;right:4px;background-color:#FFF;">' +                     
+                               '<div id="clip_edit_disp" style="position:absolute;' + overflow_style + 'width:100%;height:100%;padding:5px;'+
+                                       'width:' + (maxWidth) + 'px;" >' +
+                                               mv_get_loading_img('position:absolute;top:30px;left:30px') +
+                               '</div>'+
+                               '<div id="clip_edit_ctrl" class="ui-widget ui-widget-content ui-corner-all" style="position:absolute;'+
+                                       'left:' + ( maxWidth + 10 ) +'px;top:5px;bottom:10px;right:0px;overflow:auto;padding:5px;">'+
+                                               mv_get_loading_img() +                                   
+                               '</div>'+
+                       '</div>');                      
+               //update add media wizard title:
+               $j( _this.target_container ).dialog( 'option', 'title', gM('add_media_wizard')+': '+ gM('rsd_resource_edit', rObj.title ) );             
+               js_log('did append to: '+ _this.target_container );
+       
+               $j('#rsd_resource_edit').css('opacity',0);
+       
+               $j('#rsd_edit_img').remove();//remove any existing rsd_edit_img
+       
+               //left side holds the image right size the controls /                                                                                                           
+               $j(rsdElement).clone().attr('id', 'rsd_edit_img').appendTo('#clip_edit_disp').css({
+                       'position':'absolute',
+                       'top':'40%',
+                       'left':'20%',
+                       'cursor':'default',
+                       'opacity':0
+               });             
+                                                       
+       
+               //assume we keep aspect ratio for the thumbnail that we clicked:                
+               var tRatio = $j(rsdElement).height() / $j(rsdElement).width();
+               if(     ! tRatio )      
+                       var tRatio = 1; //set ratio to 1 if the width of the thumbnail can't be found for some reason
+       
+               js_log('set from ' +  $j('#rsd_edit_img').width()+'x'+ $j('#rsd_edit_img').height() + ' to init thumbimage to ' + maxWidth + ' x ' + parseInt( tRatio * maxWidth) );
+               //scale up image and to swap with high res version
+               $j('#rsd_edit_img').animate({
+                       'opacity':1,
+                       'top':'5px',
+                       'left':'5px',
+                       'width': maxWidth + 'px',
+                       'height': parseInt( tRatio * maxWidth)  + 'px'
+               }, "slow"); // do it slow to give it a chance to finish loading the HQ version
+       
+               if( mediaType == 'image' ){
+                       _this.loadHQImg(rObj, {'width':maxWidth}, 'rsd_edit_img', function(){                           
+                               $j('.mv_loading_img').remove();                         
+                       });
+               }
+               //also fade in the container:
+               $j('#rsd_resource_edit').animate({
+                       'opacity':1,
+                       'background-color':'#FFF',
+                       'z-index':99
+               });             
+               js_log('do load the media editor:');
+               //do load the media Editor
+               _this.doMediaEdit( rObj , mediaType );
+       },
+       loadHQImg:function(rObj, size, target_img_id, callback){        
+               //get the HQ image url:
+               rObj.pSobj.getImageObj( rObj, size, function( imObj ){          
+                       rObj['edit_url'] = imObj.url;
+               
+                       js_log("edit url: " + rObj.edit_url);
+                       //update the rObj                       
+                       rObj['width'] = imObj.width;
+                       rObj['height'] = imObj.height;
+                       
+                       //see if we need to animate some transition
+                       var newSize = false;
+                       if( size.width != imObj.width ){
+                               js_log('loadHQImg:size mismatch: ' + size.width + ' != ' + imObj.width );
+                               newSize={
+                                       'width':imObj.width + 'px',
+                                       'height':imObj.height + 'px'
+                               }               
+                               //set the target id to the new size:
+                               $j('#'+target_img_id).animate( newSize );
+                       }else{  
+                               js_log('using req size: ' + imObj.width + 'x' + imObj.height);
+                               $j('#'+target_img_id).animate( {'width':imObj.width+'px', 'height' : imObj.height + 'px'});
+                       }
+                       //don't swap it in until its loaded:
+                       var img = new Image();  
+                       // load the image image:                                
+                       $j(img).load(function () {
+                                        $j('#'+target_img_id).attr('src', rObj.edit_url );                             
+                                        //let the caller know we are done and what size we ended up with:
+                                        callback();                                    
+                               }).error(function () {
+                                       js_log("Error with:  " +  rObj.edit_url);
+                               }).attr('src', rObj.edit_url);  
+                       });     
+       },
+       cancelClipEditCB:function(){            
+               var _this = this;               
+               var b_target =   _this.target_container + '~ .ui-dialog-buttonpane';
+               $j('#rsd_resource_edit').remove();
+               js_log("should update: " + b_target + ' with: cancel');
+               $j(b_target).html( $j.btnHtml( 'Cancel' , 'mv_cancel_rsd', 'close'))
+                       .children('.mv_cancel_rsd')
+                       .btnBind()
+                       .click(function(){
+                               $j( _this.target_container).dialog('close');    
+                       })
+                                                                                       
+       },
+       /*set-up the control actions for clipEdit with relevent callbacks */
+       getClipEditControlActions:function(){
+               var _this = this;
+               return {
+                       'insert' :function(rObj){
+                               _this.insertResource(rObj);
+                       },                      
+                       'preview':function(rObj){
+                               _this.previewResource( rObj )
+                       },                      
+                       'cancel' :function(){
+                               _this.cancelClipEditCB()
+                       }                               
+               };
+       },
+       //loads the media editor:
+       doMediaEdit:function( rObj , mediaType){
+               var _this = this;                                                                       
+               var mvClipInit = {
+                               'rObj':rObj, //the resource object
+                               'parent_ct':'rsd_modal_target',
+                               'clip_disp_ct':'clip_edit_disp',
+                               'control_ct': 'clip_edit_ctrl',                                                         
+                               'media_type': mediaType,
+                               'p_rsdObj': _this,              
+                               'controlActionsCb':_this.getClipEditControlActions()                                                                                    
+               };      
+               
+               var clibs = ['mvClipEdit'];
+               if( mediaType == 'image'){
+                       //display the mvClipEdit obj once we are done loading:
+                       mvJsLoader.doLoad( clibs, function(){                   
+                               //run the image clip tools
+                               _this.cEdit = new mvClipEdit( mvClipInit );
+                       });                     
+               }
+               if( mediaType == 'video' || mediaType == 'audio'){
+                       //get any additonal embedding helper meta data prior to doing the acutal embed
+                       // normally this meta should be provided in the search result (but archive.org has a seperate query for more meida meta)
+                       rObj.pSobj.getEmbedTimeMeta( rObj, function(){                                                                                          
+                               //make sure we have the embedVideo libs:                        
+                               mvJsLoader.embedVideoCheck( function(){
+                                       js_log('append html: ' + rObj.pSobj.getEmbedHTML( rObj, {id:'embed_vid'}) );
+                                       $j('#clip_edit_disp').html(
+                                               rObj.pSobj.getEmbedHTML( rObj, {id:'embed_vid'})
+                                       );
+                                       //rewrite by id
+                                       rewrite_by_id('embed_vid',function(){                   
+                                               //grab any information that we got from the ROE xml or parsed from the media file
+                                               rObj.pSobj.getEmbedObjParsedInfo( rObj, 'embed_vid' );
+                                               //add the re-sizable to the doLoad request:                     
+                                               clibs.push( '$j.ui.resizable');
+                                               clibs.push( '$j.fn.hoverIntent');
+                                               mvJsLoader.doLoad(clibs, function(){                                                    
+                                                       //make sure the rsd_edit_img is hidden:
+                                                       $j('#rsd_edit_img').remove();                                                                                                                                                           
+                                                       //run the image clip tools
+                                                       _this.cEdit = new mvClipEdit( mvClipInit );
+                                               });
+                                       });
+                               });
+                       });
+               }               
+       },
+       checkRepoLocal:function( cp ){
+               if( cp.local ){
+                       return true;
+               }else{
+                       //check if we can embed the content locally per a domain name check:            
+                       var local_host = parseUri( this.local_wiki_api_url ).host;
+                       if( cp.local_domains ) {                                                        
+                               for(var i=0;i < cp.local_domains.length; i++){
+                                       var ld = cp.local_domains[i];
+                                        if( local_host.indexOf( ld ) != -1)
+                                                return true;
+                               }
+                       }
+                       return false;
+               }
+       
+       },
+       checkImportResource:function( rObj, cir_callback){      
+               //@@todo get the localized File/Image namespace name or do a general {NS}:Title
+               var cp = rObj.pSobj.cp;
+               var _this = this;                               
+               
+               //update base target_resource_title:            
+               rObj.target_resource_title = rObj.titleKey.replace(/File:|Image:/,'')
+               
+               //check if local repository
+               //or if import mode if just "linking" (we should alaredy have the 'url' 
+       
+               if( this.checkRepoLocal( cp ) || this.import_url_mode == 'remote_link'){
+                       //local repo jump directly to check Import Resource callback:
+                        cir_callback( rObj );
+               }else{                                                                          
+                       //update target_resource_title with resource repository prefix:                         
+                       rObj.target_resource_title = cp.resource_prefix + rObj.target_resource_title; 
+               
+                       //check if the resource is not already on this wiki             
+                       reqObj={
+                               'action':'query', 
+                               'titles': _this.cFileNS + ':' + rObj.target_resource_title,
+                               'prop'          : 'imageinfo',
+                               'iiprop'        : 'url',
+                               'iiurlwidth': '400'                             
+                       };                              
+               
+                       do_api_req( {
+                               'data':reqObj,
+                               'url':this.local_wiki_api_url
+                               }, function(data){
+                                       var found_title = false;
+                                       for(var i in data.query.pages){
+                                               if( i != '-1' && i != '-2' ){
+                                                       js_log('found title: ' + i + ':' +  data.query.pages[i]['title']);
+                                                       found_title=data.query.pages[i]['title'];
+                                                       //update to local src                                           
+                                                       rObj.local_src = data.query.pages[i]['imageinfo'][0].url;
+                                                       //@@todo maybe  update poster too?                      
+                                                       rObj.local_poster = data.query.pages[i]['imageinfo'][0].thumburl;                               
+                                               }
+                                       }               
+                                       if( found_title ){                      
+                                               js_log("checkImportResource:found title:" + found_title); 
+                                               //resource is already present (or resource with same name is already present)
+                                               rObj.target_resource_title = found_title.replace(/File:|Image:/,'');                                                            
+                                               cir_callback( rObj );
+                                       }else{
+                                               js_log("resource not present: update:"+ _this.cFileNS + ':' + rObj.target_resource_title);
+                                       
+                                               //update the rObj with import info
+                                               rObj.pSobj.updateDataForImport( rObj );                                                                 
+                               
+                                               //setup the resource description from resource description:                                     
+                                               var wt = '{{Information '+"\n"+
+                                                       '|Description= ' + rObj.pSobj.getImportResourceDescWiki( rObj );
+                                               //output person and bill info if
+                                               wt+='|Source=' + '[' +  $j.trim( rObj.link ) + ' Original Source]'+ "\n";
+                                       
+                                               if( rObj.author )
+                                                       wt+='|Author=' + rObj.author +"\n";                                                                     
+                                               
+                                               if( rObj.date )
+                                                       wt+='|Date=' + rObj.date +"\n";                                                 
+                                       
+                                               //add the Permision info:                                               
+                                               wt+='|Permission=' + rObj.pSobj.getPermissionWikiTag( rObj ) +"\n";
+                                               
+                                               if( rObj.other_versions )
+                                                       wt+='|other_versions=' + rObj.other_versions + "\n";
+                                                                                       
+                                               wt+='}}';
+                                               //get any extra categories or helpful links
+                                               wt+= rObj.pSobj.getExtraResourceDescWiki( rObj );
+                               
+                                       
+                                               $j('#rsd_resource_import').remove();//remove any old resource imports
+                                               //@@ show user dialog to import the resource
+                                               $j( _this.target_container ).append('<div id="rsd_resource_import" '+
+                                               'class="ui-state-highlight ui-widget-content ui-state-error" ' + 
+                                               'style="position:absolute;top:50px;left:50px;right:50px;bottom:50px;z-index:5">' +
+                                                       '<h3 style="color:red">Resource: <span style="color:black">' + rObj.title + '</span> needs to be imported</h3>'+
+                                                               '<div id="rsd_preview_import_container" style="position:absolute;width:50%;bottom:0px;left:0px;overflow:auto;top:30px;">' +
+                                                                       rObj.pSobj.getEmbedHTML( rObj, {'id': _this.target_container + '_rsd_pv_vid', 'max_height':'200','only_poster':true} )+ //get embedHTML with small thumb:
+                                                                       '<br style="clear both">'+
+                                                                       '<strong>Resource Page Description:</strong>'+
+                                                                       '<div id="rsd_import_desc" syle="display:inline;">'+
+                                                                               mv_get_loading_img('position:absolute;top:5px;left:5px') +
+                                                                       '</div>'+                                               
+                                                               '</div>'+
+                                                               '<div id="rds_edit_import_container" style="position:absolute;left:50%;' +
+                                                                       'bottom:0px;top:30px;right:0px;overflow:auto;">'+
+                                                                       '<strong>Local Resource Title:</strong><br>'+
+                                                                       '<input type="text" size="30" value="' + rObj.target_resource_title + '" readonly="true"><br>'+
+                                                                       '<strong>Edit WikiText Resource Description:</strong>(will be replaced by forms soon)' +                                                                                                                                                                                                
+                                                                       '<textarea id="rsd_import_ta" id="mv_img_desc" style="width:90%;" rows="8" cols="50">' +
+                                                                               wt +
+                                                                       '</textarea><br>' +
+                                                                       '<input type="checkbox" value="true" id="wpWatchthis" name="wpWatchthis" tabindex="7"/>' +
+                                                                       '<label for="wpWatchthis">Watch this page</label><br><br><br>' +
+                                                               
+                                                                       $j.btnHtml('Do Import Resource', 'rsd_import_doimport', 'check' ) + ' ' +
+                                                                        
+                                                                       $j.btnHtml('Update Preview', 'rsd_import_apreview', 'refresh' ) + '<div style="clear:both;height:20px;"/>' +
+                                                               
+                                                                       $j.btnHtml('Cancel Import', 'rsd_import_acancel', 'close' ) + ' ' +
+                                                                                                                                                       
+                                                               '</div>'+
+                                                               //output the rendered and non-renderd version of description for easy swiching:
+                                               '</div>');
+                                               //add hover:                                                            
+                                               //update video tag
+                                               rewrite_by_id(_this.target_container + '_rsd_pv_vid');
+                                               //load the preview text:                                        
+                                               _this.getParsedWikiText( wt, _this.cFileNS +':'+ rObj.target_resource_title, function( o ){                                     
+                                                       $j('#rsd_import_desc').html(o);
+                                               });
+                                               //add bidings:                          
+                                               $j( _this.target_container + ' .rsd_import_apreview').btnBind().click(function(){
+                                                       /*$j('#rsd_import_desc').show().html(
+                                                               mv_get_loading_img()
+                                                       );*/
+                                                       //load the preview text:
+                                                       _this.getParsedWikiText( $j('#rsd_import_ta').val(), _this.cFileNS +':'+ rObj.target_resource_title, function( o ){
+                                                               js_log('got updated preivew: ');
+                                                               $j('#rsd_import_desc').html(o);
+                                                       });
+                                               });
+                                               $j(_this.target_container + ' .rsd_import_doimport').btnBind().click(function(){                                                
+                                                       //check import mode:
+                                                       if(_this.import_url_mode=='form'){
+                                                               _this.doImportSpecialPage( rObj, cir_callback );
+                                                       }else if( _this.import_url_mode=='api'){
+                                                               _this.doImportAPI( rObj , cir_callback);
+                                                       }else{
+                                                               js_log("Error: import mode is not form or API (can not copy asset)");
+                                                       }                       
+                                               });
+                                               $j( _this.target_container + ' .rsd_import_acancel').btnBind().click(function(){
+                                                       $j('#rsd_resource_import').fadeOut("fast",function(){
+                                                               $j(this).remove();
+                                                       });
+                                               });     
+                                       }                       
+                               }
+                       );                                                                                              
+               }
+       },
+       doImportAPI:function(rObj, cir_callback){
+               var _this = this;
+               //baseUploadInterface
+               mvJsLoader.doLoad([
+                       'mvBaseUploadInterface',                
+                       '$j.ui.progressbar'     
+               ],function(){    
+                       
+                       //initicate a download similar to url copy:
+                       myUp = new mvBaseUploadInterface({
+                               'api_url' : _this.local_wiki_api_url,
+                               'done_upload_cb':function(){
+                                  //we have finished the upload:
+                                 
+                                  //close up the rsd_resource_import
+                                  $j('#rsd_resource_import').remove();
+                                  //run the parent callback:
+                                  cir_callback(); 
+                               }
+                       });
+                       //set the edit token if we have it handy
+                       _this.getEditToken(function( token ){
+                               myUp.etoken = token;
+                               myUp.doHttpUpload({
+                                       'url'       : rObj.src,         
+                                       'filename'  : rObj.target_resource_title,
+                                       'comment'   : $j('#rsd_import_ta').val()                                
+                               });
+                       })
+                       
+                       
+               });                             
+       },
+       getEditToken:function(callback){
+               //first try the page form: 
+               var etoken = $j("input[name='wpEditToken']").val();
+               if(etoken){             
+                       callback( etoken );
+                       return ; 
+               }
+               //@@todo try to load over ajax if( _this.local_wiki_api_url ) is set 
+               // (your on the api domain but are inserting from a normal page view) 
+               if( _this.local_wiki_api_url){
+                               
+               }               
+       },
+       /**
+        * doImportSpecialPage
+        * can be depricated once we support upload api support is widespred.
+        */
+       doImportSpecialPage:function(rObj, cir_callback){
+               var _this = this;
+                //get an edittoken:
+               do_api_req( {
+                       'data': {       'action':'query',
+                                               'prop':'info',
+                                               'intoken':'edit',
+                                               'titles': rObj.titleKey
+                                       },
+                       'url':_this.local_wiki_api_url
+                       }, function(data){
+                               //could recheck if it has been created in the mean time
+                               if( data.query.pages[-1] ){                                                             
+                                       var editToken = data.query.pages[-1]['edittoken'];
+                                       if(!editToken){
+                                               //@@todo give an ajax login or be more friendly in some way: 
+                                               js_error("You don't have permission to upload (are you logged in?)");
+                                               //remove top level:
+                                               $j('#modalbox').fadeOut("normal",function(){
+                                                       $j(this).remove();
+                                                       $j('#mv_overlay').remove();
+                                               });
+                                       }else{                                                  
+                                               //not sure if we can do remote url uploads (so just do a local post)
+                                               js_log('got token for new page:' +editToken);                                                                           
+                                               var postVars = {
+                                                       'wpSourceType'          :'web',
+                                                       'wpUploadFileURL'        : rObj.src,
+                                                       'wpDestFile'              : rObj.target_resource_title,
+                                                       'wpUploadDescription' : $j('#rsd_import_ta').val(),
+                                                       'wpWatchthis'            : $j('#wpWatchthis').val(),    
+                                                       'wpUpload'                      : 'Upload file'                                                                                                                                                                                                                                                                                                                         
+                                               }
+                                               //set to uploading:                                                                                                                                                                                     
+                                               $j('#rsd_resource_import').append('<div id="rsd_import_progress"'+                                                                      
+                                                       'style="position:absolute;top:0px;'+
+                                                               'left:0px;width:100%;height:100%;'+                                                                             
+                                                               'z-index:5;background:#FFF;overflow:auto;">'+
+                                                                       '<div style="position:absolute;left:30%;right:30%"><h3>Importing Asset</h3><br>' +
+                                                                               mv_get_loading_img('','mv_loading_bar_img') +
+                                                                       '</div>'+                               
+                                                       '</div>'                                                                                                                                                        
+                                               );                                                      
+                                               $j.post(wgArticlePath.replace(/\$1/,'Special:Upload'),
+                                                       postVars,
+                                                       function(data){                                                                         
+                                                               //@@todo this will be replaced once we add upload image support to the api.
+                                                       
+                                                               //very basic test to see if we got passed to the image page:
+                                                               //@@todo more normalization stuff
+                                                               var sstring ='var wgPageName = "' + _this.cFileNS + ':' + rObj.target_resource_title.replace(/ /g,'_') +'"';
+                                                               if(data.indexOf( sstring ) !=-1){
+                                                                       js_log('found: ' + sstring);
+                                                                       $j('#rsd_resource_import').remove();                                                                            
+                                                                       cir_callback( rObj );
+                                                               }else{                                                                                                  
+                                                                       js_log("Error or warning: (did not find: \"" + sstring + ' in output' );
+                                                                       pos_etitle = '<h1 class="firstHeading">';
+                                                                       var error_txt = form_txt = '';                                                                                                                                                                                                                                                                                                                                                                                                          
+                                                                       var res = grabWikiFormError( data );
+                                                               
+                                                                       if( res.error_txt )
+                                                                               error_txt = res.error_txt;
+                                                                               
+                                                                       if( res.form_txt )
+                                                                               form_txt = res.form_txt;
+                                                                       
+                                                                       js_log( 'error text is: ' + error_txt );        
+                                                                       $j( '#rsd_resource_import' ).html( '<h3>Error</h3>' + error_txt + '<br>' + form_txt +
+                                                                                       '<br>'+
+                                                                               '<a href="#" id="rsd_import_error" >Cancel import</a>'
+                                                                       );
+                                                                       //set up cancel action:
+                                                                       $j('#rsd_import_error').click(function(){
+                                                                               $j('#rsd_resource_import').remove();
+                                                                       });
+                                                               }
+                                                               
+                                                       }
+                                               );
+                                       }                                                       
+                               }
+                       }
+               );  
+       },
+       previewResource:function( rObj ){
+               var _this = this;
+               this.checkImportResource( rObj, function(){     
+                       //put another window ontop:
+                       $j( _this.target_container ).append('<div id="rsd_preview_display"' +
+                                       'style="position:absolute;overflow:hidden;z-index:4;top:0px;bottom:75px;right:0px;left:0px;background-color:#FFF;">' +
+                                               mv_get_loading_img('top:30px;left:30px') +
+                                       '</div>');
+                                       
+                       var bPlaneTarget = _this.target_container +'~ .ui-dialog-buttonpane';
+                       var pTitle = $j( _this.target_container ).dialog('option', 'title');                    
+                       
+                       //update title: 
+                       $j( _this.target_container ).dialog('option', 'title', 'Preview Insert of Resource: ' + rObj.title );   
+                                       
+                       //update buttons preview: 
+                       $j(bPlaneTarget).html( $j.btnHtml( gM('rsd_do_insert'), 'preview_do_insert', 'check') + ' ' )
+                               .children('.preview_do_insert')
+                               .click(function(){
+                                       _this.insertResource( rObj );
+                               });
+                       //update cancel button
+                       $j(bPlaneTarget).append('<a href="#" class="preview_close">Do More Modification</a>')
+                               .children('.preview_close')
+                               .click(function(){
+                                       $j('#rsd_preview_display').remove();
+                                       //restore title: 
+                                       $j( _this.target_container ).dialog('option', 'title', pTitle);
+                                       //restore buttons (from the clipEdit object::) 
+                                       _this.cEdit.updateInsertControlActions();
+                               });
+                                                                       
+                       //update the preview_wtext
+                       _this.updatePreviewText( rObj );                        
+                       _this.getParsedWikiText(_this.preview_wtext, _this.target_title,
+                               function(phtml){
+                                       $j('#rsd_preview_display').html( phtml );
+                                       //update the display of video tag items (if any)
+                                       mwdomReady(true);
+                               }
+                       );
+               });             
+       },
+       updatePreviewText:function( rObj ){
+               var _this = this;
+                       
+               if(_this.import_url_mode=='remote_link'){
+                       _this.cur_embed_code = rObj.pSobj.getEmbedHTML(rObj);
+               }else{
+                       _this.cur_embed_code = rObj.pSobj.getEmbedWikiCode( rObj );
+               }
+               
+               //insert at start if textInput cursor has not been set (ie == length)
+               if( _this.caret_pos &&  _this.caret_pos.text){
+                       if( _this.caret_pos.text.length == _this.caret_pos.s)
+                               _this.caret_pos.s=0;
+                       _this.preview_wtext = _this.caret_pos.text.substring(0, _this.caret_pos.s) +
+                                                                       _this.cur_embed_code +
+                                                                  _this.caret_pos.text.substring( _this.caret_pos.s );
+               }else{
+                  _this.preview_wtext =  $j(_this.target_textbox).val() +  _this.cur_embed_code;
+               }               
+               //check for missing </refrences>
+               if( _this.preview_wtext.indexOf('<references/>') ==-1 &&  _this.preview_wtext.indexOf('<ref>') != -1 )
+                        _this.preview_wtext =  _this.preview_wtext + '<references/>';
+       },
+       getParsedWikiText:function( wikitext, title,  callback ){
+               do_api_req( {
+                       'data':{'action':'parse',
+                                       'text':wikitext
+                                  },
+                       'url':this.local_wiki_api_url
+                       },function(data){                       
+                               callback( data.parse.text['*'] );
+                       }
+               );
+       },
+       insertResource:function( rObj){ 
+               js_log('insertResource: ' + rObj.title);
+               var _this = this
+               //dobule check that the resource is present:
+               this.checkImportResource( rObj, function(){
+                       _this.updatePreviewText( rObj );                                        
+                       $j(_this.target_textbox).val( _this.preview_wtext );
+                       
+                       //update the render area (if present)  
+                       if(_this.target_render_area && _this.cur_embed_code){                   
+                                //output with some padding: 
+                                $j(_this.target_render_area).append( _this.cur_embed_code + '<div style="clear:both;height:10px">')
+                                //update if its video or audio:
+                                if( rObj.mime.indexOf('audio')!=-1 || 
+                                        rObj.mime.indexOf('video')!=-1 ||
+                                        rObj.mime.indexOf('/ogg') !=-1){
+                                        mvJsLoader.embedVideoCheck(function(){
+                                               mv_video_embed();                                
+                                        });
+                                }
+                       }                                               
+                       _this.closeAll();
+               });             
+       },
+       closeAll:function(){
+                var _this = this;
+                js_log("close all");
+                $j('#rsd_resource_preview').remove();
+                $j('#rsd_resource_edit').remove();
+                $j(_this.target_container).dialog('close');             
+       },
+       setResultBarControl:function( ){
+               var _this = this;
+               var box_dark_url         = mv_skin_img_path + 'box_layout_icon_dark.png';
+               var box_light_url        = mv_skin_img_path + 'box_layout_icon.png';
+               var list_dark_url        = mv_skin_img_path + 'list_layout_icon_dark.png';
+               var list_light_url       = mv_skin_img_path + 'list_layout_icon.png';
+       
+               var about_desc ='';
+               if( this.content_providers[this.disp_item] ){
+                       var cp = this.content_providers[this.disp_item];
+                       about_desc ='<span style="position:relative;top:0px;font-style:italic;">' +
+                                       '<i>' + gM('results_from', cp.homepage, cp.title) + '</i></span>';      
+                       $j('#tab-'+this.disp_item).append( '<div id="rds_results_bar">'+                                                
+                               '<span style="float:left;top:0px;font-style:italic;">'+
+                                       gM('rsd_layout')+' '+                           
+                                       '<img id="msc_box_layout" ' +
+                                               'title = "' + gM('rsd_box_layout') + '" '+
+                                               'src = "' +  ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) + '" ' +         
+                                               'style="width:20px;height:20px;cursor:pointer;"> ' +
+                                       '<img id="msc_list_layout" '+
+                                               'title = "' + gM('rsd_list_layout') + '" '+
+                                               'src = "' +  ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) + '" '+               
+                                               'style="width:20px;height:20px;cursor:pointer;">'+              
+                                       about_desc +
+                               '</span>'+
+                               '<span id="rsd_paging_ctrl" style="float:right;"></span>'+              
+                               '</div>'
+                       );
+                       //get paging with bindings:
+                       this.getPaging('#rsd_paging_ctrl');
+                               
+                       $j('#msc_box_layout').hover(function(){         
+                               $j(this).attr("src", box_dark_url );
+                       }, function(){
+                               $j(this).attr("src",  ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) );      
+                       }).click(function(){
+                               $j(this).attr("src", box_dark_url);
+                               $j('#msc_list_layout').attr("src", list_light_url);
+                               _this.setDispMode('box');
+                       });
+               
+                       $j('#msc_list_layout').hover(function(){
+                               $j(this).attr("src", list_dark_url);
+                       }, function(){
+                               $j(this).attr("src", ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) );    
+                       }).click(function(){
+                               $j(this).attr("src", list_dark_url);
+                               $j('#msc_box_layout').attr("src", box_light_url);
+                               _this.setDispMode('list');
+                       });
+               }
+       },
+       getPaging:function(target){
+               var _this = this;
+               var cp_id = this.disp_item;
+               var cp = this.content_providers[ this.disp_item ];                                              
+               //js_log('getPaging:'+ cp_id + ' len: ' + cp.sObj.num_results);
+               var to_num = ( cp.limit > cp.sObj.num_results )?
+                                               (cp.offset + cp.sObj.num_results):
+                                               (cp.offset + cp.limit); 
+               var out = gM('rsd_results_desc') + ' ' +  (cp.offset+1) + ' to ' + to_num;
+               //check if we have more results (next prev link)
+               if(  cp.offset >=  cp.limit )
+                       out+=' <a href="#" id="rsd_pprev">' + gM('rsd_results_prev') + ' ' + cp.limit + '</a>';
+               
+               if( cp.sObj.more_results )                              
+                       out+=' <a href="#" id="rsd_pnext">' + gM('rsd_results_next') + ' ' + cp.limit + '</a>';
+               
+               $j(target).html(out);
+               //set bindings
+               $j('#rsd_pnext').click(function(){
+                       cp.offset += cp.limit;
+                       _this.runSearch();
+               });
+               $j('#rsd_pprev').click(function(){
+                       cp.offset -= cp.limit;
+                       if(cp.offset<0)
+                               cp.offset=0;
+                       _this.runSearch();
+               });
+       
+               return;                                                         
+
+       },
+       selectTab:function( selected_cp_id ){
+               js_log('select tab: ' + selected_cp_id);
+               this.disp_item = selected_cp_id;                                                
+               if( this.disp_item == 'upload' ){
+                       this.doUploadInteface();
+               }else{
+                       //update the search results:
+                       this.runSearch();
+               }                       
+       },
+       setDispMode:function(mode){
+               js_log('setDispMode:' + mode);
+               this.result_display_mode=mode;
+               //run /update search display:
+               this.drawOutputResults();
+       }
+};
diff --git a/js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js
new file mode 100644 (file)
index 0000000..83d2111
--- /dev/null
@@ -0,0 +1,119 @@
+//archive.org uses solr engine: 
+//more about solr here: 
+//http://lucene.apache.org/solr/
+
+var archiveOrgSearch = function ( iObj){
+       return this.init( iObj );
+}
+archiveOrgSearch.prototype = {
+       //archive.org constants: 
+       dnUrl:'http://www.archive.org/download/',
+       dtUrl:'http://www.archive.org/details/',
+       init:function( iObj ){
+               //init base class and inherit: 
+               var baseSearch = new baseRemoteSearch( iObj );
+               for(var i in baseSearch){
+                       if(typeof this[i] =='undefined'){
+                               this[i] = baseSearch[i];
+                       }else{
+                               this['parent_'+i] =  baseSearch[i];
+                       }
+               }
+               //inherit the cp settings for 
+       },
+       getSearchResults:function(){
+               //call parent: 
+               this.parent_getSearchResults();
+               
+               var _this = this;               
+               this.loading=true;
+               js_log('f:getSearchResults for:' + $j('#rsd_q').val() );                
+               //build the query var
+               var q = $j('#rsd_q').val();
+               //@@todo check advanced options: include audio and images media types
+               //for now force (Ogg video) & a creativecommons license
+               q+=' format:(Ogg video)';
+               q+=' licenseurl:(http\\:\\/\\/*)';
+               var reqObj = {
+                       'q': q, //just search for video atm
+                       'fl':"description,title,identifier,licenseurl,format,license,thumbnail",                        
+                       'wt':'json',                    
+                       'rows':'30',
+                       'indent':'yes'                  
+               }                                                                       
+               do_api_req( {
+                       'data':reqObj, 
+                       'url':this.cp.api_url,
+                       'jsonCB':'json.wrf'
+                       }, function(data){                              
+                               _this.addResults( data);
+                               _this.loading = false;
+                       }
+               );
+       },
+       addResults:function( data ){            
+               var _this = this;                       
+               if(data.response && data.response.docs){
+                       //set result info: 
+                       this.num_results = data.response.numFound;
+               
+                       for(var resource_id in data.response.docs){
+                               var resource = data.response.docs[resource_id];                         
+                               var rObj = {
+                                       //@@todo we should add .ogv or oga if video or audio:
+                                       'titleKey'       :  resource.identifier + '.ogg',
+                                       'resourceKey':  resource.identifier,                            
+                                       'link'           : _this.dtUrl + resource.identifier,                           
+                                       'title'          : resource.title,
+                                       'poster'         : _this.dnUrl + resource.identifier+'/format=thumbnail',
+                                       'poster_ani' : _this.dnUrl + resource.identifier+'/format=Animated+Gif',
+                                       'thumbwidth' : 160,
+                                       'thumbheight': 110,                     
+                                       'desc'           : resource.description,
+                                       'src'             : _this.dnUrl + resource.identifier+'/format=Ogg+video',
+                                       'mime'            : 'application/ogg',
+                                       //set the licence: (rsd is a pointer to the parent remoteSearchDriver )          
+                                       'license'         : this.rsd.getLicenceFromUrl( resource.licenseurl ),
+                                       'pSobj'          :_this                         
+                                       
+                               };                                                                                                                                                                                                               
+                               this.resultsObj[ resource_id ] = rObj;
+                               
+                               //likely a audio clip if no poster and type application/ogg 
+                               //@@todo we should return audio/ogg for the mime type or some other way to specify its "audio" 
+                                               
+                               //this.num_results++;   
+                               //for(var i in this.resultsObj[page_id]){
+                               //      js_log('added: '+ i +' '+ this.resultsObj[page_id][i]);
+                               //}
+                       }
+               }               
+       },
+       getEmbedTimeMeta:function(rObj, callback){
+               var _this = this;
+               do_api_req( {
+                       'data':{'avinfo':1},
+                       'url':_this.dnUrl + rObj.resourceKey + '/format=Ogg+video'
+               },function(data){                       
+                       var cat = data;
+                       if(data['length'])
+                               rObj.duration = data['length'];
+                       if(data['width'])
+                               rObj.width = data['width'];
+                       if(data['height'])
+                               rObj.height = data['height'];
+                                                                  
+                       callback();
+               });
+       },
+       getEmbedHTML: function( rObj , options) {
+               js_log('getEmbedHTML:: ' + rObj.poster );
+               if(!options)
+                       options ={};
+               var id_attr = (options['id'])?' id = "' + options['id'] +'" ': '';
+               var src = rObj.src + '?t=0:0:0/'+ seconds2npt( rObj.duration );
+               if(rObj.mime == 'application/ogg' || rObj.mime == 'audio/ogg' || rObj.mime=='video/ogg'){
+                       return '<video ' + id_attr + ' src="' + src + '" poster="' + rObj.poster + '" type="video/ogg"></video>';
+               }
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js
new file mode 100644 (file)
index 0000000..c21426c
--- /dev/null
@@ -0,0 +1,212 @@
+//base remote search obj 
+
+// @key is name of rObj variable 
+// @value is where to find the value in the item xml
+// 
+// *format:*  
+// . indicates multiple tags @ seperates the tag from attribute list 
+// {.}tag_name@{attribute1|attribute12}
+// @@todo should probably switch this over to something like Xpath if we end up parsing a lot of rss formats 
+var rsd_default_rss_item_mapping = {    
+       'poster'        : 'media:thumbnail@url',
+       'roe_url'       : 'media:roe_embed@url',
+       'person'        : 'media:person@label|url',     
+       'parent_clip':'media:parent_clip@url',
+       'bill'          : 'media:bill@label|url',       
+       'title'         : 'title',
+       'link'          : 'link',
+       'desc'          : 'description',
+       //multiple items
+       'category'  : '.media:category@label|url'
+}
+
+var baseRemoteSearch = function(iObj) {
+       return this.init(iObj);
+};
+baseRemoteSearch.prototype = {
+       
+       completed_req:0,
+       num_req:0,      
+               
+       resultsObj:{},  
+       
+       //default search result values for paging: 
+       offset                   :0,    
+       limit                     :20,
+       more_results    :false,
+       num_results             :0,     
+       
+       //init the object: 
+       init: function( iObj ){         
+               js_log('mvBaseRemoteSearch:init');
+               for(var i in iObj){
+                       this[i] = iObj[i];
+               }
+               return this;
+       },      
+       getSearchResults:function(){
+               //empty out the current results before issuing a request 
+               this.resultsObj = {};
+               //do global getSearchResults bindings
+               this.last_query = $j('#rsd_q').val();
+               this.last_offset = this.cp.offset;
+               //@@todo its possible that video rss is the "default" format we could put that logic here: 
+       },      
+       /*
+       * Parses and adds video rss based input format
+       * @param $data XML data to parse
+       * @param provider_url    the source url (used to generate absolute links)  
+       */
+       addRSSData:function( data , provider_url ){     
+               js_log('f:addRSSData');
+               var _this = this;
+               var http_host = '';
+               var http_path = '';             
+               if(provider_url){
+                       pUrl =  parseUri( provider_url );
+                       http_host = pUrl.protocol +'://'+ pUrl.authority;  
+                       http_path = pUrl.directory;     
+               }                       
+               var items = data.getElementsByTagName('item');
+               //js_log('found ' + items.length );
+               $j.each(items, function(inx, item){             
+                       var rObj = {};                  
+                       for(var i in rsd_default_rss_item_mapping){                                                                                                             
+                               var selector = rsd_default_rss_item_mapping[i].split('@');                                                              
+                               
+                               var flag_multiple = (  selector[0].substr(0,1) == '.' ) ? true : false;
+                               if( flag_multiple ){
+                                       rObj[i] = new Array();
+                                       var tag_name = selector[0].substr(1);
+                               }else{                                  
+                                       var tag_name = selector[0];
+                               }
+                               
+                               var attr_name = null;                                                                                           
+                               if( typeof selector[1] != 'undefined'){
+                                       attr_name = selector[1];                                                                        
+                                       if( attr_name.indexOf('|') != -1 )
+                                               attr_name = attr_name.split('|');       
+                               }
+                                                                                                                                                                                                               
+                               $j.each(item.getElementsByTagName( tag_name ), function (inx, node){                                                    
+                                       var tag_val = '';                                                                                                
+                                       if( node!=null && attr_name == null ){                                  
+                                               if( node.childNodes[0] != null){                                                                        
+                                                       //trim and strip html:
+                                                       tag_val = $j.trim( node.firstChild.nodeValue ).replace(/(<([^>]+)>)/ig,"");                                                      
+                                               }
+                                       }                               
+                                       if( node!=null && attr_name != null){
+                                               if(typeof attr_name == 'string'){ 
+                                                       tag_val = $j.trim( $j(node).attr( attr_name ) );
+                                               }else{
+                                                       var attr_vals = {};
+                                                       for(var j in attr_name){
+                                                               if( $j(node).attr( attr_name[j]).length != 0)
+                                                                       attr_vals[ attr_name[j] ] = $j.trim( $j(node).attr( attr_name[j]) ).replace(/(<([^>]+)>)/ig,"");
+                                                       }
+                                                       tag_val = attr_vals ;
+                                               }
+                                       }                                                                                                                                                                                                       
+                                       if(flag_multiple){
+                                               rObj[i].push( tag_val)
+                                       }else{
+                                               rObj[i] = tag_val;
+                                       }                                                                                                                                                        
+                               });             
+                               
+                                                                       
+                       } // done with property loop
+                                               
+                               
+                       //make relative urls absolute:
+                       var url_param = new Array('src', 'poster'); 
+                       for(var j=0; j < url_param.length; j++){
+                               var p = url_param[j];
+                               if(typeof rObj[p] != 'undefined'){
+                                       if( rObj[p].substr(0,1)=='/' ){                         
+                                               rObj[p] = http_host + rObj[p];
+                                       }
+                                       if( parseUri( rObj[i] ).host ==  rObj[p]){
+                                               rObj[p] = http_host + http_path + rObj[p];
+                                       }
+                               }
+                       }                       
+                       //force a mime type for now.. in the future generalize for other RSS feeds and conversions 
+                       rObj['mime'] = 'video/ogg';
+                       //add pointer to parent search obj:( this.cp.limit )? this.cp.limit : this.limit,
+               
+                       rObj['pSobj'] = _this;
+                       //add the result to the result set: 
+                       _this.resultsObj[ inx ] = rObj; 
+                       _this.num_results++;
+               });             
+       },              
+       //by default just return the existing image with callback 
+       getImageObj:function( rObj, size, callback){
+               callback( {'url':rObj.poster} );
+       },
+       //by default just return the rObj.desc
+       getInlineDescWiki:function( rObj ){
+               //return striped html  & trim white space 
+               if(rObj.desc)
+                       return $j.trim( rObj.desc.replace(/(<([^>]+)>)/ig,"") );
+               //no desc avaliable: 
+               return '';
+       },
+       //default license permission wiki text is cc based template mapping (does not confirm the templates actually exist)  
+       getPermissionWikiTag: function( rObj ){
+               if(!rObj.license)                               
+                       return '';//no license info
+               //check that its a defined creative commons licnese key: 
+               if(  this.rsd.licenses.cc.licenses[ rObj.license.key ] != 'undefined' ){
+                       return '{{Cc-' + rObj.license.key + '}}';
+               }else if( rObj.license.lurl ) {
+                       return '{{Template:External_License|' + rObj.license.lurl + '}}';
+               }               
+               
+       },
+       getImportResourceDescWiki:function(rObj){
+               return rObj.title + ' imported from ' + '[' + this.cp.homepage + 
+                       ' ' + this.cp.title+']';
+       },
+       //for thigns like categories and the like
+       getExtraResourceDescWiki:function( rObj ){
+               return '';
+       },
+       //by default just return the poster (clients can overide) 
+       getImageTransform:function(rObj, opt){
+               return rObj.poster;
+       },
+       getEmbedObjParsedInfo:function(rObj, eb_id){
+               return rObj;
+       },
+       getEmbedTimeMeta:function(rObj, callback){
+               callback();
+       },
+       getEmbedWikiCode:function(rObj){                        
+               var layout = ( rObj.layout)? rObj.layout:"right"
+               var o= '[[' + this.rsd.cFileNS + ':' + rObj.target_resource_title + '|thumb|'+layout;
+               
+               if(!rObj.target_width && rObj.width){
+                       rObj.target_width = (rObj.width < 640)? rObj.width: '640';
+               }
+               
+               if(rObj.target_width)
+                       o+='|' + rObj.target_width + 'px';
+               
+               if( rObj.inlineDesc ) 
+                       o+='|' + rObj.inlineDesc;
+                       
+               o+=']]';
+               return o;
+       },
+       updateTargetResourceTitle:function(rObj){
+               rObj.target_resource_title = rObj.titleKey.replace(/File:|Image:/,'');                                                          
+               rObj.target_resource_title = this.cp.resource_prefix + rObj.target_resource_title;
+       },
+       updateDataForImport:function( rObj ){
+               return rObj;
+       }
+}
diff --git a/js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js
new file mode 100644 (file)
index 0000000..1b9c3ab
--- /dev/null
@@ -0,0 +1,22 @@
+var flickrOrgSearch = function ( iObj){
+       return this.init( iObj );
+}
+flickrOrgSearch.prototype = {
+       init:function( iObj ){
+               //init base class and inherit: 
+               var baseSearch = new baseRemoteSearch( iObj );
+               for(var i in baseSearch){
+                       if(typeof this[i] =='undefined'){
+                               this[i] = baseSearch[i];
+                       }else{
+                               this['parent_'+i] =  baseSearch[i];
+                       }
+               }
+               //inherit the cp settings for 
+       },
+       getSearchResults:function(){
+               //call parent: 
+               this.parent_getSearchResults();
+               //setup the flickr request: 
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js
new file mode 100644 (file)
index 0000000..3832d26
--- /dev/null
@@ -0,0 +1,267 @@
+var mediaWikiSearch = function( iObj ) {               
+       return this.init( iObj );
+};
+mediaWikiSearch.prototype = {
+       init:function( iObj ){
+               //init base class and inherit: 
+               var baseSearch = new baseRemoteSearch( iObj );
+               for(var i in baseSearch){
+                       if(typeof this[i] =='undefined'){
+                               this[i] = baseSearch[i];
+                       }else{
+                               this['parent_'+i] =  baseSearch[i];
+                       }
+               }
+               //inherit the cp settings for 
+       },
+       getSearchResults:function(){
+               //call parent: 
+               this.parent_getSearchResults();
+               
+               var _this = this;
+               this.loading = true;
+               js_log('f:getSearchResults for:' + $j('#rsd_q').val() );                
+               //do two queries against the Image / File / MVD namespace:
+                                                                                
+               //build the image request object: 
+               var reqObj = {
+                       'action':'query',                        
+                       'generator':'search',
+                       'gsrsearch':  $j('#rsd_q').val(),  
+                       'gsrnamespace':6, //(only search the "file" namespace (audio, video, images)
+                       'gsrwhat':'title',
+                       'gsrlimit':  this.cp.limit,
+                       'gsroffset': this.cp.offset,
+                       'prop':'imageinfo|revisions|categories',
+                       'iiprop':'url|mime|size',
+                       'iiurlwidth': parseInt( this.rsd.thumb_width ),
+                       'rvprop':'content'
+               };                              
+               //set up the number of request: 
+               this.completed_req=0;
+               this.num_req=1;         
+               //setup the number of requests result flag:                                                                                      
+               //also do a request for page titles (would be nice if api could query both at the same time) 
+               reqObj['gsrwhat']='text';
+               do_api_req( {
+                       'data':reqObj, 
+                       'url':this.cp.api_url 
+                       }, function(data){
+                               js_log('mediaWikiSearch: got data response'); 
+                               //parse the return data
+                               _this.addResults( data);
+                               //_this.checkRequestDone(); //only need if we do two queries one for title one for text
+                               _this.loading = false;
+               });                     
+       },      
+       addResults:function( data ){    
+               js_log("f:addResults");
+               var _this = this                
+               //check if we have 
+               if( typeof data['query-continue'] != 'undefined'){
+                       if( typeof data['query-continue'].search != 'undefined')
+                               this.more_results = true;                       
+               }
+               //make sure we have pages to iderate: 
+               
+               if(data.query && data.query.pages){
+                       for(var page_id in  data.query.pages){
+                               var page =  data.query.pages[ page_id ];
+                               
+                               //make sure the reop is shared (don't show for now it confusing things)
+                               //@@todo support remote repository better
+                               if( page.imagerepository == 'shared'){
+                                       continue;
+                               }
+                               
+                               //make sure the page is not a redirect
+                               if(page.revisions[0]['*'].indexOf('#REDIRECT')===0){
+                                       //skip page is redirect 
+                                       continue;
+                               }                                                               
+                               //skip if its an empty or missing imageinfo: 
+                               if( !page.imageinfo )
+                                       continue;
+                                                                               
+                               this.resultsObj[page_id]={
+                                       'titleKey'       : page.title,
+                                       'link'           : page.imageinfo[0].descriptionurl,                            
+                                       'title'          : page.title.replace(/File:|.jpg|.png|.svg|.ogg|.ogv|.oga/ig, ''),
+                                       'poster'         : page.imageinfo[0].thumburl,
+                                       'thumbwidth' : page.imageinfo[0].thumbwidth,
+                                       'thumbheight': page.imageinfo[0].thumbheight,
+                                       'orgwidth'       : page.imageinfo[0].width,
+                                       'orgheight'      : page.imageinfo[0].height,
+                                       'mime'           : page.imageinfo[0].mime,
+                                       'src'            : page.imageinfo[0].url,
+                                       'desc'           : page.revisions[0]['*'],              
+                                       //add pointer to parent search obj:
+                                       'pSobj'          :_this,                        
+                                       'meta':{
+                                               'categories':page.categories
+                                       }
+                               }
+                               
+                               //likely a audio clip if no poster and type application/ogg 
+                               //@@todo we should return audio/ogg for the mime type or some other way to specify its "audio" 
+                               if( ! this.resultsObj[page_id].poster && this.resultsObj[page_id].mime == 'application/ogg' ){                                  
+                                       this.resultsObj[page_id].mime = 'audio/ogg';
+                               }
+                               
+                               this.num_results++;     
+                               //for(var i in this.resultsObj[page_id]){
+                               //      js_log('added: '+ i +' '+ this.resultsObj[page_id][i]);
+                               //}
+                       }
+               }else{
+                       js_log('no results:' + data);
+               }
+       },      
+       //check request done used for when we have multiple requests to check before formating results. 
+       checkRequestDone:function(){
+               //display output if done: 
+               this.completed_req++;
+               if(this.completed_req == this.num_req){
+                       this.loading = 0;
+               }
+       },      
+       getImageObj:function( rObj, size, callback ){                                   
+               if( rObj.mime=='application/ogg' )
+                       return callback( {'url':rObj.src, 'poster' : rObj.url } );
+               
+               //we can just use direct request urls
+               //@@todo thumb.php has some issues (cant serve the full image size, has poor erro handling etc) 
+               /*var baseImgUrl = this.cp.api_url.replace('api.php', 'thumb.php'); 
+               if ( rObj.mime=='image/jpeg' || rObj.mime=='image/png' ){
+                       //if requested size is greater than org size return reduced size obj: 
+                       if( size.width > rObj.orgwidth){
+                               callback({ 
+                                               'url'   : baseImgUrl + '?f=' + rObj.titleKey.replace(/\s/g, '_') + '&w='+ rObj.orgwidth,
+                                               'width' : rObj.orgwidth,
+                                               'height': rObj.orgheight
+                               }); 
+                               return false;
+                       }                       
+               }
+               //assuming svg or size is in range: give them requeted size
+               callback({ 
+                               'url'   : baseImgUrl + '?f=' + rObj.titleKey + '&w='+ size.width,
+                               'width' : size.width,
+                               'height': Math.round( ( rObj.orgheight / rObj.orgwidth)*size.width ) 
+               }); 
+               return false;
+               */              
+               
+               //his could be depreciated if thumb.php improves
+               var reqObj = {
+                       'action':'query',
+                       'format':'json',
+                       'titles':rObj.titleKey,
+                       'prop':'imageinfo',
+                       'iiprop':'url|size|mime' 
+               }
+               //set the width: 
+               if(size.width)
+                       reqObj['iiurlwidth']= size.width;                                
+                js_log('going to do req: ' + this.cp.api_url + ' ' + reqObj );
+               do_api_req( {
+                       'data':reqObj, 
+                       'url' : this.cp.api_url
+                       }, function(data){                                                              
+                               var imObj = {};
+                               for(var page_id in  data.query.pages){
+                                       var iminfo =  data.query.pages[ page_id ].imageinfo[0];
+                                       //store the orginal width:                               
+                                       imObj['org_width']=iminfo.width;
+                                       //check if thumb size > than image size and is jpeg or png (it will not scale well above its max res)                           
+                                       if( ( iminfo.mime=='image/jpeg' || iminfo=='image/png' ) &&
+                                               iminfo.thumbwidth > iminfo.width ){              
+                                               imObj['url'] = iminfo.url;
+                                               imObj['width'] = iminfo.width;
+                                               imObj['height'] = iminfo.height;                                        
+                                       }else{                                  
+                                               imObj['url'] = iminfo.thumburl;                                 
+                                               imObj['width'] = iminfo.thumbwidth;
+                                               imObj['height'] = iminfo.thumbheight;
+                                       }
+                               }
+                               js_log('getImageObj: get: ' + size.width + ' got url:' + imObj.url);                    
+                               callback( imObj ); 
+               });
+       },
+       //the insert image function   
+       insertImage:function( cEdit ){
+               if(!cEdit)
+                       var cEdit = _this.cEdit;                
+       },
+       getEmbedHTML: function( rObj , options) {
+               if(!options)
+                       options = {};
+               //set up the output var with the default values: 
+               var outOpt = { 'width': rObj.width, 'height': rObj.height};
+               if( options['max_height'] ){                    
+                       outOpt.height = (options.max_height > rObj.height) ? rObj.height : options.max_height;  
+                       outOpt.width = (rObj.width / rObj.height) *outOpt.height;                       
+               }                                               
+               var style_attr = 'style="width:' + outOpt.width + 'px;height:' + outOpt.height +'px"';
+               var id_attr = (options['id'])?' id = "' + options['id'] +'" ': '';
+               var cat = rObj;         
+               //return the html type: 
+               if(rObj.mime.indexOf('image')!=-1){
+                       return '<img ' + id_attr + ' src="' + rObj.edit_url  + '"' + style_attr + ' >';
+               }
+               var ahtml='';
+               if(rObj.mime == 'application/ogg' || rObj.mime == 'audio/ogg'){
+                       ahtml = id_attr + 
+                                               ' src="' + rObj.src + '" ' +
+                                               style_attr +
+                                               ' poster="'+  rObj.poster + '" '                                                                                
+                       if(rObj.mime.indexOf('application/ogg')!=-1){
+                               return '<video ' + ahtml + '></video>'; 
+                       }
+                                       
+                       if(rObj.mime.indexOf('audio/ogg')!=-1){
+                               return '<audio ' + ahtml + '></audio>';
+                       }
+               }               
+               js_log('ERROR:unsupored mime type: ' + rObj.mime);
+       },
+       getInlineDescWiki:function( rObj ){                                             
+               var desc = this.parent_getInlineDescWiki( rObj );
+               //just grab the description tag for inline desc:
+               var descMatch = new RegExp(/Description=(\{\{en\|)?([^|]*|)/);                  
+               var dparts = desc.match(descMatch);
+                               
+               if( dparts && dparts.length > 1){       
+                       desc = (dparts.length == 2) ? dparts[1] : dparts[2].replace('}}','');
+                       desc = (desc.substr(0,2) == '1=') ?desc.substr(2): desc;
+                       return desc;     
+               }
+               //else return the title since we could not find the desc:
+               js_log('we could not find the Description tag in :' + desc );
+               return rObj.title;
+       },
+       parseWikiTemplate: function( text ){
+               //@@todo parse wiki Template return object with properties and values
+       },
+       //returns the inline wikitext for insertion (template based crops for now) 
+       getEmbedWikiCode: function( rObj ){             
+                       //set default layout to right justified
+                       var layout = ( rObj.layout)? rObj.layout:"right"
+                       //if crop is null do base output: 
+                       if( rObj.crop == null)
+                               return this.parent_getEmbedWikiCode( rObj );                                                                                    
+                       //using the preview crop template: http://en.wikipedia.org/wiki/Template:Preview_Crop
+                       //@@todo should be replaced with server side cropping 
+                       return '{{Preview Crop ' + "\n" +
+                                               '|Image   = ' + rObj.target_resource_title + "\n" +
+                                               '|bSize   = ' + rObj.width + "\n" + 
+                                               '|cWidth  = ' + rObj.crop.w + "\n" +
+                                               '|cHeight = ' + rObj.crop.h + "\n" +
+                                               '|oTop  = ' + rObj.crop.y + "\n" +
+                                               '|oLeft   = ' + rObj.crop.x + "\n" +
+                                               '|Location =' + layout + "\n" +
+                                               '|Description =' + rObj.inlineDesc + "\n" +
+                                       '}}';
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js
new file mode 100644 (file)
index 0000000..ded2210
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+* api modes (implementations should call these objects which inherit the mvBaseRemoteSearch  
+*/
+loadGM( {
+       "mv_stream_title" : "$1 $2 to $3"
+});
+var metavidSearch = function(iObj) {
+       return this.init(iObj);
+};
+metavidSearch.prototype = {
+       reqObj:{  //set up the default request paramaters
+               'order':'recent',
+               'feed_format':'rss'             
+       },
+       init:function( iObj ){
+               //init base class and inherit: 
+               var baseSearch = new baseRemoteSearch( iObj );
+               for(var i in baseSearch){
+                       if(typeof this[i] =='undefined'){
+                               this[i] = baseSearch[i];
+                       }else{
+                               this['parent_'+i] =  baseSearch[i];
+                       }
+               }
+       },      
+       getSearchResults:function(){
+               //call parent: 
+               this.parent_getSearchResults();
+               
+               var _this = this;
+               //start loading:
+               _this.loading= 1;
+               js_log('metavidSearch::getSearchResults()');
+               //proccess all options
+               var url = this.cp.api_url;
+               //add on the req_param
+               for(var i in this.reqObj){
+                       url += '&' + i + '=' + this.reqObj[i];
+               }               
+               url += '&f[0][t]=match&f[0][v]=' + $j('#rsd_q').val();
+               //add offset limit: 
+               url+='&limit=' + this.cp.limit;
+               url+='&offset=' + this.cp.offset;                               
+               
+               do_request(url, function(data){
+                       
+                       js_log('mvSearch: got data response'); 
+                       //should have an xml rss data object:
+                       _this.addRSSData( data , url );
+                       
+                       //do some metavid specific pos processing on the rObj data:
+                       for(var i in _this.resultsObj){                         
+                               var rObj = _this.resultsObj[i];                         
+                               var proe = parseUri( rObj['roe_url'] );                         
+                               rObj['start_time'] = proe.queryKey['t'].split('/')[0];
+                               rObj['end_time'] = proe.queryKey['t'].split('/')[1];    
+                               rObj['stream_name'] = proe.queryKey['stream_name'];
+                                                               
+                               //all metavid content is public domain: 
+                               rObj['license'] = _this.rsd.getLicenceFromKey( 'pd' );
+                               
+                               //transform the title into a wiki_safe title:                    
+                               //rObj['titleKey'] = proe.queryKey['stream_name'] + '_' + rObj['start_time'].replace(/:/g,'.') + '_' + rObj['end_time'].replace(/:/g,'.') + '.ogg';
+                               rObj['titleKey'] =       _this.getTitleKey( rObj );
+                               
+                               //default width of metavid clips:        
+                               rObj['target_width'] = 400;        
+                       }                       
+                       //done loading: 
+                       _this.loading=0;
+               });
+       },
+       getTitleKey:function( rObj ){
+               return rObj['stream_name'] + '_start-' + rObj['start_time'].replace(/:/g,'.') + '_end-' + rObj['end_time'].replace(/:/g,'.') + '.ogg';  
+       },      
+       getTitle:function( rObj ){
+               var sn = rObj['stream_name'].replace(/_/g, ' ');
+               sn = sn.charAt(0).toUpperCase() + sn.substr(1);         
+               return gM('mv_stream_title', [ sn, rObj.start_time, rObj.end_time ]);   
+       },      
+       //metavid descption tied to public domain license key (government produced content) 
+       getPermissionWikiTag:function( rObj ){
+               return '{{PD-USGov}}';
+       },      
+       getExtraResourceDescWiki:function( rObj ){
+               var o = '';
+               //check for person      
+               if(  rObj.person && rObj.person['label'])
+                       o += '* featuring [[' + rObj.person['label'] + ']]' + "\n";
+                       
+               if( rObj.parent_clip )
+                       o += '* part of longer [' + rObj.parent_clip + ' video clip]'+ "\n";
+                       
+               if( rObj.person && rObj.person['url'] && rObj.person['label'] )
+                       o += '* also see speeches by [' +  $j.trim( rObj.person.url ) + ' ' + rObj.person['label'] + ']'+ "\n";
+               
+               //check for bill:
+               if( rObj.bill && rObj.bill['label'] && rObj.bill['url'])
+                       o += '* related to bill: [[' + rObj.bill['label'] + ']] more bill [' + rObj.bill['url'] + ' video clips]'+ "\n";                        
+               return o;
+       },      
+       //format is "quote" followed by [[name of person]]
+       getInlineDescWiki:function( rObj ){                                                             
+               var o = this.parent_getInlineDescWiki( rObj );          
+               //add in person if found
+               if( rObj.person &&  rObj.person['label'] ){
+                       o = $j.trim(  o.replace(rObj.person['label'], '') );
+                       //trim leading : 
+                       if(o.substr(0,1)==':')
+                               o =  o.substr(1);                               
+                       //add quotes and person at the end: 
+                       var d = this.getDateFromLink( rObj.link );
+                       o ='"' + o + '" [[' + rObj.person['label'] + ']] on ' + d.toDateString();
+               }               
+               //could do ref or direct link:  
+               o += ' \'\'[' + $j.trim( rObj.link ) + ' source clip]\'\' '; 
+               
+               //var o= '"' + o + '" by [[' + rObj.person['label'] + ']] '+
+               //              '<ref>[' + rObj.link + ' Metavid Source Page] for ' + rObj.title +'</ref>';             
+               return o;               
+       },
+       //give an updated start and end time updates the title and url
+       applyVideoAdj: function( rObj ){
+               js_log('mv ApplyVideoAdj::');           
+               //update the titleKey: 
+               rObj['titleKey'] =       this.getTitleKey( rObj );      
+               
+               //update the title: 
+               rObj['title'] = this.getTitle( rObj );  
+               
+               //update the interface: 
+               js_log('update title to: ' + rObj['title']);
+               $j('#rsd_resource_title').html( gM('rsd_resource_edit', rObj['title'] ) );
+               
+               //if the video is "roe" based select the ogg stream             
+               if( rObj.roe_url && rObj.pSobj.cp.stream_import_key){                   
+                       var source = $j('#embed_vid').get(0).media_element.getSourceById( rObj.pSobj.cp.stream_import_key );
+                       if(!source){
+                               js_error('Error::could not find source: ' +  rObj.pSobj.cp.stream_import_key);                                  
+                       }else{
+                               rObj['src'] = source.getURI();
+                               js_log("g src_key: " + rObj.pSobj.cp.stream_import_key + ' src:' + rObj['src']) ;
+                               return true;
+                       }
+               }       
+       },
+       getEmbedHTML:function( rObj , options ){
+           if(!options)
+                    options={};
+               var id_attr = (options['id'])?' id = "' + options['id'] +'" ': '';
+               var style_attr = (options['max_width'])?' style="width:'+options['max_width']+'px;"':'';        
+               //@@maybe check type here ?     
+               if(options['only_poster']){
+                       return '<img ' + id_attr + ' src="' + rObj['poster']+'" ' + style_attr + '>';   
+               }else{
+                       return '<video ' + id_attr + ' roe="' + rObj['roe_url'] + '"></video>';
+               }
+       },      
+       getImageTransform:function( rObj, opt ){                
+               if( opt.width <= 80 ){
+                       return getURLParamReplace( rObj.poster, { 'size' : "icon" } )
+               }else if( opt.width <= 160 ){
+                       return getURLParamReplace( rObj.poster, { 'size' : "small" } )
+               }else if( opt.width <= 320 ){
+                       return getURLParamReplace( rObj.poster, { 'size' : 'medium' } )
+               }else if( opt.width <= 512 ){
+                       return getURLParamReplace( rObj.poster, { 'size' : 'large' } )
+               }else{
+                       return getURLParamReplace( rObj.poster, { 'size' : 'full' } )
+               }               
+       },
+       getEmbedObjParsedInfo:function(rObj, eb_id){
+               var sources = $j('#'+eb_id).get(0).media_element.getSources();
+               rObj.other_versions ='*[' + rObj['roe_url'] + ' XML of all Video Formats and Timed Text]'+"\n";
+               for(var i in sources){
+                       var cur_source = sources[i];
+                       //rObj.other_versions += '*['+cur_source.getURI() +' ' + cur_source.title +']' + "\n";                  
+                       if( cur_source.id ==  this.cp.target_source_id)
+                               rObj['url'] = cur_source.getURI();
+               }
+               //js_log('set url to: ' + rObj['url']);
+               return rObj;                    
+       },
+       //update rObj for import:
+       updateDataForImport:function( rObj ){
+               rObj['author']='US Government';
+               //convert data to UTC type date:
+               var d = this.getDateFromLink( rObj.link );
+               rObj['date'] =   d.toDateString();              
+               rObj['license_template_tag']='PD-USGov';                
+               //update based on new start time:                
+               js_log('url is: ' + rObj.src + ' ns: ' + rObj.start_time + ' ne:' + rObj.end_time);             
+                       
+               return rObj;
+       },
+       getDateFromLink:function( link ){
+               var dateExp = new RegExp(/_([0-9]+)\-([0-9]+)\-([0-9]+)/);      
+               var dParts = link.match (dateExp);
+               var d = new Date();
+               var year_full = (dParts[3].length==2)?'20'+dParts[3].toString():dParts[3];
+               d.setFullYear(year_full, dParts[1]-1, dParts[2]);       
+               return d;
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libAddMedia/seqRemoteSearchDriver.js b/js2/mwEmbed/libAddMedia/seqRemoteSearchDriver.js
new file mode 100644 (file)
index 0000000..7597d35
--- /dev/null
@@ -0,0 +1,181 @@
+/*the sequence remote search driver
+        extends the base remote search driver with sequence specific stuff.             could seperate this out into seperate lib.
+*/
+
+var seqRemoteSearchDriver = function(iObj){
+       return this.init( iObj )
+}
+seqRemoteSearchDriver.prototype = {
+       sequence_add_target:false,
+       init:function( this_seq ){
+               var _this = this;
+               js_log("init:seqRemoteSearchDriver");
+               //setup remote search driver with a seq parent: 
+               this.pSeq = this_seq;
+               var iObj = {                    
+                       'target_container'      : '#cliplib_ic',
+                       'local_wiki_api_url': this_seq.getLocalApiUrl(),                                                                                
+                       'instance_name'         : this_seq.instance_name + '.mySearch',         
+                       'default_query'         : this.pSeq.plObj.title                                                 
+               }               
+               //inherit the remoteSearchDriver properties:n           
+               var tmpRSD = new remoteSearchDriver( iObj );
+               for(var i in tmpRSD){
+                       if(this[i]){
+                               this['parent_'+i] = tmpRSD[i];
+                       }else{
+                               this[i] = tmpRSD[i];
+                       }
+               }
+               //extend parent_do_refresh_timeline actions:
+               if(!this.pSeq.parent_do_refresh_timeline){
+                       this.pSeq.parent_do_refresh_timeline = this.pSeq.do_refresh_timeline;
+                       this.pSeq.do_refresh_timeline = function(){
+                               js_log("seqRs refresh chain::" + _this.pSeq.disp_menu_item);
+                               //call the parent
+                               _this.pSeq.parent_do_refresh_timeline();
+                               //add our local bindings if our window is 'active'
+                               if(_this.pSeq.disp_menu_item == 'cliplib'){
+                                       _this.addResultBindings();
+                               }
+                       }
+               }
+       },      
+       resourceEdit:function(){
+               var _this = this;       
+               
+       },      
+       addResultBindings:function(){
+               //set up seq:           
+               var _this = this;
+               //setup parent bindings:
+               this.parent_addResultBindings();
+               
+               //add an aditional click binding
+               $j('.rsd_res_item').click(function(){
+                       js_log('SeqRemoteSearch: rsd_res_item: click (remove sequence_add_target)');
+                       _this.sequence_add_target =false;
+               });
+               
+               //add an additional drag binding                                        
+               $j( '.rsd_res_item' ).draggable('destroy').draggable({
+                       helper:function(){
+                               return $j( this ).clone().appendTo('body').css({'z-index':9999}).get(0);
+                       },              
+                       revert:'invalid',                                               
+                       start:function(){
+                               js_log('start drag');
+                       }                                                               
+               });                             
+               $j(".mv_clip_drag").droppable( 'destroy' ).droppable({
+                       accept: '.rsd_res_item',
+                       over:function(event, ui){
+                               js_log("over : mv_clip_drag: " + $j(this).attr('id') );
+                               $j(this).css('border-right', 'solid thick red');                                
+                       },
+                       out:function(event, ui){
+                               $j(this).css('border-right', 'solid thin white');                               
+                       },
+                       drop: function(event, ui) {
+                               $j(this).css('border-right', 'solid thin white');
+                               js_log("Droped: "+ $j(ui.draggable).attr('id') +' on ' +  $j(this).attr('id') );
+                               _this.sequence_add_target =  $j(this).attr('id');
+                               //load the orginal draged item
+                               var rObj = _this.getResourceFromId( $j(ui.draggable).attr('id') );                                                      
+                               _this.resourceEdit(rObj, ui.draggable);                         
+                       }
+               });             
+       
+       },
+       insertResource:function(rObj){
+               var _this = this;
+               js_log("SEQ insert resource after:" + _this.sequence_add_target );
+               if(_this.sequence_add_target ){
+                       var tClip = _this.pSeq.getClipFromSeqID( _this.sequence_add_target );           
+                       var target_order = false;
+                       if(tClip)
+                               var target_order = tClip.order;
+               } 
+               //@@todo show watting of sorts. 
+               
+               //get target order:
+               var cat = rObj;                 
+               //check for target insert path
+               this.checkImportResource( rObj, function(){     
+                                                                                                               
+                       var clipConfig = {                                      
+                               'type'   : rObj.mime,
+                               'uri'    : _this.cFileNS + ':' + rObj.target_resource_title,                            
+                               'title'  : rObj.title                                                           
+                       };                                                                                                                              
+                       //set via local properites if avaliable
+                       clipConfig['src'] = (rObj.local_src) ? rObj.local_src : rObj.src;
+                       clipConfig['poster'] = (rObj.local_poster) ? rObj.local_poster : rObj.poster;
+                       
+                       if(rObj.start_time && rObj.end_time){
+                               clipConfig['dur'] = npt2seconds( rObj.end_time ) - npt2seconds( rObj.start_time );
+                       }else{
+                               //provide a default duration 
+                               clipConfig['dur'] = 4;
+                       }
+                       
+                       
+                       //create the media element (target order+1 (since we insert (after)             
+                       _this.pSeq.plObj.tryAddMediaObj(clipConfig, target_order+1 );           
+                       //refresh the timeline: 
+                       _this.pSeq.do_refresh_timeline();
+                       js_log("run close all: ");                                              
+                       _this.closeAll();
+               });
+       },
+       getClipEditControlActions:function(){
+               var _this = this;       
+               return {
+                       'insert_seq':function(rObj){
+                               _this.insertResource( rObj )
+                       },
+                       'cancel':function(rObj){
+                               _this.cancelClipEditCB( rObj )
+                       }
+               };
+       },
+       resourceEdit:function(rObj, rsdElement){
+               var _this = this;
+               //don't resize to default (full screen behavior) 
+               _this.dmodalCss = {};
+               //open up a new target_contaienr: 
+               if($j('#seq_resource_import').length == 0)
+                       $j('body').append('<div id="seq_resource_import" style="position:relative"></div>');
+                       
+               $j('#seq_resource_import').dialog('destroy').dialog({
+                       bgiframe: true,
+                       width:750,
+                       height:480,
+                       modal: true,
+                       buttons: { 
+                               "Cancel": function() { 
+                                               $j(this).dialog("close"); 
+                                       } 
+                               }
+               });
+               _this.target_container = '#seq_resource_import';                
+               //do parent resource edit (with updated target)
+               this.parent_resourceEdit(rObj, rsdElement);                             
+       },
+       closeAll:function(){
+               js_log( 'should close: seq_resource_import');
+               $j('#seq_resource_import').dialog('close').dialog('destroy').remove();
+               this.parent_closeAll();
+       },
+       getEditToken:function(callback){
+               if(this.pSeq.sequenceEditToken){
+                       callback( this.pSeq.sequenceEditToken )
+               }else{
+                       this.parent_getEditToken(callback);
+               }
+       },
+       cancelClipEditCB:function(){
+               js_log('seqRSD:cancelClipEditCB');
+               $j('#seq_resource_import').dialog('close').dialog('destroy').remove();                  
+       }
+};
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/css/Jcrop.gif b/js2/mwEmbed/libClipEdit/Jcrop/css/Jcrop.gif
new file mode 100644 (file)
index 0000000..72ea7cc
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/Jcrop/css/Jcrop.gif differ
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/css/jquery.Jcrop.css b/js2/mwEmbed/libClipEdit/Jcrop/css/jquery.Jcrop.css
new file mode 100644 (file)
index 0000000..16ea45d
--- /dev/null
@@ -0,0 +1,35 @@
+/* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */
+.jcrop-holder { text-align: left; }
+
+.jcrop-vline, .jcrop-hline
+{
+       font-size: 0;
+       position: absolute;
+       background: white url('Jcrop.gif') top left repeat;
+}
+.jcrop-vline { height: 100%; width: 1px !important; }
+.jcrop-hline { width: 100%; height: 1px !important; }
+.jcrop-handle {
+       font-size: 1px;
+       width: 7px !important;
+       height: 7px !important;
+       border: 1px #eee solid;
+       background-color: #333;
+       width: 9px;
+       height: 9px;
+}
+
+.jcrop-tracker { width: 100%; height: 100%; }
+
+.custom .jcrop-vline,
+.custom .jcrop-hline
+{
+       background: yellow;
+}
+.custom .jcrop-handle
+{
+       border-color: black;
+       background-color: #C7BB00;
+       -moz-border-radius: 3px;
+       -webkit-border-radius: 3px;
+}
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/crop.php b/js2/mwEmbed/libClipEdit/Jcrop/demos/crop.php
new file mode 100644 (file)
index 0000000..d6e3a11
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * Jcrop image cropping plugin for jQuery
+ * Example cropping script
+ * @copyright 2008 Kelly Hallman
+ * More info: http://deepliquid.com/content/Jcrop_Implementation_Theory.html
+ */
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST')
+{
+       $targ_w = $targ_h = 150;
+       $jpeg_quality = 90;
+
+       $src = 'demo_files/flowers.jpg';
+       $img_r = imagecreatefromjpeg($src);
+       $dst_r = ImageCreateTrueColor( $targ_w, $targ_h );
+
+       imagecopyresampled($dst_r,$img_r,0,0,$_POST['x'],$_POST['y'],
+       $targ_w,$targ_h,$_POST['w'],$_POST['h']);
+
+       header('Content-type: image/jpeg');
+       imagejpeg($dst_r,null,$jpeg_quality);
+
+       exit;
+}
+
+// If not a POST request, display page below:
+
+?><html>
+       <head>
+
+               <script src="../js/jquery.pack.js"></script>
+               <script src="../js/jquery.Jcrop.pack.js"></script>
+               <link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
+               <link rel="stylesheet" href="demo_files/demos.css" type="text/css" />
+
+               <script language="Javascript">
+
+                       $(function(){
+
+                               $('#cropbox').Jcrop({
+                                       aspectRatio: 1,
+                                       onSelect: updateCoords
+                               });
+
+                       });
+
+                       function updateCoords(c)
+                       {
+                               $('#x').val(c.x);
+                               $('#y').val(c.y);
+                               $('#w').val(c.w);
+                               $('#h').val(c.h);
+                       };
+
+                       function checkCoords()
+                       {
+                               if (parseInt($('#w').val())) return true;
+                               alert('Please select a crop region then press submit.');
+                               return false;
+                       };
+
+               </script>
+
+       </head>
+
+       <body>
+
+       <div id="outer">
+       <div class="jcExample">
+       <div class="article">
+
+               <h1>Jcrop - Crop Behavior</h1>
+
+               <!-- This is the image we're attaching Jcrop to -->
+               <img src="demo_files/flowers.jpg" id="cropbox" />
+
+               <!-- This is the form that our event handler fills -->
+               <form action="crop.php" method="post" onsubmit="return checkCoords();">
+                       <input type="hidden" id="x" name="x" />
+                       <input type="hidden" id="y" name="y" />
+                       <input type="hidden" id="w" name="w" />
+                       <input type="hidden" id="h" name="h" />
+                       <input type="submit" value="Crop Image" />
+               </form>
+
+               <p>
+                       <b>An example server-side crop script.</b> Hidden form values
+                       are set when a selection is made. If you press the <i>Crop Image</i>
+                       button, the form will be submitted and a 150x150 thumbnail will be
+                       dumped to the browser. Try it!
+               </p>
+
+               <div id="dl_links">
+                       <a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a> |
+                       <a href="http://deepliquid.com/content/Jcrop_Manual.html">Manual (Docs)</a>
+               </div>
+
+
+       </div>
+       </div>
+       </div>
+       </body>
+
+</html>
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/demos.css b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/demos.css
new file mode 100644 (file)
index 0000000..574d772
--- /dev/null
@@ -0,0 +1,47 @@
+body
+{
+       margin: 0;
+       padding: 0;
+       background: #eee;
+}
+
+.jcropper-holder { border: 1px black solid; }
+
+#outer {
+       text-align: center;
+}
+
+.jcExample
+{
+       text-align: left;
+       background: white;
+       width: 700px;
+       font-size: 80%;
+       margin: 3.5em auto 2em auto;
+       *margin: 3.5em 10% 2em 10%;
+       border: 1px black solid;
+       padding: 1em 2em 2em;
+}
+
+.jcExample .article
+{
+       width: 565px;
+}
+
+form
+{
+       margin: 1.5em 0;
+}
+
+form label
+{
+       margin-right: 1em;
+       font-weight: bold;
+       color: #990000;
+}
+
+.jcExample p
+{ 
+       font-family: Verdana, Helvetica, Arial, sans-serif;
+       font-size: 90%;
+}
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/flowers.jpg b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/flowers.jpg
new file mode 100755 (executable)
index 0000000..accbe9f
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/flowers.jpg differ
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sago.jpg b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sago.jpg
new file mode 100755 (executable)
index 0000000..50b48bf
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sago.jpg differ
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.jpg b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.jpg
new file mode 100644 (file)
index 0000000..654696c
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.jpg differ
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.png b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.png
new file mode 100644 (file)
index 0000000..970f465
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/Jcrop/demos/demo_files/sagomod.png differ
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial1.html b/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial1.html
new file mode 100644 (file)
index 0000000..cfe46ea
--- /dev/null
@@ -0,0 +1,43 @@
+<html>
+       <head>
+
+               <script src="../js/jquery.min.js"></script>
+               <script src="../js/jquery.Jcrop.js"></script>
+               <link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
+               <link rel="stylesheet" href="demo_files/demos.css" type="text/css" />
+
+               <script language="Javascript">
+
+               jQuery(function(){
+                       jQuery('#cropbox').Jcrop();
+               });
+
+               </script>
+
+       </head>
+
+       <body>
+               <div id="outer">
+               <div class="jcExample">
+               <div class="article">
+
+                       <h1>Jcrop - Hello World</h1>
+                       <img src="demo_files/flowers.jpg" id="cropbox" />
+
+                       <p>
+                               <b>This example is provided as a demo of the default behavior of Jcrop.</b>
+                               Since no event handlers have been attached it only performs
+                               the cropping behavior.
+                       </p>
+
+                       <div id="dl_links">
+                               <a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a> |
+                               <a href="http://deepliquid.com/content/Jcrop_Manual.html">Manual (Docs)</a>
+                       </div>
+
+               </div>
+               </div>
+               </div>
+       </body>
+</html>
+
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial2.html b/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial2.html
new file mode 100644 (file)
index 0000000..33180c3
--- /dev/null
@@ -0,0 +1,81 @@
+<html>
+       <head>
+
+               <script src="../js/jquery.min.js"></script>
+               <script src="../js/jquery.Jcrop.js"></script>
+               <link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
+               <link rel="stylesheet" href="demo_files/demos.css" type="text/css" />
+
+               <script language="Javascript">
+
+                       // Remember to invoke within jQuery(window).load(...)
+                       // If you don't, Jcrop may not initialize properly
+                       jQuery(document).ready(function(){
+
+                               jQuery('#cropbox').Jcrop({
+                                       onChange: showCoords,
+                                       onSelect: showCoords
+                               });
+
+                       });
+
+                       // Our simple event handler, called from onChange and onSelect
+                       // event handlers, as per the Jcrop invocation above
+                       function showCoords(c)
+                       {
+                               jQuery('#x').val(c.x);
+                               jQuery('#y').val(c.y);
+                               jQuery('#x2').val(c.x2);
+                               jQuery('#y2').val(c.y2);
+                               jQuery('#w').val(c.w);
+                               jQuery('#h').val(c.h);
+                       };
+
+               </script>
+
+       </head>
+
+       <body>
+
+       <div id="outer">
+       <div class="jcExample">
+       <div class="article">
+
+               <h1>Jcrop - Event Handlers</h1>
+
+               <!-- This is the image we're attaching Jcrop to -->
+               <img src="demo_files/flowers.jpg" id="cropbox" />
+
+               <!-- This is the form that our event handler fills -->
+               <form onsubmit="return false;">
+                       <label>X1 <input type="text" size="4" id="x" name="x" /></label>
+                       <label>Y1 <input type="text" size="4" id="y" name="y" /></label>
+                       <label>X2 <input type="text" size="4" id="x2" name="x2" /></label>
+                       <label>Y2 <input type="text" size="4" id="y2" name="y2" /></label>
+                       <label>W <input type="text" size="4" id="w" name="w" /></label>
+                       <label>H <input type="text" size="4" id="h" name="h" /></label>
+               </form>
+
+               <p>
+                       <b>An example with a basic event handler.</b> Here we've tied
+                       several form values together with a simple event handler invocation.
+                       The result is that the form values are updated in real-time as
+                       the selection is changed, thanks to Jcrop's <em>onChange</em> event handler.
+               </p>
+
+               <p>
+                       That's how easily Jcrop can be integrated into a traditional web form!
+               </p>
+
+               <div id="dl_links">
+                       <a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a> |
+                       <a href="http://deepliquid.com/content/Jcrop_Manual.html">Manual (Docs)</a>
+               </div>
+
+
+       </div>
+       </div>
+       </div>
+       </body>
+
+</html>
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial3.html b/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial3.html
new file mode 100644 (file)
index 0000000..7f44b53
--- /dev/null
@@ -0,0 +1,88 @@
+<html>
+       <head>
+
+               <script src="../js/jquery.min.js"></script>
+               <script src="../js/jquery.Jcrop.js"></script>
+               <link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
+               <link rel="stylesheet" href="demo_files/demos.css" type="text/css" />
+
+               <script language="Javascript">
+
+                       // Remember to invoke within jQuery(window).load(...)
+                       // If you don't, Jcrop may not initialize properly
+                       jQuery(window).load(function(){
+
+                               jQuery('#cropbox').Jcrop({
+                                       onChange: showPreview,
+                                       onSelect: showPreview,
+                                       aspectRatio: 1
+                               });
+
+                       });
+
+                       // Our simple event handler, called from onChange and onSelect
+                       // event handlers, as per the Jcrop invocation above
+                       function showPreview(coords)
+                       {
+                               if (parseInt(coords.w) > 0)
+                               {
+                                       var rx = 100 / coords.w;
+                                       var ry = 100 / coords.h;
+
+                                       jQuery('#preview').css({
+                                               width: Math.round(rx * 500) + 'px',
+                                               height: Math.round(ry * 370) + 'px',
+                                               marginLeft: '-' + Math.round(rx * coords.x) + 'px',
+                                               marginTop: '-' + Math.round(ry * coords.y) + 'px'
+                                       });
+                               }
+                       }
+
+               </script>
+
+       </head>
+
+       <body>
+
+       <div id="outer">
+       <div class="jcExample">
+       <div class="article">
+
+               <h1>Jcrop - Aspect ratio lock w/ preview pane</h1>
+
+               <!-- This is the image we're attaching Jcrop to -->
+               <table>
+               <tr>
+               <td>
+               <img src="demo_files/flowers.jpg" id="cropbox" />
+               </td>
+               <td>
+               <div style="width:100px;height:100px;overflow:hidden;">
+                       <img src="demo_files/flowers.jpg" id="preview" />
+               </div>
+               
+               </td>
+               </tr>
+               </table>
+
+               <p>
+                       <b>An example with aspect ratio locking and preview pane.</b>
+                       Obviously the most visual demo, the preview pane is accomplished
+                       entirely outside of Jcrop with a simple jQuery-flavored callback.
+                       This type of interface could be useful for creating a thumbnail
+                       or avatar. The onChange event handler is used to update the
+                       view in the preview pane.
+               </p>
+
+               <div id="dl_links">
+                       <a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a> |
+                       <a href="http://deepliquid.com/content/Jcrop_Manual.html">Manual (Docs)</a>
+               </div>
+
+
+       </div>
+       </div>
+       </div>
+       </body>
+
+</html>
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial4.html b/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial4.html
new file mode 100644 (file)
index 0000000..0e96a25
--- /dev/null
@@ -0,0 +1,94 @@
+<html>
+       <head>
+
+               <script src="../js/jquery.min.js"></script>
+               <script src="../js/jquery.Jcrop.js"></script>
+               <link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
+               <link rel="stylesheet" href="demo_files/demos.css" type="text/css" />
+
+               <script language="Javascript">
+
+                       $(window).load(function(){
+
+                               var api = $.Jcrop('#cropbox',{
+                                       setSelect: [ 100, 100, 200, 200 ]
+                               });
+                               var i, ac;
+
+                               // A handler to kill the action
+                               function nothing(e)
+                               {
+                                       e.stopPropagation();
+                                       e.preventDefault();
+                                       return false;
+                               };
+
+                               // Returns event handler for animation callback
+                               function anim_handler(ac)
+                               {
+                                       return function(e) {
+                                               api.animateTo(ac);
+                                               return nothing(e);
+                                       };
+                               };
+
+                               // Setup some coordinates for animation
+                               var ac =
+                               {
+                                       anim1: [50,50,450,320],
+                                       anim2: [74,81,218,228],
+                                       anim3: [8,8,32,360],
+                                       anim4: [316,150,470,230],
+                                       anim5: [80,160,500,190]
+                               };
+
+                               // Attach respective event handlers
+                               for(i in ac) jQuery('#'+i).click(anim_handler(ac[i]));
+
+                               // Attach another one manually, to demonstrate "set" w/o animation
+                               jQuery('#setsel').click(function(e) {
+                                       api.setSelect( [ 200, 200, 300, 300 ] );
+                                       return nothing(e);
+                               });
+
+                       });
+
+               </script>
+
+       </head>
+
+       <body>
+               <div id="outer">
+               <div class="jcExample">
+               <div class="article">
+
+                       <h1>Jcrop - API Demo</h1>
+                       <img src="demo_files/flowers.jpg" id="cropbox" />
+
+                       <div style="margin: 20px 0;">
+                               <button id="anim1">A1</button>
+                               <button id="anim2">A2</button>
+                               <button id="anim3">A3</button>
+                               <button id="anim4">A4</button>
+                               <button id="anim5">A5</button>
+                               <button id="setsel">Set</button>
+                       </div>
+
+                       <p>
+                               <b>API feature demonstration.</b>
+                               Press the buttons above to animate different selections.
+                               This was the original API demo, before additional API functionality
+                               was added (see Advanced API demo).
+                       </p>
+
+               <div id="dl_links">
+                       <a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a> |
+                       <a href="http://deepliquid.com/content/Jcrop_Manual.html">Manual (Docs)</a>
+               </div>
+
+               </div>
+               </div>
+               </div>
+       </body>
+</html>
+
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial5.html b/js2/mwEmbed/libClipEdit/Jcrop/demos/tutorial5.html
new file mode 100644 (file)
index 0000000..1b9c0f3
--- /dev/null
@@ -0,0 +1,206 @@
+<html>
+       <head>
+
+               <script src="../js/jquery.min.js"></script>
+               <script src="../js/jquery.Jcrop.js"></script>
+               <link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
+               <link rel="stylesheet" href="demo_files/demos.css" type="text/css" />
+               <style type="text/css">
+                       fieldset.optdual { width: 500px; }
+                       .optdual { position: relative; }
+                       .optdual .offset { position: absolute; left: 18em; }
+                       .optlist label { width: 16em; display: block; }
+                       #dl_links { margin-top: .5em; }
+               </style>
+               <script language="Javascript">
+
+                       $(window).load(function(){
+
+                               var jcrop_api;
+                               var i, ac;
+
+                               initJcrop();
+                               
+                               function initJcrop()//{{{
+                               {
+
+                                       jcrop_api = $.Jcrop('#cropbox');
+
+                                       $('#can_click,#can_move,#can_size')
+                                               .attr('checked','checked');
+
+                                       $('#ar_lock,#size_lock,#bg_swap').attr('checked',false);
+
+                               };
+                               //}}}
+
+                               // A handler to kill the action
+                               // Probably not necessary, but I like it
+                               function nothing(e)
+                               {
+                                       e.stopPropagation();
+                                       e.preventDefault();
+                                       return false;
+                               };
+
+                               // Use the API to find cropping dimensions
+                               // Then generate a random selection
+                               // This function is used by setSelect and animateTo buttons
+                               // Mainly for demonstration purposes
+                               function getRandom() {
+                                       var dim = jcrop_api.getBounds();
+                                       return [
+                                               Math.round(Math.random() * dim[0]),
+                                               Math.round(Math.random() * dim[1]),
+                                               Math.round(Math.random() * dim[0]),
+                                               Math.round(Math.random() * dim[1])
+                                       ];
+                               };
+
+                               // Attach interface buttons
+                               // This may appear to be a lot of code but it's simple stuff
+
+                               $('#setSelect').click(function(e) {
+                                       // Sets a random selection
+                                       jcrop_api.setSelect(getRandom());
+                               });
+
+                               $('#animateTo').click(function(e) {
+                                       // Animates to a random selection
+                                       jcrop_api.animateTo(getRandom());
+                               });
+
+                               $('#release').click(function(e) {
+                                       // Release method clears the selection
+                                       jcrop_api.release();
+                               });
+
+                               $('#disable').click(function(e) {
+                                       jcrop_api.disable();
+
+                                       $('#enable').show();
+                                       $('.requiresjcrop').hide();
+                               });
+
+                               $('#enable').click(function(e) {
+                                       jcrop_api.enable();
+
+                                       $('#enable').hide();
+                                       $('.requiresjcrop').show();
+                               });
+
+                               $('#rehook').click(function(e) {
+                                       initJcrop();
+                                       $('#rehook,#enable').hide();
+                                       $('#unhook,.requiresjcrop').show();
+                                       return nothing(e);
+                               });
+
+                               $('#unhook').click(function(e) {
+                                       jcrop_api.destroy();
+
+                                       $('#unhook,#enable,.requiresjcrop').hide();
+                                       $('#rehook').show();
+                                       return nothing(e);
+                               });
+
+                               // The checkboxes simply set options based on it's checked value
+                               // Options are changed by passing a new options object
+
+                               // Also, to prevent strange behavior, they are initially checked
+                               // This matches the default initial state of Jcrop
+
+                               $('#can_click').change(function(e) {
+                                       jcrop_api.setOptions({ allowSelect: !!this.checked });
+                                       jcrop_api.focus();
+                               });
+
+                               $('#can_move').change(function(e) {
+                                       jcrop_api.setOptions({ allowMove: !!this.checked });
+                                       jcrop_api.focus();
+                               });
+
+                               $('#can_size').change(function(e) {
+                                       jcrop_api.setOptions({ allowResize: !!this.checked });
+                                       jcrop_api.focus();
+                               });
+
+                               $('#ar_lock').change(function(e) {
+                                       jcrop_api.setOptions(this.checked? { aspectRatio: 4/3 }: { aspectRatio: 0 });
+                                       jcrop_api.focus();
+                               });
+                               $('#size_lock').change(function(e) {
+                                       jcrop_api.setOptions(this.checked? {
+                                               minSize: [ 80, 80 ],
+                                               maxSize: [ 350, 350 ]
+                                       }: {
+                                               minSize: [ 0, 0 ],
+                                               maxSize: [ 0, 0 ]
+                                       });
+                                       jcrop_api.focus();
+                               });
+                               $('#bg_swap').change(function(e) {
+                                       jcrop_api.setOptions( this.checked? {
+                                               outerImage: 'demo_files/sagomod.png',
+                                               bgOpacity: 1
+                                       }: {
+                                               outerImage: 'demo_files/sago.jpg',
+                                               bgOpacity: .6
+                                       });
+                                       jcrop_api.release();
+                               });
+
+                       });
+
+               </script>
+
+       </head>
+
+       <body>
+               <div id="outer">
+               <div class="jcExample">
+               <div class="article">
+
+                       <h1>Jcrop - API Demo</h1>
+                       <img src="demo_files/sago.jpg" id="cropbox" />
+
+                       <div style="margin: 20px 0;">
+
+                               <span class="requiresjcrop">
+                                       <button id="setSelect">setSelect</button>
+                                       <button id="animateTo">animateTo</button>
+                                       <button id="release">Release</button>
+                                       <button id="disable">Disable</button>
+                               </span>
+
+                               <button id="enable" style="display:none;">Re-Enable</button>
+                               <button id="unhook">Destroy!</button>
+                               <button id="rehook" style="display:none;">Attach Jcrop</button>
+
+                       </div>
+
+                       <fieldset class="optdual requiresjcrop">
+                               <legend>Option Toggles</legend>
+                               <div class="optlist offset">
+                                       <label><input type="checkbox" id="ar_lock" />Aspect ratio</label>
+                                       <label><input type="checkbox" id="size_lock" />minSize/maxSize setting</label>
+                                       <label><input type="checkbox" id="bg_swap" />Change outerImage</label>
+                               </div>
+                               <div class="optlist">
+                                       <label><input type="checkbox" id="can_click" />Allow new selections</label>
+                                       <label><input type="checkbox" id="can_move" />Selection can be moved</label>
+                                       <label><input type="checkbox" id="can_size" />Resizable selection</label>
+                               </div>
+                       </fieldset>
+
+               <div id="dl_links">
+                       <a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a> |
+                       <a href="http://deepliquid.com/content/Jcrop_Manual.html">Manual (Docs)</a>
+               </div>
+
+               </div>
+               </div>
+               </div>
+       </body>
+</html>
+
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/index.html b/js2/mwEmbed/libClipEdit/Jcrop/index.html
new file mode 100644 (file)
index 0000000..4f65fb0
--- /dev/null
@@ -0,0 +1,65 @@
+<html>
+<head>
+<title>Jcrop: the jQuery Image Cropping Plugin</title>
+</head>
+<body>
+
+<div style="margin:0;padding:1em 5em;width:40em;">
+<h1>Jcrop Image Cropping Plugin</h1>
+
+<big>
+       <a href="http://deepliquid.com/content/Jcrop.html"><b>Jcrop</b></a>
+       is the image cropping plugin for
+       <a href="http://jquery.com/">jQuery</a>.<br>
+       You've successfully unpacked Jcrop.
+</big>
+
+<h3>Static Demos</h3>
+
+<ul>
+       <li><a href="demos/tutorial1.html">Hello World</a> &mdash; default behavior</a></li>
+       <li><a href="demos/tutorial2.html">Basic Handler</a> &mdash; basic form integration</a></li>
+       <li><a href="demos/tutorial3.html">Aspect Ratio w/ Preview Pane</a> &mdash; nice visual example</a></li>
+       <li><a href="demos/tutorial4.html">Setting/Animating Selection</a> &mdash; animation demo</a></li>
+       <li><a href="demos/tutorial5.html">API Interface</a> &mdash; real-time API example</a></li>
+</ul>
+
+<h3>Live Demo</h3>
+
+<ul>
+       <li><a href="demos/crop.php">PHP Cropping Demo</a> &mdash; requires PHP/gd support</a></li>
+</ul>
+
+<h3>Jcrop Links</h3>
+
+<ul>
+       <li><a href="http://deepliquid.com/content/Jcrop.html">Jcrop Home</a></li>
+       <li><a href="http://deepliquid.com/content/Jcrop_Manual.html">Jcrop Manual</a></li>
+</ul>
+
+<hr noshade="noshade" size="1" style="margin-top:2em;" />
+<small>
+       <b>&copy; 2008 Kelly Hallman and DeepLiquid.com</b><br>
+       Free software released under
+       <a href="http://deepliquid.com/content/Jcrop_License.html">MIT License</a>
+</small>
+</div>
+
+
+
+
+<!-- Below here for internal analysis {{{ -->
+
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+var pageTracker = _gat._getTracker("UA-5176876-1");
+pageTracker._trackPageview();
+</script>
+
+<!-- }}} -->
+
+</body>
+</html>
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/js/jquery.Jcrop.js b/js2/mwEmbed/libClipEdit/Jcrop/js/jquery.Jcrop.js
new file mode 100644 (file)
index 0000000..ad261f9
--- /dev/null
@@ -0,0 +1,1197 @@
+/**
+ * jquery.Jcrop.js v0.9.8
+ * jQuery Image Cropping Plugin
+ * @author Kelly Hallman <khallman@gmail.com>
+ * Copyright (c) 2008-2009 Kelly Hallman - released under MIT License {{{
+ *
+ * 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.
+
+ * }}}
+ */
+
+(function($) {
+
+$.Jcrop = function(obj,opt)
+{
+       // Initialization {{{
+
+       // Sanitize some options {{{
+       var obj = obj, opt = opt;
+
+       if (typeof(obj) !== 'object') obj = $(obj)[0];
+       if (typeof(opt) !== 'object') opt = { };
+
+       // Some on-the-fly fixes for MSIE...sigh
+       if (!('trackDocument' in opt))
+       {
+               opt.trackDocument = $.browser.msie ? false : true;
+               if ($.browser.msie && $.browser.version.split('.')[0] == '8')
+                       opt.trackDocument = true;
+       }
+
+       if (!('keySupport' in opt))
+                       opt.keySupport = $.browser.msie ? false : true;
+               
+       // }}}
+       // Extend the default options {{{
+       var defaults = {
+
+               // Basic Settings
+               trackDocument:          false,
+               baseClass:                      'jcrop',
+               addClass:                       null,
+
+               // Styling Options
+               bgColor:                        'black',
+               bgOpacity:                      .6,
+               borderOpacity:          .4,
+               handleOpacity:          .5,
+
+               handlePad:                      5,
+               handleSize:                     9,
+               handleOffset:           5,
+               edgeMargin:                     14,
+
+               aspectRatio:            0,
+               keySupport:                     true,
+               cornerHandles:          true,
+               sideHandles:            true,
+               drawBorders:            true,
+               dragEdges:                      true,
+
+               boxWidth:                       0,
+               boxHeight:                      0,
+
+               boundary:                       8,
+               animationDelay:         20,
+               swingSpeed:                     3,
+
+               allowSelect:            true,
+               allowMove:                      true,
+               allowResize:            true,
+
+               minSelect:                      [ 0, 0 ],
+               maxSize:                        [ 0, 0 ],
+               minSize:                        [ 0, 0 ],
+
+               // Callbacks / Event Handlers
+               onChange: function() { },
+               onSelect: function() { }
+
+       };
+       var options = defaults;
+       setOptions(opt);
+
+       // }}}
+       // Initialize some jQuery objects {{{
+
+       var $origimg = $(obj);
+       var $img = $origimg.clone().removeAttr('id').css({ position: 'absolute' });
+
+       $img.width($origimg.width());
+       $img.height($origimg.height());
+       $origimg.after($img).hide();
+
+       presize($img,options.boxWidth,options.boxHeight);
+
+       var boundx = $img.width(),
+               boundy = $img.height(),
+
+               $div = $('<div />')
+                       .width(boundx).height(boundy)
+                       .addClass(cssClass('holder'))
+                       .css({
+                               position: 'relative',
+                               backgroundColor: options.bgColor
+                       }).insertAfter($origimg).append($img);
+       ;
+       
+       if (options.addClass) $div.addClass(options.addClass);
+       //$img.wrap($div);
+
+       var $img2 = $('<img />')/*{{{*/
+                       .attr('src',$img.attr('src'))
+                       .css('position','absolute')
+                       .width(boundx).height(boundy)
+       ;/*}}}*/
+       var $img_holder = $('<div />')/*{{{*/
+               .width(pct(100)).height(pct(100))
+               .css({
+                       zIndex: 310,
+                       position: 'absolute',
+                       overflow: 'hidden'
+               })
+               .append($img2)
+       ;/*}}}*/
+       var $hdl_holder = $('<div />')/*{{{*/
+               .width(pct(100)).height(pct(100))
+               .css('zIndex',320);
+       /*}}}*/
+       var $sel = $('<div />')/*{{{*/
+               .css({
+                       position: 'absolute',
+                       zIndex: 300
+               })
+               .insertBefore($img)
+               .append($img_holder,$hdl_holder)
+       ;/*}}}*/
+
+       var bound = options.boundary;
+       var $trk = newTracker().width(boundx+(bound*2)).height(boundy+(bound*2))
+               .css({ position: 'absolute', top: px(-bound), left: px(-bound), zIndex: 290 })
+               .mousedown(newSelection);       
+       
+       /* }}} */
+       // Set more variables {{{
+
+       var xlimit, ylimit, xmin, ymin;
+       var xscale, yscale, enabled = true;
+       var docOffset = getPos($img),
+               // Internal states
+               btndown, lastcurs, dimmed, animating,
+               shift_down;
+
+       // }}}
+               
+
+               // }}}
+       // Internal Modules {{{
+
+       var Coords = function()/*{{{*/
+       {
+               var x1 = 0, y1 = 0, x2 = 0, y2 = 0, ox, oy;
+
+               function setPressed(pos)/*{{{*/
+               {
+                       var pos = rebound(pos);
+                       x2 = x1 = pos[0];
+                       y2 = y1 = pos[1];
+               };
+               /*}}}*/
+               function setCurrent(pos)/*{{{*/
+               {
+                       var pos = rebound(pos);
+                       ox = pos[0] - x2;
+                       oy = pos[1] - y2;
+                       x2 = pos[0];
+                       y2 = pos[1];
+               };
+               /*}}}*/
+               function getOffset()/*{{{*/
+               {
+                       return [ ox, oy ];
+               };
+               /*}}}*/
+               function moveOffset(offset)/*{{{*/
+               {
+                       var ox = offset[0], oy = offset[1];
+
+                       if (0 > x1 + ox) ox -= ox + x1;
+                       if (0 > y1 + oy) oy -= oy + y1;
+
+                       if (boundy < y2 + oy) oy += boundy - (y2 + oy);
+                       if (boundx < x2 + ox) ox += boundx - (x2 + ox);
+
+                       x1 += ox;
+                       x2 += ox;
+                       y1 += oy;
+                       y2 += oy;
+               };
+               /*}}}*/
+               function getCorner(ord)/*{{{*/
+               {
+                       var c = getFixed();
+                       switch(ord)
+                       {
+                               case 'ne': return [ c.x2, c.y ];
+                               case 'nw': return [ c.x, c.y ];
+                               case 'se': return [ c.x2, c.y2 ];
+                               case 'sw': return [ c.x, c.y2 ];
+                       }
+               };
+               /*}}}*/
+               function getFixed()/*{{{*/
+               {
+                       if (!options.aspectRatio) return getRect();
+                       // This function could use some optimization I think...
+                       var aspect = options.aspectRatio,
+                               min_x = options.minSize[0]/xscale, 
+                               min_y = options.minSize[1]/yscale,
+                               max_x = options.maxSize[0]/xscale, 
+                               max_y = options.maxSize[1]/yscale,
+                               rw = x2 - x1,
+                               rh = y2 - y1,
+                               rwa = Math.abs(rw),
+                               rha = Math.abs(rh),
+                               real_ratio = rwa / rha,
+                               xx, yy
+                       ;
+                       if (max_x == 0) { max_x = boundx * 10 }
+                       if (max_y == 0) { max_y = boundy * 10 }
+                       if (real_ratio < aspect)
+                       {
+                               yy = y2;
+                               w = rha * aspect;
+                               xx = rw < 0 ? x1 - w : w + x1;
+
+                               if (xx < 0)
+                               {
+                                       xx = 0;
+                                       h = Math.abs((xx - x1) / aspect);
+                                       yy = rh < 0 ? y1 - h: h + y1;
+                               }
+                               else if (xx > boundx)
+                               {
+                                       xx = boundx;
+                                       h = Math.abs((xx - x1) / aspect);
+                                       yy = rh < 0 ? y1 - h : h + y1;
+                               }
+                       }
+                       else
+                       {
+                               xx = x2;
+                               h = rwa / aspect;
+                               yy = rh < 0 ? y1 - h : y1 + h;
+                               if (yy < 0)
+                               {
+                                       yy = 0;
+                                       w = Math.abs((yy - y1) * aspect);
+                                       xx = rw < 0 ? x1 - w : w + x1;
+                               }
+                               else if (yy > boundy)
+                               {
+                                       yy = boundy;
+                                       w = Math.abs(yy - y1) * aspect;
+                                       xx = rw < 0 ? x1 - w : w + x1;
+                               }
+                       }
+
+                       // Magic %-)
+                       if(xx > x1) { // right side
+                         if(xx - x1 < min_x) {
+                               xx = x1 + min_x;
+                         } else if (xx - x1 > max_x) {
+                               xx = x1 + max_x;
+                         }
+                         if(yy > y1) {
+                               yy = y1 + (xx - x1)/aspect;
+                         } else {
+                               yy = y1 - (xx - x1)/aspect;
+                         }
+                       } else if (xx < x1) { // left side
+                         if(x1 - xx < min_x) {
+                               xx = x1 - min_x
+                         } else if (x1 - xx > max_x) {
+                               xx = x1 - max_x;
+                         }
+                         if(yy > y1) {
+                               yy = y1 + (x1 - xx)/aspect;
+                         } else {
+                               yy = y1 - (x1 - xx)/aspect;
+                         }
+                       }
+
+                       if(xx < 0) {
+                               x1 -= xx;
+                               xx = 0;
+                       } else  if (xx > boundx) {
+                               x1 -= xx - boundx;
+                               xx = boundx;
+                       }
+
+                       if(yy < 0) {
+                               y1 -= yy;
+                               yy = 0;
+                       } else  if (yy > boundy) {
+                               y1 -= yy - boundy;
+                               yy = boundy;
+                       }
+
+                       return last = makeObj(flipCoords(x1,y1,xx,yy));
+               };
+               /*}}}*/
+               function rebound(p)/*{{{*/
+               {
+                       if (p[0] < 0) p[0] = 0;
+                       if (p[1] < 0) p[1] = 0;
+
+                       if (p[0] > boundx) p[0] = boundx;
+                       if (p[1] > boundy) p[1] = boundy;
+
+                       return [ p[0], p[1] ];
+               };
+               /*}}}*/
+               function flipCoords(x1,y1,x2,y2)/*{{{*/
+               {
+                       var xa = x1, xb = x2, ya = y1, yb = y2;
+                       if (x2 < x1)
+                       {
+                               xa = x2;
+                               xb = x1;
+                       }
+                       if (y2 < y1)
+                       {
+                               ya = y2;
+                               yb = y1;
+                       }
+                       return [ Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb) ];
+               };
+               /*}}}*/
+               function getRect()/*{{{*/
+               {
+                       var xsize = x2 - x1;
+                       var ysize = y2 - y1;
+
+                       if (xlimit && (Math.abs(xsize) > xlimit))
+                               x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
+                       if (ylimit && (Math.abs(ysize) > ylimit))
+                               y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
+
+                       if (ymin && (Math.abs(ysize) < ymin))
+                               y2 = (ysize > 0) ? (y1 + ymin) : (y1 - ymin);
+                       if (xmin && (Math.abs(xsize) < xmin))
+                               x2 = (xsize > 0) ? (x1 + xmin) : (x1 - xmin);
+
+                       if (x1 < 0) { x2 -= x1; x1 -= x1; }
+                       if (y1 < 0) { y2 -= y1; y1 -= y1; }
+                       if (x2 < 0) { x1 -= x2; x2 -= x2; }
+                       if (y2 < 0) { y1 -= y2; y2 -= y2; }
+                       if (x2 > boundx) { var delta = x2 - boundx; x1 -= delta; x2 -= delta; }
+                       if (y2 > boundy) { var delta = y2 - boundy; y1 -= delta; y2 -= delta; }
+                       if (x1 > boundx) { var delta = x1 - boundy; y2 -= delta; y1 -= delta; }
+                       if (y1 > boundy) { var delta = y1 - boundy; y2 -= delta; y1 -= delta; }
+
+                       return makeObj(flipCoords(x1,y1,x2,y2));
+               };
+               /*}}}*/
+               function makeObj(a)/*{{{*/
+               {
+                       return { x: a[0], y: a[1], x2: a[2], y2: a[3],
+                               w: a[2] - a[0], h: a[3] - a[1] };
+               };
+               /*}}}*/
+
+               return {
+                       flipCoords: flipCoords,
+                       setPressed: setPressed,
+                       setCurrent: setCurrent,
+                       getOffset: getOffset,
+                       moveOffset: moveOffset,
+                       getCorner: getCorner,
+                       getFixed: getFixed
+               };
+       }();
+
+       /*}}}*/
+       var Selection = function()/*{{{*/
+       {
+               var start, end, dragmode, awake, hdep = 370;
+               var borders = { };
+               var handle = { };
+               var seehandles = false;
+               var hhs = options.handleOffset;
+
+               /* Insert draggable elements {{{*/
+
+               // Insert border divs for outline
+               if (options.drawBorders) {
+                       borders = {
+                                       top: insertBorder('hline')
+                                               .css('top',$.browser.msie?px(-1):px(0)),
+                                       bottom: insertBorder('hline'),
+                                       left: insertBorder('vline'),
+                                       right: insertBorder('vline')
+                       };
+               }
+
+               // Insert handles on edges
+               if (options.dragEdges) {
+                       handle.t = insertDragbar('n');
+                       handle.b = insertDragbar('s');
+                       handle.r = insertDragbar('e');
+                       handle.l = insertDragbar('w');
+               }
+
+               // Insert side handles
+               options.sideHandles &&
+                       createHandles(['n','s','e','w']);
+
+               // Insert corner handles
+               options.cornerHandles &&
+                       createHandles(['sw','nw','ne','se']);
+
+               /*}}}*/
+               // Private Methods
+               function insertBorder(type)/*{{{*/
+               {
+                       var jq = $('<div />')
+                               .css({position: 'absolute', opacity: options.borderOpacity })
+                               .addClass(cssClass(type));
+                       $img_holder.append(jq);
+                       return jq;
+               };
+               /*}}}*/
+               function dragDiv(ord,zi)/*{{{*/
+               {
+                       var jq = $('<div />')
+                               .mousedown(createDragger(ord))
+                               .css({
+                                       cursor: ord+'-resize',
+                                       position: 'absolute',
+                                       zIndex: zi 
+                               })
+                       ;
+                       $hdl_holder.append(jq);
+                       return jq;
+               };
+               /*}}}*/
+               function insertHandle(ord)/*{{{*/
+               {
+                       return dragDiv(ord,hdep++)
+                               .css({ top: px(-hhs+1), left: px(-hhs+1), opacity: options.handleOpacity })
+                               .addClass(cssClass('handle'));
+               };
+               /*}}}*/
+               function insertDragbar(ord)/*{{{*/
+               {
+                       var s = options.handleSize,
+                               o = hhs,
+                               h = s, w = s,
+                               t = o, l = o;
+
+                       switch(ord)
+                       {
+                               case 'n': case 's': w = pct(100); break;
+                               case 'e': case 'w': h = pct(100); break;
+                       }
+
+                       return dragDiv(ord,hdep++).width(w).height(h)
+                               .css({ top: px(-t+1), left: px(-l+1)});
+               };
+               /*}}}*/
+               function createHandles(li)/*{{{*/
+               {
+                       for(i in li) handle[li[i]] = insertHandle(li[i]);
+               };
+               /*}}}*/
+               function moveHandles(c)/*{{{*/
+               {
+                       var midvert  = Math.round((c.h / 2) - hhs),
+                               midhoriz = Math.round((c.w / 2) - hhs),
+                               north = west = -hhs+1,
+                               east = c.w - hhs,
+                               south = c.h - hhs,
+                               x, y;
+
+                       'e' in handle &&
+                               handle.e.css({ top: px(midvert), left: px(east) }) &&
+                               handle.w.css({ top: px(midvert) }) &&
+                               handle.s.css({ top: px(south), left: px(midhoriz) }) &&
+                               handle.n.css({ left: px(midhoriz) });
+
+                       'ne' in handle &&
+                               handle.ne.css({ left: px(east) }) &&
+                               handle.se.css({ top: px(south), left: px(east) }) &&
+                               handle.sw.css({ top: px(south) });
+
+                       'b' in handle &&
+                               handle.b.css({ top: px(south) }) &&
+                               handle.r.css({ left: px(east) });
+               };
+               /*}}}*/
+               function moveto(x,y)/*{{{*/
+               {
+                       $img2.css({ top: px(-y), left: px(-x) });
+                       $sel.css({ top: px(y), left: px(x) });
+               };
+               /*}}}*/
+               function resize(w,h)/*{{{*/
+               {
+                       $sel.width(w).height(h);
+               };
+               /*}}}*/
+               function refresh()/*{{{*/
+               {
+                       var c = Coords.getFixed();
+
+                       Coords.setPressed([c.x,c.y]);
+                       Coords.setCurrent([c.x2,c.y2]);
+
+                       updateVisible();
+               };
+               /*}}}*/
+
+               // Internal Methods
+               function updateVisible()/*{{{*/
+                       { if (awake) return update(); };
+               /*}}}*/
+               function update()/*{{{*/
+               {
+                       var c = Coords.getFixed();
+
+                       resize(c.w,c.h);
+                       moveto(c.x,c.y);
+
+                       options.drawBorders &&
+                               borders['right'].css({ left: px(c.w-1) }) &&
+                                       borders['bottom'].css({ top: px(c.h-1) });
+
+                       seehandles && moveHandles(c);
+                       awake || show();
+
+                       options.onChange(unscale(c));
+               };
+               /*}}}*/
+               function show()/*{{{*/
+               {
+                       $sel.show();
+                       $img.css('opacity',options.bgOpacity);
+                       awake = true;
+               };
+               /*}}}*/
+               function release()/*{{{*/
+               {
+                       disableHandles();
+                       $sel.hide();
+                       $img.css('opacity',1);
+                       awake = false;
+               };
+               /*}}}*/
+               function showHandles()//{{{
+               {
+                       if (seehandles)
+                       {
+                               moveHandles(Coords.getFixed());
+                               $hdl_holder.show();
+                       }
+               };
+               //}}}
+               function enableHandles()/*{{{*/
+               { 
+                       seehandles = true;
+                       if (options.allowResize)
+                       {
+                               moveHandles(Coords.getFixed());
+                               $hdl_holder.show();
+                               return true;
+                       }
+               };
+               /*}}}*/
+               function disableHandles()/*{{{*/
+               {
+                       seehandles = false;
+                       $hdl_holder.hide();
+               };
+               /*}}}*/
+               function animMode(v)/*{{{*/
+               {
+                       (animating = v) ? disableHandles(): enableHandles();
+               };
+               /*}}}*/
+               function done()/*{{{*/
+               {
+                       animMode(false);
+                       refresh();
+               };
+               /*}}}*/
+
+               var $track = newTracker().mousedown(createDragger('move'))
+                               .css({ cursor: 'move', position: 'absolute', zIndex: 360 })
+
+               $img_holder.append($track);
+               disableHandles();
+
+               return {
+                       updateVisible: updateVisible,
+                       update: update,
+                       release: release,
+                       refresh: refresh,
+                       setCursor: function (cursor) { $track.css('cursor',cursor); },
+                       enableHandles: enableHandles,
+                       enableOnly: function() { seehandles = true; },
+                       showHandles: showHandles,
+                       disableHandles: disableHandles,
+                       animMode: animMode,
+                       done: done
+               };
+       }();
+       /*}}}*/
+       var Tracker = function()/*{{{*/
+       {
+               var onMove              = function() { },
+                       onDone          = function() { },
+                       trackDoc        = options.trackDocument;
+
+               if (!trackDoc)
+               {
+                       $trk
+                               .mousemove(trackMove)
+                               .mouseup(trackUp)
+                               .mouseout(trackUp)
+                       ;
+               }
+
+               function toFront()/*{{{*/
+               {
+                       $trk.css({zIndex:450});
+                       if (trackDoc)
+                       {
+                               $(document)
+                                       .mousemove(trackMove)
+                                       .mouseup(trackUp)
+                               ;
+                       }
+               }
+               /*}}}*/
+               function toBack()/*{{{*/
+               {
+                       $trk.css({zIndex:290});
+                       if (trackDoc)
+                       {
+                               $(document)
+                                       .unbind('mousemove',trackMove)
+                                       .unbind('mouseup',trackUp)
+                               ;
+                       }
+               }
+               /*}}}*/
+               function trackMove(e)/*{{{*/
+               {
+                       onMove(mouseAbs(e));
+               };
+               /*}}}*/
+               function trackUp(e)/*{{{*/
+               {
+                       e.preventDefault();
+                       e.stopPropagation();
+
+                       if (btndown)
+                       {
+                               btndown = false;
+
+                               onDone(mouseAbs(e));
+                               options.onSelect(unscale(Coords.getFixed()));
+                               toBack();
+                               onMove = function() { };
+                               onDone = function() { };
+                       }
+
+                       return false;
+               };
+               /*}}}*/
+
+               function activateHandlers(move,done)/* {{{ */
+               {
+                       btndown = true;
+                       onMove = move;
+                       onDone = done;
+                       toFront();
+                       return false;
+               };
+               /* }}} */
+
+               function setCursor(t) { $trk.css('cursor',t); };
+
+               $img.before($trk);
+               return {
+                       activateHandlers: activateHandlers,
+                       setCursor: setCursor
+               };
+       }();
+       /*}}}*/
+       var KeyManager = function()/*{{{*/
+       {
+               var $keymgr = $('<input type="radio" />')
+                               .css({ position: 'absolute', left: '-30px' })
+                               .keypress(parseKey)
+                               .blur(onBlur),
+
+                       $keywrap = $('<div />')
+                               .css({
+                                       position: 'absolute',
+                                       overflow: 'hidden'
+                               })
+                               .append($keymgr)
+               ;
+
+               function watchKeys()/*{{{*/
+               {
+                       if (options.keySupport)
+                       {
+                               $keymgr.show();
+                               $keymgr.focus();
+                       }
+               };
+               /*}}}*/
+               function onBlur(e)/*{{{*/
+               {
+                       $keymgr.hide();
+               };
+               /*}}}*/
+               function doNudge(e,x,y)/*{{{*/
+               {
+                       if (options.allowMove) {
+                               Coords.moveOffset([x,y]);
+                               Selection.updateVisible();
+                       };
+                       e.preventDefault();
+                       e.stopPropagation();
+               };
+               /*}}}*/
+               function parseKey(e)/*{{{*/
+               {
+                       if (e.ctrlKey) return true;
+                       shift_down = e.shiftKey ? true : false;
+                       var nudge = shift_down ? 10 : 1;
+                       switch(e.keyCode)
+                       {
+                               case 37: doNudge(e,-nudge,0); break;
+                               case 39: doNudge(e,nudge,0); break;
+                               case 38: doNudge(e,0,-nudge); break;
+                               case 40: doNudge(e,0,nudge); break;
+
+                               case 27: Selection.release(); break;
+
+                               case 9: return true;
+                       }
+
+                       return nothing(e);
+               };
+               /*}}}*/
+               
+               if (options.keySupport) $keywrap.insertBefore($img);
+               return {
+                       watchKeys: watchKeys
+               };
+       }();
+       /*}}}*/
+
+       // }}}
+       // Internal Methods {{{
+
+       function px(n) { return '' + parseInt(n) + 'px'; };
+       function pct(n) { return '' + parseInt(n) + '%'; };
+       function cssClass(cl) { return options.baseClass + '-' + cl; };
+       function getPos(obj)/*{{{*/
+       {
+               // Updated in v0.9.4 to use built-in dimensions plugin
+               var pos = $(obj).offset();
+               return [ pos.left, pos.top ];
+       };
+       /*}}}*/
+       function mouseAbs(e)/*{{{*/
+       {
+               return [ (e.pageX - docOffset[0]), (e.pageY - docOffset[1]) ];
+       };
+       /*}}}*/
+       function myCursor(type)/*{{{*/
+       {
+               if (type != lastcurs)
+               {
+                       Tracker.setCursor(type);
+                       //Handles.xsetCursor(type);
+                       lastcurs = type;
+               }
+       };
+       /*}}}*/
+       function startDragMode(mode,pos)/*{{{*/
+       {
+               docOffset = getPos($img);
+               Tracker.setCursor(mode=='move'?mode:mode+'-resize');
+
+               if (mode == 'move')
+                       return Tracker.activateHandlers(createMover(pos), doneSelect);
+
+               var fc = Coords.getFixed();
+               var opp = oppLockCorner(mode);
+               var opc = Coords.getCorner(oppLockCorner(opp));
+
+               Coords.setPressed(Coords.getCorner(opp));
+               Coords.setCurrent(opc);
+
+               Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);
+       };
+       /*}}}*/
+       function dragmodeHandler(mode,f)/*{{{*/
+       {
+               return function(pos) {
+                       if (!options.aspectRatio) switch(mode)
+                       {
+                               case 'e': pos[1] = f.y2; break;
+                               case 'w': pos[1] = f.y2; break;
+                               case 'n': pos[0] = f.x2; break;
+                               case 's': pos[0] = f.x2; break;
+                       }
+                       else switch(mode)
+                       {
+                               case 'e': pos[1] = f.y+1; break;
+                               case 'w': pos[1] = f.y+1; break;
+                               case 'n': pos[0] = f.x+1; break;
+                               case 's': pos[0] = f.x+1; break;
+                       }
+                       Coords.setCurrent(pos);
+                       Selection.update();
+               };
+       };
+       /*}}}*/
+       function createMover(pos)/*{{{*/
+       {
+               var lloc = pos;
+               KeyManager.watchKeys();
+
+               return function(pos)
+               {
+                       Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
+                       lloc = pos;
+                       
+                       Selection.update();
+               };
+       };
+       /*}}}*/
+       function oppLockCorner(ord)/*{{{*/
+       {
+               switch(ord)
+               {
+                       case 'n': return 'sw';
+                       case 's': return 'nw';
+                       case 'e': return 'nw';
+                       case 'w': return 'ne';
+                       case 'ne': return 'sw';
+                       case 'nw': return 'se';
+                       case 'se': return 'nw';
+                       case 'sw': return 'ne';
+               };
+       };
+       /*}}}*/
+       function createDragger(ord)/*{{{*/
+       {
+               return function(e) {
+                       if (options.disabled) return false;
+                       if ((ord == 'move') && !options.allowMove) return false;
+                       btndown = true;
+                       startDragMode(ord,mouseAbs(e));
+                       e.stopPropagation();
+                       e.preventDefault();
+                       return false;
+               };
+       };
+       /*}}}*/
+       function presize($obj,w,h)/*{{{*/
+       {
+               var nw = $obj.width(), nh = $obj.height();
+               if ((nw > w) && w > 0)
+               {
+                       nw = w;
+                       nh = (w/$obj.width()) * $obj.height();
+               }
+               if ((nh > h) && h > 0)
+               {
+                       nh = h;
+                       nw = (h/$obj.height()) * $obj.width();
+               }
+               xscale = $obj.width() / nw;
+               yscale = $obj.height() / nh;
+               $obj.width(nw).height(nh);
+       };
+       /*}}}*/
+       function unscale(c)/*{{{*/
+       {
+               return {
+                       x: parseInt(c.x * xscale), y: parseInt(c.y * yscale), 
+                       x2: parseInt(c.x2 * xscale), y2: parseInt(c.y2 * yscale), 
+                       w: parseInt(c.w * xscale), h: parseInt(c.h * yscale)
+               };
+       };
+       /*}}}*/
+       function doneSelect(pos)/*{{{*/
+       {
+               var c = Coords.getFixed();
+               if (c.w > options.minSelect[0] && c.h > options.minSelect[1])
+               {
+                       Selection.enableHandles();
+                       Selection.done();
+               }
+               else
+               {
+                       Selection.release();
+               }
+               Tracker.setCursor( options.allowSelect?'crosshair':'default' );
+       };
+       /*}}}*/
+       function newSelection(e)/*{{{*/
+       {
+               if (options.disabled) return false;
+               if (!options.allowSelect) return false;
+               btndown = true;
+               docOffset = getPos($img);
+               Selection.disableHandles();
+               myCursor('crosshair');
+               var pos = mouseAbs(e);
+               Coords.setPressed(pos);
+               Tracker.activateHandlers(selectDrag,doneSelect);
+               KeyManager.watchKeys();
+               Selection.update();
+
+               e.stopPropagation();
+               e.preventDefault();
+               return false;
+       };
+       /*}}}*/
+       function selectDrag(pos)/*{{{*/
+       {
+               Coords.setCurrent(pos);
+               Selection.update();
+       };
+       /*}}}*/
+       function newTracker()
+       {
+               var trk = $('<div></div>').addClass(cssClass('tracker'));
+               $.browser.msie && trk.css({ opacity: 0, backgroundColor: 'white' });
+               return trk;
+       };
+
+       // }}}
+       // API methods {{{
+               
+       function animateTo(a)/*{{{*/
+       {
+               var x1 = a[0] / xscale,
+                       y1 = a[1] / yscale,
+                       x2 = a[2] / xscale,
+                       y2 = a[3] / yscale;
+
+               if (animating) return;
+
+               var animto = Coords.flipCoords(x1,y1,x2,y2);
+               var c = Coords.getFixed();
+               var animat = initcr = [ c.x, c.y, c.x2, c.y2 ];
+               var interv = options.animationDelay;
+
+               var x = animat[0];
+               var y = animat[1];
+               var x2 = animat[2];
+               var y2 = animat[3];
+               var ix1 = animto[0] - initcr[0];
+               var iy1 = animto[1] - initcr[1];
+               var ix2 = animto[2] - initcr[2];
+               var iy2 = animto[3] - initcr[3];
+               var pcent = 0;
+               var velocity = options.swingSpeed;
+
+               Selection.animMode(true);
+
+               var animator = function()
+               {
+                       return function()
+                       {
+                               pcent += (100 - pcent) / velocity;
+
+                               animat[0] = x + ((pcent / 100) * ix1);
+                               animat[1] = y + ((pcent / 100) * iy1);
+                               animat[2] = x2 + ((pcent / 100) * ix2);
+                               animat[3] = y2 + ((pcent / 100) * iy2);
+
+                               if (pcent < 100) animateStart();
+                                       else Selection.done();
+
+                               if (pcent >= 99.8) pcent = 100;
+
+                               setSelectRaw(animat);
+                       };
+               }();
+
+               function animateStart()
+                       { window.setTimeout(animator,interv); };
+
+               animateStart();
+       };
+       /*}}}*/
+       function setSelect(rect)//{{{
+       {
+               setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);
+       };
+       //}}}
+       function setSelectRaw(l) /*{{{*/
+       {
+               Coords.setPressed([l[0],l[1]]);
+               Coords.setCurrent([l[2],l[3]]);
+               Selection.update();
+       };
+       /*}}}*/
+       function setOptions(opt)/*{{{*/
+       {
+               if (typeof(opt) != 'object') opt = { };
+               options = $.extend(options,opt);
+
+               if (typeof(options.onChange)!=='function')
+                       options.onChange = function() { };
+
+               if (typeof(options.onSelect)!=='function')
+                       options.onSelect = function() { };
+
+       };
+       /*}}}*/
+       function tellSelect()/*{{{*/
+       {
+               return unscale(Coords.getFixed());
+       };
+       /*}}}*/
+       function tellScaled()/*{{{*/
+       {
+               return Coords.getFixed();
+       };
+       /*}}}*/
+       function setOptionsNew(opt)/*{{{*/
+       {
+               setOptions(opt);
+               interfaceUpdate();
+       };
+       /*}}}*/
+       function disableCrop()//{{{
+       {
+               options.disabled = true;
+               Selection.disableHandles();
+               Selection.setCursor('default');
+               Tracker.setCursor('default');
+       };
+       //}}}
+       function enableCrop()//{{{
+       {
+               options.disabled = false;
+               interfaceUpdate();
+       };
+       //}}}
+       function cancelCrop()//{{{
+       {
+               Selection.done();
+               Tracker.activateHandlers(null,null);
+       };
+       //}}}
+       function destroy()//{{{
+       {
+               $div.remove();
+               $origimg.show();
+       };
+       //}}}
+
+       function interfaceUpdate(alt)//{{{
+       // This method tweaks the interface based on options object.
+       // Called when options are changed and at end of initialization.
+       {
+               options.allowResize ?
+                       alt?Selection.enableOnly():Selection.enableHandles():
+                       Selection.disableHandles();
+
+               Tracker.setCursor( options.allowSelect? 'crosshair': 'default' );
+               Selection.setCursor( options.allowMove? 'move': 'default' );
+
+               $div.css('backgroundColor',options.bgColor);
+
+               if ('setSelect' in options) {
+                       setSelect(opt.setSelect);
+                       Selection.done();
+                       delete(options.setSelect);
+               }
+
+               if ('trueSize' in options) {
+                       xscale = options.trueSize[0] / boundx;
+                       yscale = options.trueSize[1] / boundy;
+               }
+
+               xlimit = options.maxSize[0] || 0;
+               ylimit = options.maxSize[1] || 0;
+               xmin = options.minSize[0] || 0;
+               ymin = options.minSize[1] || 0;
+
+               if ('outerImage' in options)
+               {
+                       $img.attr('src',options.outerImage);
+                       delete(options.outerImage);
+               }
+
+               Selection.refresh();
+       };
+       //}}}
+
+       // }}}
+
+       $hdl_holder.hide();
+       interfaceUpdate(true);
+       
+       var api = {
+               animateTo: animateTo,
+               setSelect: setSelect,
+               setOptions: setOptionsNew,
+               tellSelect: tellSelect,
+               tellScaled: tellScaled,
+
+               disable: disableCrop,
+               enable: enableCrop,
+               cancel: cancelCrop,
+
+               focus: KeyManager.watchKeys,
+
+               getBounds: function() { return [ boundx * xscale, boundy * yscale ]; },
+               getWidgetSize: function() { return [ boundx, boundy ]; },
+
+               release: Selection.release,
+               destroy: destroy
+
+       };
+
+       $origimg.data('Jcrop',api);
+       return api;
+};
+
+$.fn.Jcrop = function(options)/*{{{*/
+{
+       function attachWhenDone(from)/*{{{*/
+       {
+               var loadsrc = options.useImg || from.src;
+               var img = new Image();
+               img.onload = function() { $.Jcrop(from,options); };
+               img.src = loadsrc;
+       };
+       /*}}}*/
+       if (typeof(options) !== 'object') options = { };
+
+       // Iterate over each object, attach Jcrop
+       this.each(function()
+       {
+               // If we've already attached to this object
+               if ($(this).data('Jcrop'))
+               {
+                       // The API can be requested this way (undocumented)
+                       if (options == 'api') return $(this).data('Jcrop');
+                       // Otherwise, we just reset the options...
+                       else $(this).data('Jcrop').setOptions(options);
+               }
+               // If we haven't been attached, preload and attach
+               else attachWhenDone(this);
+       });
+
+       // Return "this" so we're chainable a la jQuery plugin-style!
+       return this;
+};
+/*}}}*/
+
+})(jQuery);
diff --git a/js2/mwEmbed/libClipEdit/Jcrop/js/jquery.Jcrop.min.js b/js2/mwEmbed/libClipEdit/Jcrop/js/jquery.Jcrop.min.js
new file mode 100644 (file)
index 0000000..9002b97
--- /dev/null
@@ -0,0 +1,163 @@
+/**
+ * Jcrop v.0.9.8 (minimized)
+ * (c) 2008 Kelly Hallman and DeepLiquid.com
+ * More information: http://deepliquid.com/content/Jcrop.html
+ * Released under MIT License - this header must remain with code
+ */
+
+
+(function($){$.Jcrop=function(obj,opt)
+{var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt))
+{opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8')
+opt.trackDocument=true;}
+if(!('keySupport'in opt))
+opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('<img />').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('<div />').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('<div />').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('<div />').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function()
+{var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos)
+{var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos)
+{var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset()
+{return[ox,oy];};function moveOffset(offset)
+{var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundy<y2+oy)oy+=boundy-(y2+oy);if(boundx<x2+ox)ox+=boundx-(x2+ox);x1+=ox;x2+=ox;y1+=oy;y2+=oy;};function getCorner(ord)
+{var c=getFixed();switch(ord)
+{case'ne':return[c.x2,c.y];case'nw':return[c.x,c.y];case'se':return[c.x2,c.y2];case'sw':return[c.x,c.y2];}};function getFixed()
+{if(!options.aspectRatio)return getRect();var aspect=options.aspectRatio,min_x=options.minSize[0]/xscale,min_y=options.minSize[1]/yscale,max_x=options.maxSize[0]/xscale,max_y=options.maxSize[1]/yscale,rw=x2-x1,rh=y2-y1,rwa=Math.abs(rw),rha=Math.abs(rh),real_ratio=rwa/rha,xx,yy;if(max_x==0){max_x=boundx*10}
+if(max_y==0){max_y=boundy*10}
+if(real_ratio<aspect)
+{yy=y2;w=rha*aspect;xx=rw<0?x1-w:w+x1;if(xx<0)
+{xx=0;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}
+else if(xx>boundx)
+{xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}
+else
+{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0)
+{yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}
+else if(yy>boundy)
+{yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}}
+if(xx>x1){if(xx-x1<min_x){xx=x1+min_x;}else if(xx-x1>max_x){xx=x1+max_x;}
+if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xx<x1){if(x1-xx<min_x){xx=x1-min_x}else if(x1-xx>max_x){xx=x1-max_x;}
+if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}}
+if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;}
+if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;}
+return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p)
+{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2)
+{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2<x1)
+{xa=x2;xb=x1;}
+if(y2<y1)
+{ya=y2;yb=y1;}
+return[Math.round(xa),Math.round(ya),Math.round(xb),Math.round(yb)];};function getRect()
+{var xsize=x2-x1;var ysize=y2-y1;if(xlimit&&(Math.abs(xsize)>xlimit))
+x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit))
+y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)<ymin))
+y2=(ysize>0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)<xmin))
+x2=(xsize>0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;}
+if(y1<0){y2-=y1;y1-=y1;}
+if(x2<0){x1-=x2;x2-=x2;}
+if(y2<0){y1-=y2;y2-=y2;}
+if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;}
+if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;}
+if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;}
+if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;}
+return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a)
+{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function()
+{var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};}
+if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');}
+options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type)
+{var jq=$('<div />').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi)
+{var jq=$('<div />').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord)
+{return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord)
+{var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord)
+{case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;}
+return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li)
+{for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c)
+{var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y)
+{$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h)
+{$sel.width(w).height(h);};function refresh()
+{var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible()
+{if(awake)return update();};function update()
+{var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show()
+{$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release()
+{disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles()
+{if(seehandles)
+{moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles()
+{seehandles=true;if(options.allowResize)
+{moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles()
+{seehandles=false;$hdl_holder.hide();};function animMode(v)
+{(animating=v)?disableHandles():enableHandles();};function done()
+{animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360})
+$img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function()
+{var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc)
+{$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);}
+function toFront()
+{$trk.css({zIndex:450});if(trackDoc)
+{$(document).mousemove(trackMove).mouseup(trackUp);}}
+function toBack()
+{$trk.css({zIndex:290});if(trackDoc)
+{$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}}
+function trackMove(e)
+{onMove(mouseAbs(e));};function trackUp(e)
+{e.preventDefault();e.stopPropagation();if(btndown)
+{btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};}
+return false;};function activateHandlers(move,done)
+{btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function()
+{var $keymgr=$('<input type="radio" />').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('<div />').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys()
+{if(options.keySupport)
+{$keymgr.show();$keymgr.focus();}};function onBlur(e)
+{$keymgr.hide();};function doNudge(e,x,y)
+{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e)
+{if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode)
+{case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;}
+return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj)
+{var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e)
+{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type)
+{if(type!=lastcurs)
+{Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos)
+{docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move')
+return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f)
+{return function(pos){if(!options.aspectRatio)switch(mode)
+{case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}
+else switch(mode)
+{case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}
+Coords.setCurrent(pos);Selection.update();};};function createMover(pos)
+{var lloc=pos;KeyManager.watchKeys();return function(pos)
+{Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord)
+{switch(ord)
+{case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord)
+{return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h)
+{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0)
+{nw=w;nh=(w/$obj.width())*$obj.height();}
+if((nh>h)&&h>0)
+{nh=h;nw=(h/$obj.height())*$obj.width();}
+xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c)
+{return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos)
+{var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1])
+{Selection.enableHandles();Selection.done();}
+else
+{Selection.release();}
+Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e)
+{if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos)
+{Coords.setCurrent(pos);Selection.update();};function newTracker()
+{var trk=$('<div></div>').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a)
+{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function()
+{return function()
+{pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart()
+{window.setTimeout(animator,interv);};animateStart();};function setSelect(rect)
+{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l)
+{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt)
+{if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function')
+options.onChange=function(){};if(typeof(options.onSelect)!=='function')
+options.onSelect=function(){};};function tellSelect()
+{return unscale(Coords.getFixed());};function tellScaled()
+{return Coords.getFixed();};function setOptionsNew(opt)
+{setOptions(opt);interfaceUpdate();};function disableCrop()
+{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop()
+{options.disabled=false;interfaceUpdate();};function cancelCrop()
+{Selection.done();Tracker.activateHandlers(null,null);};function destroy()
+{$div.remove();$origimg.show();};function interfaceUpdate(alt)
+{options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);}
+if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;}
+xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options)
+{$img.attr('src',options.outerImage);delete(options.outerImage);}
+Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options)
+{function attachWhenDone(from)
+{var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function()
+{if($(this).data('Jcrop'))
+{if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);}
+else attachWhenDone(this);});return this;};})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/css/colorpicker.css b/js2/mwEmbed/libClipEdit/colorpicker/css/colorpicker.css
new file mode 100644 (file)
index 0000000..c2b9296
--- /dev/null
@@ -0,0 +1,177 @@
+.colorpicker {\r
+       width: 356px;\r
+       height: 176px;\r
+       overflow: hidden;\r
+       position: absolute;\r
+       background: url(../images/colorpicker_background.png);\r
+       font-family: Arial, Helvetica, sans-serif;\r
+       display: none;\r
+}\r
+.colorpicker_color {\r
+       width: 150px;\r
+       height: 150px;\r
+       left: 14px;\r
+       top: 13px;\r
+       position: absolute;\r
+       background: #f00;\r
+       overflow: hidden;\r
+       cursor: crosshair;\r
+}\r
+.colorpicker_color div {\r
+       position: absolute;\r
+       top: 0;\r
+       left: 0;\r
+       width: 150px;\r
+       height: 150px;\r
+       background: url(../images/colorpicker_overlay.png);\r
+}\r
+.colorpicker_color div div {\r
+       position: absolute;\r
+       top: 0;\r
+       left: 0;\r
+       width: 11px;\r
+       height: 11px;\r
+       overflow: hidden;\r
+       background: url(../images/colorpicker_select.gif);\r
+       margin: -5px 0 0 -5px;\r
+}\r
+.colorpicker_hue {\r
+       position: absolute;\r
+       top: 13px;\r
+       left: 171px;\r
+       width: 35px;\r
+       height: 150px;\r
+       cursor: n-resize;\r
+}\r
+.colorpicker_hue div {\r
+       position: absolute;\r
+       width: 35px;\r
+       height: 9px;\r
+       overflow: hidden;\r
+       background: url(../images/colorpicker_indic.gif) left top;\r
+       margin: -4px 0 0 0;\r
+       left: 0px;\r
+}\r
+.colorpicker_new_color {\r
+       position: absolute;\r
+       width: 60px;\r
+       height: 30px;\r
+       left: 213px;\r
+       top: 13px;\r
+       background: #f00;\r
+}\r
+.colorpicker_current_color {\r
+       position: absolute;\r
+       width: 60px;\r
+       height: 30px;\r
+       left: 283px;\r
+       top: 13px;\r
+       background: #f00;\r
+}\r
+.colorpicker input {\r
+       background-color: transparent;\r
+       border: 1px solid transparent;\r
+       position: absolute;\r
+       font-size: 10px;\r
+       font-family: Arial, Helvetica, sans-serif;\r
+       color: #898989;\r
+       top: 4px;\r
+       right: 11px;\r
+       text-align: right;\r
+       margin: 0;\r
+       padding: 0;\r
+       height: 11px;\r
+}\r
+.colorpicker_hex {\r
+       position: absolute;\r
+       width: 72px;\r
+       height: 22px;\r
+       background: url(../images/colorpicker_hex.png) top;\r
+       left: 212px;\r
+       top: 142px;\r
+}\r
+.colorpicker_hex input {\r
+       right: 6px;\r
+}\r
+.colorpicker_field {\r
+       height: 22px;\r
+       width: 62px;\r
+       background-position: top;\r
+       position: absolute;\r
+}\r
+.colorpicker_field span {\r
+       position: absolute;\r
+       width: 12px;\r
+       height: 22px;\r
+       overflow: hidden;\r
+       top: 0;\r
+       right: 0;\r
+       cursor: n-resize;\r
+}\r
+.colorpicker_rgb_r {\r
+       background-image: url(../images/colorpicker_rgb_r.png);\r
+       top: 52px;\r
+       left: 212px;\r
+}\r
+.colorpicker_rgb_g {\r
+       background-image: url(../images/colorpicker_rgb_g.png);\r
+       top: 82px;\r
+       left: 212px;\r
+}\r
+.colorpicker_rgb_b {\r
+       background-image: url(../images/colorpicker_rgb_b.png);\r
+       top: 112px;\r
+       left: 212px;\r
+}\r
+.colorpicker_hsb_h {\r
+       background-image: url(../images/colorpicker_hsb_h.png);\r
+       top: 52px;\r
+       left: 282px;\r
+}\r
+.colorpicker_hsb_s {\r
+       background-image: url(../images/colorpicker_hsb_s.png);\r
+       top: 82px;\r
+       left: 282px;\r
+}\r
+.colorpicker_hsb_b {\r
+       background-image: url(../images/colorpicker_hsb_b.png);\r
+       top: 112px;\r
+       left: 282px;\r
+}\r
+.colorpicker_submit {\r
+       position: absolute;\r
+       width: 22px;\r
+       height: 22px;\r
+       background: url(../images/colorpicker_submit.png) top;\r
+       left: 322px;\r
+       top: 142px;\r
+       overflow: hidden;\r
+}\r
+.colorpicker_focus {\r
+       background-position: center;\r
+}\r
+.colorpicker_hex.colorpicker_focus {\r
+       background-position: bottom;\r
+}\r
+.colorpicker_submit.colorpicker_focus {\r
+       background-position: bottom;\r
+}\r
+.colorpicker_slider {\r
+       background-position: bottom;\r
+}
+
+/* chery picked from layout.css (should be more "jquery-ui" like when we get a chance */
+.colorSelector  {
+       background:url("../images/select.png") repeat scroll 0 0 transparent;
+       height:36px;
+       position:relative;
+       width:36px;
+}
+.colorSelector div {
+       position: absolute;
+       top: 3px;
+       left: 3px;
+       width: 30px;
+       height: 30px;
+       background: url(../images/select.png) center;
+}\r
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/css/layout.css b/js2/mwEmbed/libClipEdit/colorpicker/css/layout.css
new file mode 100644 (file)
index 0000000..8b3f00f
--- /dev/null
@@ -0,0 +1,218 @@
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td { \r
+       margin:0;\r
+       padding:0;\r
+}\r
+table {\r
+       border-collapse:collapse;\r
+       border-spacing:0;\r
+}\r
+fieldset,img { \r
+       border:0;\r
+}\r
+address,caption,cite,code,dfn,em,strong,th,var {\r
+       font-style:normal;\r
+       font-weight:normal;\r
+}\r
+ol,ul {\r
+       list-style:none;\r
+}\r
+caption,th {\r
+       text-align:left;\r
+}\r
+h1,h2,h3,h4,h5,h6 {\r
+       font-size:100%;\r
+       font-weight:normal;\r
+}\r
+q:before,q:after {\r
+       content:'';\r
+}\r
+abbr,acronym { border:0;\r
+}\r
+html, body {\r
+       background-color: #fff;\r
+       font-family: Arial, Helvetica, sans-serif;\r
+       font-size: 12px;\r
+       line-height: 18px;\r
+       color: #52697E;\r
+}\r
+body {\r
+       text-align: center;\r
+       overflow: auto;\r
+}\r
+.wrapper {\r
+       width: 700px;\r
+       margin: 0 auto;\r
+       text-align: left;\r
+}\r
+h1 {\r
+       font-size: 21px;\r
+       height: 47px;\r
+       line-height: 47px;\r
+       text-transform: uppercase;\r
+}\r
+.navigationTabs {\r
+       height: 23px;\r
+       line-height: 23px;\r
+       border-bottom: 1px solid #ccc;\r
+}\r
+.navigationTabs li {\r
+       float: left;\r
+       height: 23px;\r
+       line-height: 23px;\r
+       padding-right: 3px;\r
+}\r
+.navigationTabs li a{\r
+       float: left;\r
+       dispaly: block;\r
+       height: 23px;\r
+       line-height: 23px;\r
+       padding: 0 10px;\r
+       overflow: hidden;\r
+       color: #52697E;\r
+       background-color: #eee;\r
+       position: relative;\r
+       text-decoration: none;\r
+}\r
+.navigationTabs li a:hover {\r
+       background-color: #f0f0f0;\r
+}\r
+.navigationTabs li a.active {\r
+       background-color: #fff;\r
+       border: 1px solid #ccc;\r
+       border-bottom: 0px solid;\r
+}\r
+.tabsContent {\r
+       border: 1px solid #ccc;\r
+       border-top: 0px solid;\r
+       width: 698px;\r
+       overflow: hidden;\r
+}\r
+.tab {\r
+       padding: 16px;\r
+       display: none;\r
+}\r
+.tab h2 {\r
+       font-weight: bold;\r
+       font-size: 16px;\r
+}\r
+.tab h3 {\r
+       font-weight: bold;\r
+       font-size: 14px;\r
+       margin-top: 20px;\r
+}\r
+.tab p {\r
+       margin-top: 16px;\r
+       clear: both;\r
+}\r
+.tab ul {\r
+       margin-top: 16px;\r
+       list-style: disc;\r
+}\r
+.tab li {\r
+       margin: 10px 0 0 35px;\r
+}\r
+.tab a {\r
+       color: #8FB0CF;\r
+}\r
+.tab strong {\r
+       font-weight: bold;\r
+}\r
+.tab pre {\r
+       font-size: 11px;\r
+       margin-top: 20px;\r
+       width: 668px;\r
+       overflow: auto;\r
+       clear: both;\r
+}\r
+.tab table {\r
+       width: 100%;\r
+}\r
+.tab table td {\r
+       padding: 6px 10px 6px 0;\r
+       vertical-align: top;\r
+}\r
+.tab dt {\r
+       margin-top: 16px;\r
+}\r
+\r
+#colorSelector {\r
+       position: relative;\r
+       width: 36px;\r
+       height: 36px;\r
+       background: url(../images/select.png);\r
+}\r
+#colorSelector div {\r
+       position: absolute;\r
+       top: 3px;\r
+       left: 3px;\r
+       width: 30px;\r
+       height: 30px;\r
+       background: url(../images/select.png) center;\r
+}\r
+#colorSelector2 {\r
+       position: absolute;\r
+       top: 0;\r
+       left: 0;\r
+       width: 36px;\r
+       height: 36px;\r
+       background: url(../images/select2.png);\r
+}\r
+#colorSelector2 div {\r
+       position: absolute;\r
+       top: 4px;\r
+       left: 4px;\r
+       width: 28px;\r
+       height: 28px;\r
+       background: url(../images/select2.png) center;\r
+}\r
+#colorpickerHolder2 {\r
+       top: 32px;\r
+       left: 0;\r
+       width: 356px;\r
+       height: 0;\r
+       overflow: hidden;\r
+       position: absolute;\r
+}\r
+#colorpickerHolder2 .colorpicker {\r
+       background-image: url(../images/custom_background.png);\r
+       position: absolute;\r
+       bottom: 0;\r
+       left: 0;\r
+}\r
+#colorpickerHolder2 .colorpicker_hue div {\r
+       background-image: url(../images/custom_indic.gif);\r
+}\r
+#colorpickerHolder2 .colorpicker_hex {\r
+       background-image: url(../images/custom_hex.png);\r
+}\r
+#colorpickerHolder2 .colorpicker_rgb_r {\r
+       background-image: url(../images/custom_rgb_r.png);\r
+}\r
+#colorpickerHolder2 .colorpicker_rgb_g {\r
+       background-image: url(../images/custom_rgb_g.png);\r
+}\r
+#colorpickerHolder2 .colorpicker_rgb_b {\r
+       background-image: url(../images/custom_rgb_b.png);\r
+}\r
+#colorpickerHolder2 .colorpicker_hsb_s {\r
+       background-image: url(../images/custom_hsb_s.png);\r
+       display: none;\r
+}\r
+#colorpickerHolder2 .colorpicker_hsb_h {\r
+       background-image: url(../images/custom_hsb_h.png);\r
+       display: none;\r
+}\r
+#colorpickerHolder2 .colorpicker_hsb_b {\r
+       background-image: url(../images/custom_hsb_b.png);\r
+       display: none;\r
+}\r
+#colorpickerHolder2 .colorpicker_submit {\r
+       background-image: url(../images/custom_submit.png);\r
+}\r
+#colorpickerHolder2 .colorpicker input {\r
+       color: #778398;\r
+}\r
+#customWidget {\r
+       position: relative;\r
+       height: 36px;\r
+}\r
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/Thumbs.db b/js2/mwEmbed/libClipEdit/colorpicker/images/Thumbs.db
new file mode 100644 (file)
index 0000000..d396c36
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/Thumbs.db differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/blank.gif b/js2/mwEmbed/libClipEdit/colorpicker/images/blank.gif
new file mode 100644 (file)
index 0000000..75b945d
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/blank.gif differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_background.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_background.png
new file mode 100644 (file)
index 0000000..8401572
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_background.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hex.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hex.png
new file mode 100644 (file)
index 0000000..4e532d7
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hex.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_b.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_b.png
new file mode 100644 (file)
index 0000000..dfac595
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_b.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_h.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_h.png
new file mode 100644 (file)
index 0000000..3977ed9
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_h.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_s.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_s.png
new file mode 100644 (file)
index 0000000..a2a6997
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_hsb_s.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_indic.gif b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_indic.gif
new file mode 100644 (file)
index 0000000..f9fa95e
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_indic.gif differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_overlay.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_overlay.png
new file mode 100644 (file)
index 0000000..561cdd9
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_overlay.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_b.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_b.png
new file mode 100644 (file)
index 0000000..dfac595
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_b.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_g.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_g.png
new file mode 100644 (file)
index 0000000..72b3276
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_g.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_r.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_r.png
new file mode 100644 (file)
index 0000000..4855fe0
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_rgb_r.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_select.gif b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_select.gif
new file mode 100644 (file)
index 0000000..599f7f1
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_select.gif differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_submit.png b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_submit.png
new file mode 100644 (file)
index 0000000..7f4c082
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/colorpicker_submit.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_background.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_background.png
new file mode 100644 (file)
index 0000000..cf55ffd
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_background.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hex.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hex.png
new file mode 100644 (file)
index 0000000..888f444
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hex.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_b.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_b.png
new file mode 100644 (file)
index 0000000..2f99dae
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_b.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_h.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_h.png
new file mode 100644 (file)
index 0000000..a217e92
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_h.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_s.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_s.png
new file mode 100644 (file)
index 0000000..7826b41
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_hsb_s.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_indic.gif b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_indic.gif
new file mode 100644 (file)
index 0000000..222fb94
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_indic.gif differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_b.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_b.png
new file mode 100644 (file)
index 0000000..80764e5
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_b.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_g.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_g.png
new file mode 100644 (file)
index 0000000..fc9778b
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_g.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_r.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_r.png
new file mode 100644 (file)
index 0000000..91b0cd4
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_rgb_r.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/custom_submit.png b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_submit.png
new file mode 100644 (file)
index 0000000..cd202cd
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/custom_submit.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/select.png b/js2/mwEmbed/libClipEdit/colorpicker/images/select.png
new file mode 100644 (file)
index 0000000..21213bf
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/select.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/select2.png b/js2/mwEmbed/libClipEdit/colorpicker/images/select2.png
new file mode 100644 (file)
index 0000000..2cd2cab
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/select2.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/images/slider.png b/js2/mwEmbed/libClipEdit/colorpicker/images/slider.png
new file mode 100644 (file)
index 0000000..8b03da9
Binary files /dev/null and b/js2/mwEmbed/libClipEdit/colorpicker/images/slider.png differ
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/index.html b/js2/mwEmbed/libClipEdit/colorpicker/index.html
new file mode 100644 (file)
index 0000000..e1ad578
--- /dev/null
@@ -0,0 +1,184 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\r
+<head>\r
+       <link rel="stylesheet" href="css/colorpicker.css" type="text/css" />\r
+    <link rel="stylesheet" media="screen" type="text/css" href="css/layout.css" />\r
+    <title>ColorPicker - jQuery plugin</title>\r
+       <script type="text/javascript" src="js/jquery.js"></script>\r
+       <script type="text/javascript" src="js/colorpicker.js"></script>\r
+    <script type="text/javascript" src="js/eye.js"></script>\r
+    <script type="text/javascript" src="js/utils.js"></script>\r
+    <script type="text/javascript" src="js/layout.js?ver=1.0.2"></script>\r
+</head>\r
+<body>\r
+    <div class="wrapper">\r
+        <h1>Color Picker - jQuery plugin</h1>\r
+        <ul class="navigationTabs">\r
+            <li><a href="#about" rel="about">About</a></li>\r
+            <li><a href="#download" rel="download">Download</a></li>\r
+            <li><a href="#implement" rel="implement">Implement</a></li>\r
+        </ul>\r
+        <div class="tabsContent">\r
+            <div class="tab">\r
+                <h2>About</h2>\r
+                <p>A simple component to select color in the same way you select color in Adobe Photoshop</p>\r
+                               <h3>Last update</h3>\r
+                               <p>23.05.2009 - Check Download tab</p>\r
+                <h3>Features</h3>\r
+                <ul>\r
+                    <li>Flat mode - as element in page</li>\r
+                    <li>Powerful controls for color selection</li>\r
+                                       <li>Easy to customize the look by changing some images</li>\r
+                                       <li>Fits into the viewport</li>\r
+                </ul>\r
+                               <h3>License</h3>\r
+                               <p>Dual licensed under the MIT and GPL licenses.</p>\r
+                <h3>Examples</h3>\r
+                <p>Flat mode.</p>\r
+                <p id="colorpickerHolder">\r
+                </p>\r
+                <pre>\r
+$('#colorpickerHolder').ColorPicker({flat: true});\r
+                </pre>\r
+                <p>Custom skin and using flat mode to display the color picker in a custom widget.</p>\r
+                               <div id="customWidget">\r
+                                       <div id="colorSelector2"><div style="background-color: #00ff00"></div></div>\r
+                       <div id="colorpickerHolder2">\r
+                       </div>\r
+                               </div>\r
+\r
+                               <p>Attached to an text field and using callback functions to update the color with field's value and set the value back in the field by submiting the color.</p>\r
+                               <p><input type="text" maxlength="6" size="6" id="colorpickerField1" value="00ff00" /></p>\r
+                               <p><input type="text" maxlength="6" size="6" id="colorpickerField3" value="0000ff" /></p>\r
+                               <p><input type="text" maxlength="6" size="6" id="colorpickerField2" value="ff0000" /></p>\r
+                               <pre>$('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({\r
+       onSubmit: function(hsb, hex, rgb, el) {\r
+               $(el).val(hex);\r
+               $(el).ColorPickerHide();\r
+       },\r
+       onBeforeShow: function () {\r
+               $(this).ColorPickerSetColor(this.value);\r
+       }\r
+})\r
+.bind('keyup', function(){\r
+       $(this).ColorPickerSetColor(this.value);\r
+});\r
+</pre>\r
+                               <p>Attached to DOMElement and using callbacks to live preview the color and adding animation.</p>\r
+                               <p>\r
+                                       <div id="colorSelector"><div style="background-color: #0000ff"></div></div>\r
+                               </p>\r
+                               <pre>\r
+$('#colorSelector').ColorPicker({\r
+       color: '#0000ff',\r
+       onShow: function (colpkr) {\r
+               $(colpkr).fadeIn(500);\r
+               return false;\r
+       },\r
+       onHide: function (colpkr) {\r
+               $(colpkr).fadeOut(500);\r
+               return false;\r
+       },\r
+       onChange: function (hsb, hex, rgb) {\r
+               $('#colorSelector div').css('backgroundColor', '#' + hex);\r
+       }\r
+});\r
+</pre>\r
+            </div>\r
+            <div class="tab">\r
+                <h2>Download</h2>\r
+                <p><a href="colorpicker.zip">colorpicker.zip (73 kb)</a>: jQuery, Javscript files, CSS files, images, examples and instructions.</p>\r
+                <h3>Changelog</h3>\r
+                <dl>\r
+                                       <dt>23.05.2009</dt>\r
+                                       <dd>Added: close on color selection example</dd>\r
+                                       <dd>Added: restore original color option</dd>\r
+                                       <dd>Changed: color update on key up event</dd>\r
+                                       <dd>Fixed: colorpicker hide and show methods</dd>\r
+                                       <dd>Fixed: reference to options. Multiple fields with colorpickers is possible now.</dd>\r
+                                       <dd>Fixed: RGB to HSB convertion</dd>\r
+                                       <dt>22.08.2008</dt>\r
+                                       <dd>Fixed bug: where some events were not canceled right on Safari</dd>\r
+                                       <dd>Fixed bug: where teh view port was not detected right on Safari</dd>\r
+                                       <dt>16-07-2008</dt>\r
+                                       <dd>Fixed bug where the letter 'F' could not be typed in the Hex field</dd>\r
+                                       <dd>Fixed bug where the changes on Hex field where not parsed</dd>\r
+                                       <dd>Added new option 'livePreview'</dd>\r
+                                       <dt>08-07-2008</dt>\r
+                                       <dd>Fixed typo in the code, both JavaScript and CSS</dd>\r
+                                       <dd>Changed the cursor for some elements</dd>\r
+                                       <dd>Added new demo explaining how to implement custom skin</dd>\r
+                                       <dt>07.07.2008</dt>\r
+                                       <dd>The first release.</dd>\r
+                </dl>\r
+            </div>\r
+            <div class="tab">\r
+                <h2>Implement</h2>\r
+                <p>Attach the Javascript and CSS files to your document. Edit CSS file and fix the paths to  images and change colors to fit your site theme.</p>\r
+                <pre>\r
+&lt;link rel="stylesheet" media="screen" type="text/css" href="css/colorpicker.css" /&gt;\r
+&lt;script type="text/javascript" src="js/colorpicker.js"&gt;&lt;/script&gt;\r
+                </pre>\r
+                <h3>Invocation code</h3>\r
+                <p>All you have to do is to select the elements in a jQuery way and call the plugin.</p>\r
+                <pre>\r
+ $('input').ColorPicker(options);\r
+                </pre>\r
+                <h3>Options</h3>\r
+                <p>A hash of parameters. All parameters are optional.</p>\r
+                <table>\r
+                       <tr>\r
+                               <td><strong>eventName</strong></td>\r
+                               <td>string</td>\r
+                               <td>The desired event to trigger the colorpicker. Default: 'click'</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>color</strong></td>\r
+                               <td>string or hash</td>\r
+                               <td>The default color. String for hex color or hash for RGB and HSB ({r:255, r:0, b:0}) . Default: 'ff0000'</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>flat</strong></td>\r
+                               <td>boolean</td>\r
+                               <td>Whatever if the color picker is appended to the element or triggered by an event. Default false</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>livePreview</strong></td>\r
+                               <td>boolean</td>\r
+                               <td>Whatever if the color values are filled in the fields while changing values on selector or a field. If false it may improve speed. Default true</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>onShow</strong></td>\r
+                               <td>function</td>\r
+                               <td>Callback function triggered when the color picker is shown</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>onBeforeShow</strong></td>\r
+                               <td>function</td>\r
+                               <td>Callback function triggered before the color picker is shown</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>onHide</strong></td>\r
+                               <td>function</td>\r
+                               <td>Callback function triggered when the color picker is hidden</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>onChange</strong></td>\r
+                               <td>function</td>\r
+                               <td>Callback function triggered when the color is changed</td>\r
+                       </tr>\r
+                       <tr>\r
+                               <td><strong>onSubmit</strong></td>\r
+                               <td>function</td>\r
+                               <td>Callback function triggered when the color it is chosen</td>\r
+                       </tr>\r
+                </table>\r
+                <h3>Set color</h3>\r
+                <p>If you want to set a new color.</p>\r
+                <pre>$('input').ColorPickerSetColor(color);</pre>\r
+                               <p>The 'color' argument is the same format as the option color, string for hex color or hash for RGB and HSB ({r:255, r:0, b:0}).</p>\r
+            </div>\r
+        </div>\r
+    </div>\r
+</body>\r
+</html>\r
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/js/colorpicker.js b/js2/mwEmbed/libClipEdit/colorpicker/js/colorpicker.js
new file mode 100644 (file)
index 0000000..10a2b22
--- /dev/null
@@ -0,0 +1,484 @@
+/**\r
+ *\r
+ * Color picker\r
+ * Author: Stefan Petre www.eyecon.ro\r
+ * \r
+ * Dual licensed under the MIT and GPL licenses\r
+ * \r
+ */\r
+(function ($) {\r
+       var ColorPicker = function () {\r
+               var\r
+                       ids = {},\r
+                       inAction,\r
+                       charMin = 65,\r
+                       visible,\r
+                       tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',\r
+                       defaults = {\r
+                               eventName: 'click',\r
+                               onShow: function () {},\r
+                               onBeforeShow: function(){},\r
+                               onHide: function () {},\r
+                               onChange: function () {},\r
+                               onSubmit: function () {},\r
+                               color: 'ff0000',\r
+                               livePreview: true,\r
+                               flat: false\r
+                       },\r
+                       fillRGBFields = function  (hsb, cal) {\r
+                               var rgb = HSBToRGB(hsb);\r
+                               $(cal).data('colorpicker').fields\r
+                                       .eq(1).val(rgb.r).end()\r
+                                       .eq(2).val(rgb.g).end()\r
+                                       .eq(3).val(rgb.b).end();\r
+                       },\r
+                       fillHSBFields = function  (hsb, cal) {\r
+                               $(cal).data('colorpicker').fields\r
+                                       .eq(4).val(hsb.h).end()\r
+                                       .eq(5).val(hsb.s).end()\r
+                                       .eq(6).val(hsb.b).end();\r
+                       },\r
+                       fillHexFields = function (hsb, cal) {\r
+                               $(cal).data('colorpicker').fields\r
+                                       .eq(0).val(HSBToHex(hsb)).end();\r
+                       },\r
+                       setSelector = function (hsb, cal) {\r
+                               $(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));\r
+                               $(cal).data('colorpicker').selectorIndic.css({\r
+                                       left: parseInt(150 * hsb.s/100, 10),\r
+                                       top: parseInt(150 * (100-hsb.b)/100, 10)\r
+                               });\r
+                       },\r
+                       setHue = function (hsb, cal) {\r
+                               $(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));\r
+                       },\r
+                       setCurrentColor = function (hsb, cal) {\r
+                               $(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));\r
+                       },\r
+                       setNewColor = function (hsb, cal) {\r
+                               $(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));\r
+                       },\r
+                       keyDown = function (ev) {\r
+                               var pressedKey = ev.charCode || ev.keyCode || -1;\r
+                               if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {\r
+                                       return false;\r
+                               }\r
+                               var cal = $(this).parent().parent();\r
+                               if (cal.data('colorpicker').livePreview === true) {\r
+                                       change.apply(this);\r
+                               }\r
+                       },\r
+                       change = function (ev) {\r
+                               var cal = $(this).parent().parent(), col;\r
+                               if (this.parentNode.className.indexOf('_hex') > 0) {\r
+                                       cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));\r
+                               } else if (this.parentNode.className.indexOf('_hsb') > 0) {\r
+                                       cal.data('colorpicker').color = col = fixHSB({\r
+                                               h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),\r
+                                               s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),\r
+                                               b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)\r
+                                       });\r
+                               } else {\r
+                                       cal.data('colorpicker').color = col = RGBToHSB(fixRGB({\r
+                                               r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),\r
+                                               g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),\r
+                                               b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)\r
+                                       }));\r
+                               }\r
+                               if (ev) {\r
+                                       fillRGBFields(col, cal.get(0));\r
+                                       fillHexFields(col, cal.get(0));\r
+                                       fillHSBFields(col, cal.get(0));\r
+                               }\r
+                               setSelector(col, cal.get(0));\r
+                               setHue(col, cal.get(0));\r
+                               setNewColor(col, cal.get(0));\r
+                               cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);\r
+                       },\r
+                       blur = function (ev) {\r
+                               var cal = $(this).parent().parent();\r
+                               cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');\r
+                       },\r
+                       focus = function () {\r
+                               charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;\r
+                               $(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');\r
+                               $(this).parent().addClass('colorpicker_focus');\r
+                       },\r
+                       downIncrement = function (ev) {\r
+                               var field = $(this).parent().find('input').focus();\r
+                               var current = {\r
+                                       el: $(this).parent().addClass('colorpicker_slider'),\r
+                                       max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),\r
+                                       y: ev.pageY,\r
+                                       field: field,\r
+                                       val: parseInt(field.val(), 10),\r
+                                       preview: $(this).parent().parent().data('colorpicker').livePreview                                      \r
+                               };\r
+                               $(document).bind('mouseup', current, upIncrement);\r
+                               $(document).bind('mousemove', current, moveIncrement);\r
+                       },\r
+                       moveIncrement = function (ev) {\r
+                               ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));\r
+                               if (ev.data.preview) {\r
+                                       change.apply(ev.data.field.get(0), [true]);\r
+                               }\r
+                               return false;\r
+                       },\r
+                       upIncrement = function (ev) {\r
+                               change.apply(ev.data.field.get(0), [true]);\r
+                               ev.data.el.removeClass('colorpicker_slider').find('input').focus();\r
+                               $(document).unbind('mouseup', upIncrement);\r
+                               $(document).unbind('mousemove', moveIncrement);\r
+                               return false;\r
+                       },\r
+                       downHue = function (ev) {\r
+                               var current = {\r
+                                       cal: $(this).parent(),\r
+                                       y: $(this).offset().top\r
+                               };\r
+                               current.preview = current.cal.data('colorpicker').livePreview;\r
+                               $(document).bind('mouseup', current, upHue);\r
+                               $(document).bind('mousemove', current, moveHue);\r
+                       },\r
+                       moveHue = function (ev) {\r
+                               change.apply(\r
+                                       ev.data.cal.data('colorpicker')\r
+                                               .fields\r
+                                               .eq(4)\r
+                                               .val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))\r
+                                               .get(0),\r
+                                       [ev.data.preview]\r
+                               );\r
+                               return false;\r
+                       },\r
+                       upHue = function (ev) {\r
+                               fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
+                               fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
+                               $(document).unbind('mouseup', upHue);\r
+                               $(document).unbind('mousemove', moveHue);\r
+                               return false;\r
+                       },\r
+                       downSelector = function (ev) {\r
+                               var current = {\r
+                                       cal: $(this).parent(),\r
+                                       pos: $(this).offset()\r
+                               };\r
+                               current.preview = current.cal.data('colorpicker').livePreview;\r
+                               $(document).bind('mouseup', current, upSelector);\r
+                               $(document).bind('mousemove', current, moveSelector);\r
+                       },\r
+                       moveSelector = function (ev) {\r
+                               change.apply(\r
+                                       ev.data.cal.data('colorpicker')\r
+                                               .fields\r
+                                               .eq(6)\r
+                                               .val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))\r
+                                               .end()\r
+                                               .eq(5)\r
+                                               .val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))\r
+                                               .get(0),\r
+                                       [ev.data.preview]\r
+                               );\r
+                               return false;\r
+                       },\r
+                       upSelector = function (ev) {\r
+                               fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
+                               fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
+                               $(document).unbind('mouseup', upSelector);\r
+                               $(document).unbind('mousemove', moveSelector);\r
+                               return false;\r
+                       },\r
+                       enterSubmit = function (ev) {\r
+                               $(this).addClass('colorpicker_focus');\r
+                       },\r
+                       leaveSubmit = function (ev) {\r
+                               $(this).removeClass('colorpicker_focus');\r
+                       },\r
+                       clickSubmit = function (ev) {\r
+                               var cal = $(this).parent();\r
+                               var col = cal.data('colorpicker').color;\r
+                               cal.data('colorpicker').origColor = col;\r
+                               setCurrentColor(col, cal.get(0));\r
+                               cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);\r
+                       },\r
+                       show = function (ev) {\r
+                               var cal = $('#' + $(this).data('colorpickerId'));\r
+                               cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);\r
+                               var pos = $(this).offset();\r
+                               var viewPort = getViewport();\r
+                               var top = pos.top + this.offsetHeight;\r
+                               var left = pos.left;\r
+                               if (top + 176 > viewPort.t + viewPort.h) {\r
+                                       top -= this.offsetHeight + 176;\r
+                               }\r
+                               if (left + 356 > viewPort.l + viewPort.w) {\r
+                                       left -= 356;\r
+                               }\r
+                               cal.css({left: left + 'px', top: top + 'px'});\r
+                               if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {\r
+                                       cal.show();\r
+                               }\r
+                               $(document).bind('mousedown', {cal: cal}, hide);\r
+                               return false;\r
+                       },\r
+                       hide = function (ev) {\r
+                               if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {\r
+                                       if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {\r
+                                               ev.data.cal.hide();\r
+                                       }\r
+                                       $(document).unbind('mousedown', hide);\r
+                               }\r
+                       },\r
+                       isChildOf = function(parentEl, el, container) {\r
+                               if (parentEl == el) {\r
+                                       return true;\r
+                               }\r
+                               if (parentEl.contains) {\r
+                                       return parentEl.contains(el);\r
+                               }\r
+                               if ( parentEl.compareDocumentPosition ) {\r
+                                       return !!(parentEl.compareDocumentPosition(el) & 16);\r
+                               }\r
+                               var prEl = el.parentNode;\r
+                               while(prEl && prEl != container) {\r
+                                       if (prEl == parentEl)\r
+                                               return true;\r
+                                       prEl = prEl.parentNode;\r
+                               }\r
+                               return false;\r
+                       },\r
+                       getViewport = function () {\r
+                               var m = document.compatMode == 'CSS1Compat';\r
+                               return {\r
+                                       l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),\r
+                                       t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),\r
+                                       w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),\r
+                                       h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)\r
+                               };\r
+                       },\r
+                       fixHSB = function (hsb) {\r
+                               return {\r
+                                       h: Math.min(360, Math.max(0, hsb.h)),\r
+                                       s: Math.min(100, Math.max(0, hsb.s)),\r
+                                       b: Math.min(100, Math.max(0, hsb.b))\r
+                               };\r
+                       }, \r
+                       fixRGB = function (rgb) {\r
+                               return {\r
+                                       r: Math.min(255, Math.max(0, rgb.r)),\r
+                                       g: Math.min(255, Math.max(0, rgb.g)),\r
+                                       b: Math.min(255, Math.max(0, rgb.b))\r
+                               };\r
+                       },\r
+                       fixHex = function (hex) {\r
+                               var len = 6 - hex.length;\r
+                               if (len > 0) {\r
+                                       var o = [];\r
+                                       for (var i=0; i<len; i++) {\r
+                                               o.push('0');\r
+                                       }\r
+                                       o.push(hex);\r
+                                       hex = o.join('');\r
+                               }\r
+                               return hex;\r
+                       }, \r
+                       HexToRGB = function (hex) {\r
+                               var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);\r
+                               return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};\r
+                       },\r
+                       HexToHSB = function (hex) {\r
+                               return RGBToHSB(HexToRGB(hex));\r
+                       },\r
+                       RGBToHSB = function (rgb) {\r
+                               var hsb = {\r
+                                       h: 0,\r
+                                       s: 0,\r
+                                       b: 0\r
+                               };\r
+                               var min = Math.min(rgb.r, rgb.g, rgb.b);\r
+                               var max = Math.max(rgb.r, rgb.g, rgb.b);\r
+                               var delta = max - min;\r
+                               hsb.b = max;\r
+                               if (max != 0) {\r
+                                       \r
+                               }\r
+                               hsb.s = max != 0 ? 255 * delta / max : 0;\r
+                               if (hsb.s != 0) {\r
+                                       if (rgb.r == max) {\r
+                                               hsb.h = (rgb.g - rgb.b) / delta;\r
+                                       } else if (rgb.g == max) {\r
+                                               hsb.h = 2 + (rgb.b - rgb.r) / delta;\r
+                                       } else {\r
+                                               hsb.h = 4 + (rgb.r - rgb.g) / delta;\r
+                                       }\r
+                               } else {\r
+                                       hsb.h = -1;\r
+                               }\r
+                               hsb.h *= 60;\r
+                               if (hsb.h < 0) {\r
+                                       hsb.h += 360;\r
+                               }\r
+                               hsb.s *= 100/255;\r
+                               hsb.b *= 100/255;\r
+                               return hsb;\r
+                       },\r
+                       HSBToRGB = function (hsb) {\r
+                               var rgb = {};\r
+                               var h = Math.round(hsb.h);\r
+                               var s = Math.round(hsb.s*255/100);\r
+                               var v = Math.round(hsb.b*255/100);\r
+                               if(s == 0) {\r
+                                       rgb.r = rgb.g = rgb.b = v;\r
+                               } else {\r
+                                       var t1 = v;\r
+                                       var t2 = (255-s)*v/255;\r
+                                       var t3 = (t1-t2)*(h%60)/60;\r
+                                       if(h==360) h = 0;\r
+                                       if(h<60) {rgb.r=t1;     rgb.b=t2; rgb.g=t2+t3}\r
+                                       else if(h<120) {rgb.g=t1; rgb.b=t2;     rgb.r=t1-t3}\r
+                                       else if(h<180) {rgb.g=t1; rgb.r=t2;     rgb.b=t2+t3}\r
+                                       else if(h<240) {rgb.b=t1; rgb.r=t2;     rgb.g=t1-t3}\r
+                                       else if(h<300) {rgb.b=t1; rgb.g=t2;     rgb.r=t2+t3}\r
+                                       else if(h<360) {rgb.r=t1; rgb.g=t2;     rgb.b=t1-t3}\r
+                                       else {rgb.r=0; rgb.g=0; rgb.b=0}\r
+                               }\r
+                               return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};\r
+                       },\r
+                       RGBToHex = function (rgb) {\r
+                               var hex = [\r
+                                       rgb.r.toString(16),\r
+                                       rgb.g.toString(16),\r
+                                       rgb.b.toString(16)\r
+                               ];\r
+                               $.each(hex, function (nr, val) {\r
+                                       if (val.length == 1) {\r
+                                               hex[nr] = '0' + val;\r
+                                       }\r
+                               });\r
+                               return hex.join('');\r
+                       },\r
+                       HSBToHex = function (hsb) {\r
+                               return RGBToHex(HSBToRGB(hsb));\r
+                       },\r
+                       restoreOriginal = function () {\r
+                               var cal = $(this).parent();\r
+                               var col = cal.data('colorpicker').origColor;\r
+                               cal.data('colorpicker').color = col;\r
+                               fillRGBFields(col, cal.get(0));\r
+                               fillHexFields(col, cal.get(0));\r
+                               fillHSBFields(col, cal.get(0));\r
+                               setSelector(col, cal.get(0));\r
+                               setHue(col, cal.get(0));\r
+                               setNewColor(col, cal.get(0));\r
+                       };\r
+               return {\r
+                       init: function (opt) {\r
+                               opt = $.extend({}, defaults, opt||{});\r
+                               if (typeof opt.color == 'string') {\r
+                                       opt.color = HexToHSB(opt.color);\r
+                               } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {\r
+                                       opt.color = RGBToHSB(opt.color);\r
+                               } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {\r
+                                       opt.color = fixHSB(opt.color);\r
+                               } else {\r
+                                       return this;\r
+                               }\r
+                               return this.each(function () {\r
+                                       if (!$(this).data('colorpickerId')) {\r
+                                               var options = $.extend({}, opt);\r
+                                               options.origColor = opt.color;\r
+                                               var id = 'collorpicker_' + parseInt(Math.random() * 1000);\r
+                                               $(this).data('colorpickerId', id);\r
+                                               var cal = $(tpl).attr('id', id);\r
+                                               if (options.flat) {\r
+                                                       cal.appendTo(this).show();\r
+                                               } else {\r
+                                                       cal.appendTo(document.body);\r
+                                               }\r
+                                               options.fields = cal\r
+                                                                                       .find('input')\r
+                                                                                               .bind('keyup', keyDown)\r
+                                                                                               .bind('change', change)\r
+                                                                                               .bind('blur', blur)\r
+                                                                                               .bind('focus', focus);\r
+                                               cal\r
+                                                       .find('span').bind('mousedown', downIncrement).end()\r
+                                                       .find('>div.colorpicker_current_color').bind('click', restoreOriginal);\r
+                                               options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);\r
+                                               options.selectorIndic = options.selector.find('div div');\r
+                                               options.el = this;\r
+                                               options.hue = cal.find('div.colorpicker_hue div');\r
+                                               cal.find('div.colorpicker_hue').bind('mousedown', downHue);\r
+                                               options.newColor = cal.find('div.colorpicker_new_color');\r
+                                               options.currentColor = cal.find('div.colorpicker_current_color');\r
+                                               cal.data('colorpicker', options);\r
+                                               cal.find('div.colorpicker_submit')\r
+                                                       .bind('mouseenter', enterSubmit)\r
+                                                       .bind('mouseleave', leaveSubmit)\r
+                                                       .bind('click', clickSubmit);\r
+                                               fillRGBFields(options.color, cal.get(0));\r
+                                               fillHSBFields(options.color, cal.get(0));\r
+                                               fillHexFields(options.color, cal.get(0));\r
+                                               setHue(options.color, cal.get(0));\r
+                                               setSelector(options.color, cal.get(0));\r
+                                               setCurrentColor(options.color, cal.get(0));\r
+                                               setNewColor(options.color, cal.get(0));\r
+                                               if (options.flat) {\r
+                                                       cal.css({\r
+                                                               position: 'relative',\r
+                                                               display: 'block'\r
+                                                       });\r
+                                               } else {\r
+                                                       $(this).bind(options.eventName, show);\r
+                                               }\r
+                                       }\r
+                               });\r
+                       },\r
+                       showPicker: function() {\r
+                               return this.each( function () {\r
+                                       if ($(this).data('colorpickerId')) {\r
+                                               show.apply(this);\r
+                                       }\r
+                               });\r
+                       },\r
+                       hidePicker: function() {\r
+                               return this.each( function () {\r
+                                       if ($(this).data('colorpickerId')) {\r
+                                               $('#' + $(this).data('colorpickerId')).hide();\r
+                                       }\r
+                               });\r
+                       },\r
+                       setColor: function(col) {\r
+                               if (typeof col == 'string') {\r
+                                       col = HexToHSB(col);\r
+                               } else if (col.r != undefined && col.g != undefined && col.b != undefined) {\r
+                                       col = RGBToHSB(col);\r
+                               } else if (col.h != undefined && col.s != undefined && col.b != undefined) {\r
+                                       col = fixHSB(col);\r
+                               } else {\r
+                                       return this;\r
+                               }\r
+                               return this.each(function(){\r
+                                       if ($(this).data('colorpickerId')) {\r
+                                               var cal = $('#' + $(this).data('colorpickerId'));\r
+                                               cal.data('colorpicker').color = col;\r
+                                               cal.data('colorpicker').origColor = col;\r
+                                               fillRGBFields(col, cal.get(0));\r
+                                               fillHSBFields(col, cal.get(0));\r
+                                               fillHexFields(col, cal.get(0));\r
+                                               setHue(col, cal.get(0));\r
+                                               setSelector(col, cal.get(0));\r
+                                               setCurrentColor(col, cal.get(0));\r
+                                               setNewColor(col, cal.get(0));\r
+                                       }\r
+                               });\r
+                       }\r
+               };\r
+       }();\r
+       $.fn.extend({\r
+               ColorPicker: ColorPicker.init,\r
+               ColorPickerHide: ColorPicker.hidePicker,\r
+               ColorPickerShow: ColorPicker.showPicker,\r
+               ColorPickerSetColor: ColorPicker.setColor\r
+       });\r
+})(jQuery)
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/js/eye.js b/js2/mwEmbed/libClipEdit/colorpicker/js/eye.js
new file mode 100644 (file)
index 0000000..ea70e64
--- /dev/null
@@ -0,0 +1,34 @@
+/**\r
+ *\r
+ * Zoomimage\r
+ * Author: Stefan Petre www.eyecon.ro\r
+ * \r
+ */\r
+(function($){\r
+       var EYE = window.EYE = function() {\r
+               var _registered = {\r
+                       init: []\r
+               };\r
+               return {\r
+                       init: function() {\r
+                               $.each(_registered.init, function(nr, fn){\r
+                                       fn.call();\r
+                               });\r
+                       },\r
+                       extend: function(prop) {\r
+                               for (var i in prop) {\r
+                                       if (prop[i] != undefined) {\r
+                                               this[i] = prop[i];\r
+                                       }\r
+                               }\r
+                       },\r
+                       register: function(fn, type) {\r
+                               if (!_registered[type]) {\r
+                                       _registered[type] = [];\r
+                               }\r
+                               _registered[type].push(fn);\r
+                       }\r
+               };\r
+       }();\r
+       $(EYE.init);\r
+})(jQuery);\r
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/js/layout.js b/js2/mwEmbed/libClipEdit/colorpicker/js/layout.js
new file mode 100644 (file)
index 0000000..e0dfb8f
--- /dev/null
@@ -0,0 +1,67 @@
+(function($){\r
+       var initLayout = function() {\r
+               var hash = window.location.hash.replace('#', '');\r
+               var currentTab = $('ul.navigationTabs a')\r
+                                                       .bind('click', showTab)\r
+                                                       .filter('a[rel=' + hash + ']');\r
+               if (currentTab.size() == 0) {\r
+                       currentTab = $('ul.navigationTabs a:first');\r
+               }\r
+               showTab.apply(currentTab.get(0));\r
+               $('#colorpickerHolder').ColorPicker({flat: true});\r
+               $('#colorpickerHolder2').ColorPicker({\r
+                       flat: true,\r
+                       color: '#00ff00',\r
+                       onSubmit: function(hsb, hex, rgb) {\r
+                               $('#colorSelector2 div').css('backgroundColor', '#' + hex);\r
+                       }\r
+               });\r
+               $('#colorpickerHolder2>div').css('position', 'absolute');\r
+               var widt = false;\r
+               $('#colorSelector2').bind('click', function() {\r
+                       $('#colorpickerHolder2').stop().animate({height: widt ? 0 : 173}, 500);\r
+                       widt = !widt;\r
+               });\r
+               $('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({\r
+                       onSubmit: function(hsb, hex, rgb, el) {\r
+                               $(el).val(hex);\r
+                               $(el).ColorPickerHide();\r
+                       },\r
+                       onBeforeShow: function () {\r
+                               $(this).ColorPickerSetColor(this.value);\r
+                       }\r
+               })\r
+               .bind('keyup', function(){\r
+                       $(this).ColorPickerSetColor(this.value);\r
+               });\r
+               $('#colorSelector').ColorPicker({\r
+                       color: '#0000ff',\r
+                       onShow: function (colpkr) {\r
+                               $(colpkr).fadeIn(500);\r
+                               return false;\r
+                       },\r
+                       onHide: function (colpkr) {\r
+                               $(colpkr).fadeOut(500);\r
+                               return false;\r
+                       },\r
+                       onChange: function (hsb, hex, rgb) {\r
+                               $('#colorSelector div').css('backgroundColor', '#' + hex);\r
+                       }\r
+               });\r
+       };\r
+       \r
+       var showTab = function(e) {\r
+               var tabIndex = $('ul.navigationTabs a')\r
+                                                       .removeClass('active')\r
+                                                       .index(this);\r
+               $(this)\r
+                       .addClass('active')\r
+                       .blur();\r
+               $('div.tab')\r
+                       .hide()\r
+                               .eq(tabIndex)\r
+                               .show();\r
+       };\r
+       \r
+       EYE.register(initLayout, 'init');\r
+})(jQuery)
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/colorpicker/js/utils.js b/js2/mwEmbed/libClipEdit/colorpicker/js/utils.js
new file mode 100644 (file)
index 0000000..cc7ce14
--- /dev/null
@@ -0,0 +1,252 @@
+/**\r
+ *\r
+ * Utilities\r
+ * Author: Stefan Petre www.eyecon.ro\r
+ * \r
+ */\r
+(function($) {\r
+EYE.extend({\r
+       getPosition : function(e, forceIt)\r
+       {\r
+               var x = 0;\r
+               var y = 0;\r
+               var es = e.style;\r
+               var restoreStyles = false;\r
+               if (forceIt && jQuery.curCSS(e,'display') == 'none') {\r
+                       var oldVisibility = es.visibility;\r
+                       var oldPosition = es.position;\r
+                       restoreStyles = true;\r
+                       es.visibility = 'hidden';\r
+                       es.display = 'block';\r
+                       es.position = 'absolute';\r
+               }\r
+               var el = e;\r
+               if (el.getBoundingClientRect) { // IE\r
+                       var box = el.getBoundingClientRect();\r
+                       x = box.left + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) - 2;\r
+                       y = box.top + Math.max(document.documentElement.scrollTop, document.body.scrollTop) - 2;\r
+               } else {\r
+                       x = el.offsetLeft;\r
+                       y = el.offsetTop;\r
+                       el = el.offsetParent;\r
+                       if (e != el) {\r
+                               while (el) {\r
+                                       x += el.offsetLeft;\r
+                                       y += el.offsetTop;\r
+                                       el = el.offsetParent;\r
+                               }\r
+                       }\r
+                       if (jQuery.browser.safari && jQuery.curCSS(e, 'position') == 'absolute' ) {\r
+                               x -= document.body.offsetLeft;\r
+                               y -= document.body.offsetTop;\r
+                       }\r
+                       el = e.parentNode;\r
+                       while (el && el.tagName.toUpperCase() != 'BODY' && el.tagName.toUpperCase() != 'HTML') \r
+                       {\r
+                               if (jQuery.curCSS(el, 'display') != 'inline') {\r
+                                       x -= el.scrollLeft;\r
+                                       y -= el.scrollTop;\r
+                               }\r
+                               el = el.parentNode;\r
+                       }\r
+               }\r
+               if (restoreStyles == true) {\r
+                       es.display = 'none';\r
+                       es.position = oldPosition;\r
+                       es.visibility = oldVisibility;\r
+               }\r
+               return {x:x, y:y};\r
+       },\r
+       getSize : function(e)\r
+       {\r
+               var w = parseInt(jQuery.curCSS(e,'width'), 10);\r
+               var h = parseInt(jQuery.curCSS(e,'height'), 10);\r
+               var wb = 0;\r
+               var hb = 0;\r
+               if (jQuery.curCSS(e, 'display') != 'none') {\r
+                       wb = e.offsetWidth;\r
+                       hb = e.offsetHeight;\r
+               } else {\r
+                       var es = e.style;\r
+                       var oldVisibility = es.visibility;\r
+                       var oldPosition = es.position;\r
+                       es.visibility = 'hidden';\r
+                       es.display = 'block';\r
+                       es.position = 'absolute';\r
+                       wb = e.offsetWidth;\r
+                       hb = e.offsetHeight;\r
+                       es.display = 'none';\r
+                       es.position = oldPosition;\r
+                       es.visibility = oldVisibility;\r
+               }\r
+               return {w:w, h:h, wb:wb, hb:hb};\r
+       },\r
+       getClient : function(e)\r
+       {\r
+               var h, w;\r
+               if (e) {\r
+                       w = e.clientWidth;\r
+                       h = e.clientHeight;\r
+               } else {\r
+                       var de = document.documentElement;\r
+                       w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;\r
+                       h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;\r
+               }\r
+               return {w:w,h:h};\r
+       },\r
+       getScroll : function (e)\r
+       {\r
+               var t=0, l=0, w=0, h=0, iw=0, ih=0;\r
+               if (e && e.nodeName.toLowerCase() != 'body') {\r
+                       t = e.scrollTop;\r
+                       l = e.scrollLeft;\r
+                       w = e.scrollWidth;\r
+                       h = e.scrollHeight;\r
+               } else  {\r
+                       if (document.documentElement) {\r
+                               t = document.documentElement.scrollTop;\r
+                               l = document.documentElement.scrollLeft;\r
+                               w = document.documentElement.scrollWidth;\r
+                               h = document.documentElement.scrollHeight;\r
+                       } else if (document.body) {\r
+                               t = document.body.scrollTop;\r
+                               l = document.body.scrollLeft;\r
+                               w = document.body.scrollWidth;\r
+                               h = document.body.scrollHeight;\r
+                       }\r
+                       if (typeof pageYOffset != 'undefined') {\r
+                               t = pageYOffset;\r
+                               l = pageXOffset;\r
+                       }\r
+                       iw = self.innerWidth||document.documentElement.clientWidth||document.body.clientWidth||0;\r
+                       ih = self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight||0;\r
+               }\r
+               return { t: t, l: l, w: w, h: h, iw: iw, ih: ih };\r
+       },\r
+       getMargins : function(e, toInteger)\r
+       {\r
+               var t = jQuery.curCSS(e,'marginTop') || '';\r
+               var r = jQuery.curCSS(e,'marginRight') || '';\r
+               var b = jQuery.curCSS(e,'marginBottom') || '';\r
+               var l = jQuery.curCSS(e,'marginLeft') || '';\r
+               if (toInteger)\r
+                       return {\r
+                               t: parseInt(t, 10)||0,\r
+                               r: parseInt(r, 10)||0,\r
+                               b: parseInt(b, 10)||0,\r
+                               l: parseInt(l, 10)\r
+                       };\r
+               else\r
+                       return {t: t, r: r,     b: b, l: l};\r
+       },\r
+       getPadding : function(e, toInteger)\r
+       {\r
+               var t = jQuery.curCSS(e,'paddingTop') || '';\r
+               var r = jQuery.curCSS(e,'paddingRight') || '';\r
+               var b = jQuery.curCSS(e,'paddingBottom') || '';\r
+               var l = jQuery.curCSS(e,'paddingLeft') || '';\r
+               if (toInteger)\r
+                       return {\r
+                               t: parseInt(t, 10)||0,\r
+                               r: parseInt(r, 10)||0,\r
+                               b: parseInt(b, 10)||0,\r
+                               l: parseInt(l, 10)\r
+                       };\r
+               else\r
+                       return {t: t, r: r,     b: b, l: l};\r
+       },\r
+       getBorder : function(e, toInteger)\r
+       {\r
+               var t = jQuery.curCSS(e,'borderTopWidth') || '';\r
+               var r = jQuery.curCSS(e,'borderRightWidth') || '';\r
+               var b = jQuery.curCSS(e,'borderBottomWidth') || '';\r
+               var l = jQuery.curCSS(e,'borderLeftWidth') || '';\r
+               if (toInteger)\r
+                       return {\r
+                               t: parseInt(t, 10)||0,\r
+                               r: parseInt(r, 10)||0,\r
+                               b: parseInt(b, 10)||0,\r
+                               l: parseInt(l, 10)||0\r
+                       };\r
+               else\r
+                       return {t: t, r: r,     b: b, l: l};\r
+       },\r
+       traverseDOM : function(nodeEl, func)\r
+       {\r
+               func(nodeEl);\r
+               nodeEl = nodeEl.firstChild;\r
+               while(nodeEl){\r
+                       EYE.traverseDOM(nodeEl, func);\r
+                       nodeEl = nodeEl.nextSibling;\r
+               }\r
+       },\r
+       getInnerWidth :  function(el, scroll) {\r
+               var offsetW = el.offsetWidth;\r
+               return scroll ? Math.max(el.scrollWidth,offsetW) - offsetW + el.clientWidth:el.clientWidth;\r
+       },\r
+       getInnerHeight : function(el, scroll) {\r
+               var offsetH = el.offsetHeight;\r
+               return scroll ? Math.max(el.scrollHeight,offsetH) - offsetH + el.clientHeight:el.clientHeight;\r
+       },\r
+       getExtraWidth : function(el) {\r
+               if($.boxModel)\r
+                       return (parseInt($.curCSS(el, 'paddingLeft'))||0)\r
+                               + (parseInt($.curCSS(el, 'paddingRight'))||0)\r
+                               + (parseInt($.curCSS(el, 'borderLeftWidth'))||0)\r
+                               + (parseInt($.curCSS(el, 'borderRightWidth'))||0);\r
+               return 0;\r
+       },\r
+       getExtraHeight : function(el) {\r
+               if($.boxModel)\r
+                       return (parseInt($.curCSS(el, 'paddingTop'))||0)\r
+                               + (parseInt($.curCSS(el, 'paddingBottom'))||0)\r
+                               + (parseInt($.curCSS(el, 'borderTopWidth'))||0)\r
+                               + (parseInt($.curCSS(el, 'borderBottomWidth'))||0);\r
+               return 0;\r
+       },\r
+       isChildOf: function(parentEl, el, container) {\r
+               if (parentEl == el) {\r
+                       return true;\r
+               }\r
+               if (!el || !el.nodeType || el.nodeType != 1) {\r
+                       return false;\r
+               }\r
+               if (parentEl.contains && !$.browser.safari) {\r
+                       return parentEl.contains(el);\r
+               }\r
+               if ( parentEl.compareDocumentPosition ) {\r
+                       return !!(parentEl.compareDocumentPosition(el) & 16);\r
+               }\r
+               var prEl = el.parentNode;\r
+               while(prEl && prEl != container) {\r
+                       if (prEl == parentEl)\r
+                               return true;\r
+                       prEl = prEl.parentNode;\r
+               }\r
+               return false;\r
+       },\r
+       centerEl : function(el, axis)\r
+       {\r
+               var clientScroll = EYE.getScroll();\r
+               var size = EYE.getSize(el);\r
+               if (!axis || axis == 'vertically')\r
+                       $(el).css(\r
+                               {\r
+                                       top: clientScroll.t + ((Math.min(clientScroll.h,clientScroll.ih) - size.hb)/2) + 'px'\r
+                               }\r
+                       );\r
+               if (!axis || axis == 'horizontally')\r
+                       $(el).css(\r
+                               {\r
+                                       left: clientScroll.l + ((Math.min(clientScroll.w,clientScroll.iw) - size.wb)/2) + 'px'\r
+                               }\r
+                       );\r
+       }\r
+});\r
+if (!$.easing.easeout) {\r
+       $.easing.easeout = function(p, n, firstNum, delta, duration) {\r
+               return -delta * ((n=n/duration-1)*n*n*n - 1) + firstNum;\r
+       };\r
+}\r
+       \r
+})(jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/mvClipEdit.js b/js2/mwEmbed/libClipEdit/mvClipEdit.js
new file mode 100644 (file)
index 0000000..deea8e8
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+       hanndles clip edit controls 
+       'inoutpoints':0,        //should let you set the in and out points of clip
+       'panzoom':0,             //should allow setting keyframes and tweenning modes                   
+       'overlays':0,            //should allow setting "locked to clip" overlay tracks 
+       'audio':0                       //should allow controlling the audio volume (with keyframes) 
+*/
+//set gMsg object:
+loadGM( { 
+       "mv_crop":"Crop Image",
+       "mv_apply_crop":"Apply Crop to Image",
+       "mv_reset_crop":"Rest Crop",
+       "mv_insert_image_page":"Insert Into page",
+       "mv_insert_into_sequence": "Insert Into Sequence",
+       "mv_preview_insert":"Preview Insert",
+       "mv_cancel_image_insert": "Cancel Insert",
+       
+       "sc_fileopts":"Clip Detail Edit",
+       "sc_inoutpoints":"Set In-Out points",   
+       "sc_overlays":"Overlays",
+       "sc_audio":"Audio Control",
+       "sc_duration":"Duration",               
+               
+       "mv_template_properties":"Template Properties",
+       "mv_custom_title":"Custom Title",
+       "mv_edit_properties":"Edit Properties",
+       "mv_other_properties":"Other Properties",
+       "mv_resource_page" : "Resource Page:",
+       
+       "mv_set_in_out_points": "Set in-out points",
+       "mv_start_time": "Start Time",
+       "mv_end_time": "End Time",
+       "mv_preview_inout": "Preview/Play In-out points"
+});
+
+var default_clipedit_values = {
+       'rObj': null,            // the resource object
+       'clip_disp_ct':null,//target clip disp
+       'control_ct':null,       //control container
+       'media_type': null, //media type
+       'parent_ct': null,       //parent container
+                       
+       'p_rsdObj': null,       //parent remote search object
+       'p_seqObj': null,        //parent sequence Object
+       
+       'controlActionsCb' : null, //the object that configures control Action callbacks
+       
+       'edit_action': null, //the requested edit action
+       'profile': 'inpage' //the given profile either "inpage" or "sequence"                                           
+}
+var mvClipEdit = function(iObj) {              
+       return this.init(iObj);
+};
+mvClipEdit.prototype = {
+       
+       selTool:null, //selected tool
+       crop: null, //the crop values
+       base_img_src:null,
+       
+       init:function( iObj){
+               //init object: 
+               for(var i in default_clipedit_values){
+                       if( iObj[i] ){   
+                               this[i] = iObj[i];
+                       }
+               }
+
+               //if media type was not supplied detect for resource if possible:
+               //@@todo more advanced detection.                
+               if(!this.media_type && this.rObj && this.rObj.type ){
+                       if( this.rObj.type.indexOf("image/") === 0){
+                               this.media_type = 'image';
+                       }else if( this.rObj.type.indexOf("video/") === 0){
+                               this.media_type = 'video';
+                       }else if( this.rObj.type.indexOf("text/") === 0){
+                               this.media_type = 'template';
+                       }
+               }                               
+               
+               //display control:
+               if(this.profile == 'sequence'){                 
+                       this.doEditTypesMenu();
+                       this.doDisplayEdit();
+               }else{                          
+                       //check the media_type:
+                       js_log('mvClipEdit:: media type:' + this.media_type + ' base width: ' + this.rObj.width + ' bh: ' + this.rObj.height);          
+                       //could seperate out into media Types objects for now just call method
+                       if(this.media_type == 'image'){
+                               this.setUpImageCtrl();
+                       }else if(this.media_type=='video'){
+                               this.setUpVideoCtrl();
+                       }
+               }
+       },
+       
+       //master edit types object:
+       //maybe we should refactor these into their own classes  
+       //more refactor each media type should be its own class inheriting the shared baseEditType object
+       edit_types:{            
+               'duration':{                    
+                       'media':['image','template'],
+                       'doEdit':function( _this, target ){
+                               //(_this is a smilClip instance)
+                               //do clock mouse scroll duration editor
+                               $j(target).html(                                                                        
+                                               '<label for="ce_dur">Duration: </label>' +                                              
+                                               '<input name="ce_dur" tabindex="1" maxlength="11" value="'+
+                                                       seconds2npt( _this.rObj.getDuration() )+
+                                                       '" size="10"/>'+                                                        
+                                       '</div>'        
+                               ).children("input[name='ce_dur']").change(function(){
+                                        js_log("update duration:" + $j(this).val() );
+                                        //update the parent sequence object: 
+                                        _this.rObj.dur = smilParseTime( $j(this).val() );
+                                        //update the playlist: 
+                                        _this.p_seqObj.do_refresh_timeline( true );                                     
+                               });
+                               
+                       }                       
+               },
+               'inoutpoints':{
+                       'media':['video'],
+                       'doEdit':function( _this, target ){                                                             
+                               //do clock mouse scroll duration editor
+                               var end_ntp = ( _this.rObj.embed.end_ntp) ? _this.rObj.embed.end_ntp : _this.rObj.embed.getDuration();
+                               if(!end_ntp)
+                                       end_ntp = seconds2npt( _this.rObj.dur );
+                                       
+                               var start_ntp = (_this.rObj.embed.start_ntp) ? _this.rObj.embed.start_ntp : seconds2npt( 0 );
+                               if(!start_ntp)
+                                       seconds2npt( 0 );
+                                       
+                               $j(target).html(
+                                       _this.getSetInOutHtml({
+                                               'start_ntp'     : start_ntp, 
+                                               'end_ntp'       : end_ntp
+                                       })              
+                               );
+                               _this.setInOutBindings();
+                       }               
+               },
+               'fileopts':{
+                       'media':['image','video','template'],
+                       'doEdit':function(_this, target ){                                                      
+                               //if media type is template we have to query to get its URI to get its paramaters
+                               if(_this.media_type == 'template' && !_this.rObj.tVars){                
+                                       mv_set_loading('#sub_cliplib_ic');
+                                       var reqObj ={   'action':'query',
+                                                                       'prop':'revisions',
+                                                                       'titles': _this.rObj.uri,
+                                                                       'rvprop':'content' 
+                                                               };
+                                       //get the interface uri from the plObject
+                                       var api_url = _this.p_seqObj.plObj.interface_url; 
+                                       //first check                                    
+                                       do_api_req( {
+                                               'data':reqObj,
+                                               'url':api_url
+                                               }, function(data){
+                                                       if(typeof data.query.pages == 'undefined')
+                                                               return _this.doEditOpts(target);
+                                                       for(var i in data.query.pages){
+                                                               var page = data.query.pages[i];
+                                                               if(!page['revisions'] || !page['revisions'][0]['*']){
+                                                                       return _this.doEditOpts(target);        
+                                                               }else{
+                                                                       var template_rev = page['revisions'][0]['*'];
+                                                               }
+                                                       }                                               
+                                                       
+                                                       //do a regular ex to get the ~likely~ template values 
+                                                       //(of course this sucks)
+                                                       //but maybe this will make its way into the api sometime soon to support wysiwyg type editors
+                                                       //idealy it would expose a good deal of info about the template params
+                                                       js_log('matching against: ' + template_rev);
+                                                       var tempVars = template_rev.match(/\{\{\{([^\}]*)\}\}\}/gi);
+                                                       //clean up results:
+                                                       _this.rObj.tVars = new Array();
+                                                       for(var i=0; i < tempVars.length; i++){
+                                                               var tvar = tempVars[i].replace('{{{','').replace('}}}','');
+                                                               //strip anything after a | 
+                                                               if(tvar.indexOf('|') != -1){
+                                                                       tvar = tvar.substr(0, tvar.indexOf('|'));
+                                                               }                                                                                                               
+                                                               //check for duplicates: 
+                                                               var do_add=true;
+                                                               for(var j=0; j < _this.rObj.tVars.length; j++){
+                                                                       js_log('checking: ' + _this.rObj.tVars[j] + ' against:' + tvar);
+                                                                       if( _this.rObj.tVars[j] == tvar)
+                                                                               do_add=false;
+                                                               }
+                                                               //add the template vars to the output obj
+                                                               if(do_add)
+                                                                       _this.rObj.tVars.push( tvar );
+                                                       }                                       
+                                                       _this.doEditOpts(target);
+                                               }
+                                       );
+                               }else{
+                                       _this.doEditOpts(target);
+                               }
+                       }               
+               },
+               'overlays':{                    
+                       'media':['image','video'],
+                       'doEdit':function(_this, target){
+                               //do clock mouse scroll duration editor
+                               $j(target).html('<h3>Current Overlays:</h3>Add,Remove,Modify');
+                       }       
+               },
+               'audio':{
+                       'media':['image','video', 'template'],
+                       'doEdit':function(_this, target){
+                               //do clock mouse scroll duration editor
+                               $j(target).html('<h3>Audio Volume:</h3>');
+                       }       
+               }               
+       },      
+       doEditOpts:function(target){
+               var _this = this;
+               //add html for rObj resource:
+               var o=  '<table>' +
+                               '<tr>' +
+                                       '<td colspan="2"><b>'+gM('mv_edit_properties')+'</b></td>'+
+                               '</tr>'+
+                               '<tr>'+
+                                       '<td>' + 
+                                               gM('mv_custom_title') + 
+                                       '</td>'+
+                                       '<td><input type="text" size="15" maxwidth="255" value="';
+                                               if(_this.rObj.title != null)
+                                                       o+=_this.rObj.title;
+                                               o+='">'+
+                                       '</td>'+
+                               '</tr>';                
+               if( _this.rObj.tVars){
+                       var existing_p = _this.rObj.params;
+                       var testing_a = _this.rObj.tVars;
+                       //debugger;
+                       o+= '<tr>'+
+                                       '<td colspan="2"><b>' + gM('mv_template_properties') + '</b></td>'+
+                               '</tr>';
+                       for(var i =0; i < _this.rObj.tVars.length ; i++){
+                               o+='<tr>'+
+                                       '<td>' + 
+                                               _this.rObj.tVars[i] + 
+                                       '</td>' +
+                                       '<td><input name="'+_this.rObj.tVars[i]+'" class="ic_tparam" type="text" size="15" maxwidth="255" value="';
+                               if(_this.rObj.params[ _this.rObj.tVars[i] ]){
+                                       o+= _this.rObj.params[ _this.rObj.tVars[i] ];
+                               }
+                               o+='">'+ 
+                                       '</td>'+
+                               '</tr>';                
+                       }
+               }               
+               if(typeof wgArticlePath != 'undefined' ){
+                       var res_src = wgArticlePath.replace(/\$1/, _this.rObj.uri );
+                       var res_title = _this.rObj.uri;
+               }else{
+                       //var res_page = 
+                       var res_src = _this.rObj.src;                                                           
+                       var res_title = parseUri(_this.rObj.src).file;                  
+               } 
+               o+=     '<tr>'+
+                                       '<td colspan="2"><b>'+gM('mv_other_properties')+'</b></td>'+
+                               '</tr>'+
+                               '<tr>'+
+                                       '<td>' + 
+                                               gM('mv_resource_page') + 
+                                       '</td>' +
+                                       '<td><a href="' + res_src  +'" '+
+                                               ' target="new">'+
+                                                       res_title + '</a>'+
+                                       '</td>'+
+                               '</tr>';
+               o+='</table>'; 
+               
+               $j(target).html ( o );
+               
+               //add update bindings
+               $j(target + ' .ic_tparam').change(function(){
+                       js_log("updated tparam::" + $j(this).attr("name"));
+                       //update param value: 
+                       _this.rObj.params[ $j(this).attr("name") ] = $j(this).val();
+                       //re-parse & update template
+                       var template_wiki_text = '{{' + _this.rObj.uri;
+                       for(var i =0;i < _this.rObj.tVars.length ; i++){        
+                               
+                               template_wiki_text += "\n|"+_this.rObj.tVars[i] + ' = ' +  _this.rObj.params[ _this.rObj.tVars[i] ]  ;
+                       }               
+                       template_wiki_text += "\n}}";                           
+                       var reqObj ={   
+                                       'action':'parse',
+                                       'title' : _this.p_seqObj.plObj.mTitle,
+                                       'text'  :       template_wiki_text                                                              
+                       };
+                       $j( _this.rObj.embed ).html( mv_get_loading_img() );
+                       
+                       var api_url = _this.p_seqObj.plObj.interface_url; 
+                       do_api_req({
+                               'data':reqObj,
+                               'url':api_url
+                       },function(data){
+                               if(data.parse.text['*']){
+                                       //update the target
+                                       $j( _this.rObj.embed ).html( data.parse.text['*'] );
+                               }
+                       })
+               })
+                               
+               //update doFocusBindings
+               if( _this.p_seqObj )
+                       _this.p_seqObj.doFocusBindings();
+       },
+       doEditTypesMenu:function(){
+               var _this = this;
+               //add in subMenus if set
+               //check for submenu and add to item container           
+               var o='';               
+               var tabc ='';                                   
+               o+= '<div id="mv_submenu_clipedit">';
+               o+='<ul>';               
+               var first_tab = false;
+               $j.each(this.edit_types, function(sInx, editType){                      
+                       //check if the given editType is valid for our given media type
+                       var include = false;
+                       for(var i =0; i < editType.media.length;i++){
+                               if( editType.media[i] == _this.media_type){
+                                       include = true; 
+                                       if(!first_tab)
+                                               first_tab = sInx;
+                               }
+                       }
+                       if(include){                            
+                               o+=     '<li>'+ 
+                                               '<a id="mv_smi_'+sInx+'" href="#sc_' + sInx + '">' + gM('sc_' + sInx ) + '</a>'+
+                                       '</li>';                                                                                                                        
+                               tabc += '<div id="sc_' + sInx + '" style="overflow:auto;" ></div>';                                                                                                                                                                                                     
+                       }        
+               });
+               o+= '</ul>' + tabc;
+               o+= '</div>';
+               //add sub menu container with menu html:                
+               $j('#'+this.control_ct).html( o ) ;                     
+               //set up bindings:       
+               $j('#mv_submenu_clipedit').tabs({
+                       selected: 0,
+                       select: function(event, ui) {                                                                   
+                               _this.doDisplayEdit( $j(ui.tab).attr('id').replace('mv_smi_', '') );
+                       }                               
+               }).addClass('ui-tabs-vertical ui-helper-clearfix');
+               //close left: 
+               $j("#mv_submenu_clipedit li").removeClass('ui-corner-top').addClass('ui-corner-left');          
+               //update the default edit display: 
+               _this.doDisplayEdit( first_tab );
+       },
+       doDisplayEdit:function( edit_type ){
+               if(!edit_type)
+                       return false;
+               js_log('doDisplayEdit: ' + edit_type );                 
+               
+               //do edit interface for that edit type: 
+               if( this.edit_types[ edit_type ].doEdit )
+                       this.edit_types[ edit_type ].doEdit(this, '#sc_'+edit_type );
+       },
+       setUpVideoCtrl:function(){
+               js_log('setUpVideoCtrl:f');
+               var _this = this;
+               var eb = $j('#embed_vid').get(0);
+               //turn on preview to avoid onDone actions
+               eb.preview_mode = true;
+               $j('#'+this.control_ct).html('<h3>Edit Video Tools:</h3>');
+               if( eb.supportsURLTimeEncoding() ){                     
+                       $j('#'+this.control_ct).append( 
+                               _this.getSetInOutHtml({
+                                       'start_ntp'     : eb.start_ntp, 
+                                       'end_ntp'       : eb.end_ntp   
+                               }) 
+                       );
+                       _this.setInOutBindings();                       
+               }
+               $j('#'+this.control_ct).append( _this.getInsertDescHtml() );
+               
+               if( _this.p_rsdObj && _this.p_rsdObj.import_url_mode == 'none'){                        
+                       $j('#'+this.control_ct).append(  gM('no_import_by_url') + '<br>' +                       
+                               '<a href="#" class="mv_cancel_img_edit" title="' + gM('mv_cancel_image_insert')+'">' + gM('mv_cancel_image_insert') + '</a> ' );
+               }else{                                                                          
+                       this.updateInsertControlActions();
+               }                                                               
+       },
+       setInOutBindings:function(){
+               var _this = this;
+               
+               var start_sec = npt2seconds($j('#'+this.control_ct + ' .startInOut').val() );
+               var end_sec   = npt2seconds($j('#'+this.control_ct + ' .endInOut').val() );
+               
+               //if we don't have 0 as start then assume we are in a range request and give some buffer area:            
+               var min_slider =  (start_sec - 60 < 0 ) ? 0 : start_sec - 60;
+               if(min_slider!=0){
+                       var max_slider =  end_sec+60;
+               }else{
+                       max_slider = end_sec;
+               }               
+               
+               $j('#'+this.control_ct + ' .inOutSlider').slider({
+                       range: true,
+                       min: min_slider,
+                       max: max_slider,
+                       values: [start_sec, end_sec],
+                       slide: function(event, ui) {
+                               js_log(" vals:"+  seconds2npt( ui.values[0] ) + ' : ' + seconds2npt( ui.values[1]) );
+                               $j('#'+_this.control_ct + ' .startInOut').val( seconds2npt( ui.values[0] ) );
+                               $j('#'+_this.control_ct + ' .endInOut').val( seconds2npt( ui.values[1] ) );
+                       },
+                       change:function(event, ui){
+                               do_video_time_update( seconds2npt( ui.values[0]), seconds2npt( ui.values[1] ) );
+                       }                       
+               });
+               
+               //preview button:
+               $j('#'+this.control_ct + ' .inOutPreviewClip').hover(
+                       function(){
+                               $j(this).addClass('ui-state-hover');
+                       },
+                       function(){
+                               $j(this).removeClass('ui-state-hover');
+                       }
+               ).click(function(){                     
+                       $j('#embed_vid').get(0).stop();
+                       $j('#embed_vid').get(0).play();
+               });       
+               //simple hover: 
+                 
+       },
+       getSetInOutHtml:function( setInt ){
+               return '<strong>' + gM('mv_set_in_out_points') + '</strong>'+
+                       '<table border="0" style="background: transparent; width:94%;height:50px;">'+
+                               '<tr>' +
+                                       '<td style="width:55px">'+
+                                               gM('mv_start_time') + 
+                                               '<input class="ui-widget-content ui-corner-all startInOut" size="9" value="' + setInt.start_ntp +'">'+
+                                       '</td>' +
+                                       '<td>' +
+                                               '<div class="inOutSlider"></div>'+
+                                       '</td>' +
+                                       '<td style="width:55px">'+
+                                               gM('mv_end_time') + 
+                                               '<input class="ui-widget-content ui-corner-all endInOut" size="9" value="'+ setInt.end_ntp +'">'+
+                                       '</td>' +
+                               '</tr>' +
+                       '</table>'+
+                       '<a href="#" class="ui-state-default ui-corner-all ui-icon_link inOutPreviewClip"><span class="ui-icon ui-icon-video"></span>'+ gM('mv_preview_inout') +'</a>';                            
+       },
+       getInsertDescHtml:function(){   
+               var o= '<h3>Inline Description</h3>'+                            
+                                       '<textarea style="width:95%" id="mv_inline_img_desc" rows="5" cols="30">';                              
+               if( this.p_rsdObj ){
+                       //if we have a parent remote search driver let it parse the inline description          
+                       o+= this.rObj.pSobj.getInlineDescWiki( this.rObj );
+               }
+               o+='</textarea><br>';           
+               //js_log('getInsertDescHtml: ' + o );
+               return o;
+       },
+       updateInsertControlActions:function(){
+               var _this = this;               
+               var b_target =   _this.p_rsdObj.target_container + '~ .ui-dialog-buttonpane';
+               //empty the ui-dialog-buttonpane bar:
+               $j(b_target).empty();
+               for(var cbType in _this.controlActionsCb){
+                       switch(cbType){
+                               case 'insert_seq':
+                                       $j(b_target).append( $j.btnHtml(gM('mv_insert_into_sequence'), 'mv_insert_sequence', 'check' ) + ' ' )
+                                               .children('.mv_insert_sequence')
+                                               .btnBind()
+                                               .click(function(){
+                                                       _this.applyEdit();                                                      
+                                                       _this.controlActionsCb['insert_seq'](  _this.rObj );            
+                                               });
+                               break;                          
+                               case 'insert': 
+                                       $j(b_target).append(  $j.btnHtml(gM('mv_insert_image_page'), 'mv_insert_image_page', 'check' ) + ' ' )
+                                               .children('.mv_insert_image_page')
+                                               .btnBind()
+                                               .click(function(){
+                                                       _this.applyEdit();
+                                                       _this.controlActionsCb['insert'](  _this.rObj );                                                                                                                                                
+                                               }).show('slow');                                        
+                               break;
+                               case 'preview':
+                                       $j(b_target).append( $j.btnHtml( gM('mv_preview_insert'), 'mv_preview_insert', 'refresh') + ' ' )
+                                               .children('.mv_preview_insert')
+                                               .btnBind()
+                                               .click(function(){      
+                                                       _this.applyEdit();
+                                                       _this.controlActionsCb['preview'](  _this.rObj );
+                                               }).show('slow');                                        
+                               break;          
+                               case 'cancel':
+                                       $j(b_target).append( $j.btnHtml( gM('mv_cancel_image_insert'), 'mv_cancel_img_edit', 'close') + ' ')
+                                               .children('.mv_cancel_img_edit')
+                                               .btnBind()
+                                               .click(function(){
+                                                       //no cancel action; 
+                                                       _this.controlActionsCb['cancel'](  _this.rObj );                                                        
+                                               }).show('slow');                                        
+                               break;
+                       }                               
+               }               
+       },
+       applyEdit:function(){
+               var _this = this;
+               js_log('applyEdit::' + this.media_type);
+               if(this.media_type == 'image'){
+                       this.applyCrop();
+               }else if(this.media_type == 'video'){
+                       this.applyVideoAdj();
+               }
+               //copy over the desc text to the resource object
+               _this.rObj['inlineDesc']= $j('#mv_inline_img_desc').val();
+       },      
+       setUpImageCtrl:function(){
+               var _this = this;               
+               //by default apply Crop tool 
+               $j('#'+this.control_ct).html(
+                       '<h3>Edit tools</h3>' +                          
+                                       '<div class="mv_edit_button mv_crop_button_base" id="mv_crop_button" alt="crop" title="'+gM('mv_crop')+'"/>'+
+                                       '<a href="#" class="mv_crop_msg">' + gM('mv_crop') + '</a> '+
+                                       '<span style="display:none" class="mv_crop_msg_load">' + gM('loading_txt') + '</span> '+
+                                       '<a href="#" style="display:none" class="mv_apply_crop">' + gM('mv_apply_crop') + '</a> '+
+                                       '<a href="#" style="display:none" class="mv_rest_crop">' + gM('mv_reset_crop') + '</a> '+
+                               '<hr style="clear:both"/><br>'+                         
+                       '<span style="float:left;">Layout:</span>' +
+                               '<input type="radio" name="mv_layout" id="mv_layout_left" style="float:left"><div id="mv_layout_left_img" title="'+gM('mv_layout_left')+'"/>'+
+                               '<input type="radio" name="mv_layout" id="mv_layout_right" style="float:left"><div id="mv_layout_right_img" title="'+gM('mv_layout_left')+'"/>'+        
+                       '<hr style="clear:both" /><br>' +                                                                        
+                               _this.getInsertDescHtml()                                                       
+               );
+               //add the actions to the 'button bar'
+               _this.updateInsertControlActions()      
+               
+               /*scale: 
+                '<div class="mv_edit_button mv_scale_button_base" id="mv_scale_button" alt="crop" title="'+gM('mv_scale')+'"></div>'+                          
+                               '<a href="#" class="mv_scale_msg">' + gM('mv_scale') + '</a><br>'+
+                               '<a href="#" style="display:none" class="mv_apply_scale">' + gM('mv_apply_scale') + '</a> '+
+                               '<a href="#" style="display:none" class="mv_rest_scale">' + gM('mv_reset_scale') + '</a><br> '+
+               
+               */
+               //add bindings:
+               
+               //make sure the default is reflected:
+               if( ! _this.rObj.layout )
+                       _this.rObj.layout = 'right';
+               $j('#mv_layout_' + _this.rObj.layout)[0].checked = true;
+               
+               //left radio click 
+               $j('#mv_layout_left,#mv_layout_left_img').click(function(){
+                       $j('#mv_layout_right')[0].checked = false;
+                       $j('#mv_layout_left')[0].checked = true;
+                       _this.rObj.layout = 'left';
+               });
+               //right radio click
+               $j('#mv_layout_right,#mv_layout_right_img').click(function(){
+                       $j('#mv_layout_left')[0].checked = false;
+                       $j('#mv_layout_right')[0].checked = true;
+                       _this.rObj.layout = 'right';
+               });
+               $j('#mv_crop_button,.mv_crop_msg,.mv_apply_crop').click(function(){
+                       js_log('click:mv_crop_button: base width: ' + _this.rObj.width + ' bh: ' + _this.rObj.height);
+                       if($j('#mv_crop_button').hasClass('mv_crop_button_selected')){                          
+                               _this.applyCrop();
+                       }else{
+                               js_log('click:turn on');
+                               _this.enableCrop();
+                       }
+               });             
+               $j('.mv_rest_crop').click(function(){   
+                       $j('.mv_apply_crop,.mv_rest_crop').hide();
+                       $j('.mv_crop_msg').show();
+                       $j('#mv_crop_button').removeClass('mv_crop_button_selected').addClass('mv_crop_button_base').attr('title',gM('mv_crop'));
+                       _this.rObj.crop=null;
+                       $j('#' + _this.clip_disp_ct ).empty().html(
+                               '<img src="' + _this.rObj.edit_url + '" id="rsd_edit_img">'
+                       );
+               });                             
+       },
+       applyVideoAdj:function(){               
+               js_log('applyVideoAdj::');      
+               
+               //be sure to "stop the video (some plugins can't have DOM elements on top of them) 
+               $j('#embed_vid').get(0).stop(); 
+               
+               //update video related keys:            
+               ;
+               this.rObj['start_time'] = $j('#'+this.control_ct + ' .startInOut').val();
+               this.rObj['end_time']   = $j('#'+this.control_ct + ' .endInOut').val() ; 
+               
+               //do the local video adjust
+               if(typeof this.rObj.pSobj['applyVideoAdj'] != 'undefined'){                     
+                       this.rObj.pSobj.applyVideoAdj( this.rObj );
+               }
+       },
+       applyCrop:function(){
+               var _this = this;
+               $j('.mv_apply_crop').hide();
+               $j('.mv_crop_msg').show();
+               $j('#mv_crop_button').removeClass('mv_crop_button_selected').addClass('mv_crop_button_base').attr('title',gM('mv_crop'));
+               js_log( 'click:turn off' );
+               var cat = _this.rObj;           
+               if(_this.rObj.crop){                    
+                       //empty out and display croped:
+                       $j('#'+_this.clip_disp_ct ).empty().html(
+                               '<div id="mv_cropcotainer" style="overflow:hidden;position:absolute;'+
+                                       'width:' + _this.rObj.crop.w + 'px;'+
+                                       'height:' + _this.rObj.crop.h + 'px;">'+
+                                       '<div id="mv_crop_img" style="position:absolute;'+
+                                               'top:-' + _this.rObj.crop.y +'px;'+
+                                               'left:-' + _this.rObj.crop.x + 'px;">'+
+                                               '<img src="' + _this.rObj.edit_url  + '">'+
+                                       '</div>'+
+                               '</div>'                                                
+                       );                      
+               }
+               return true;
+       },
+       //right now enableCrop loads "just in time" 
+       //@@todo we really need an "auto loader" type system. 
+       enableCrop:function(){
+               var _this = this;
+               $j('.mv_crop_msg').hide();
+               $j('.mv_crop_msg_load').show();
+               var doEnableCrop = function(){  
+                       $j('.mv_crop_msg_load').hide();
+                       $j('.mv_rest_crop,.mv_apply_crop').show();                              
+                       $j('#mv_crop_button').removeClass('mv_crop_button_base').addClass('mv_crop_button_selected').attr('title',gM('mv_crop_done'));                          
+                       $j('#' + _this.clip_disp_ct + ' img').Jcrop({
+                                onSelect: function(c){
+                                        js_log('on select:' + c.x +','+ c.y+','+ c.x2+','+ c.y2+','+ c.w+','+ c.h);
+                                        _this.rObj.crop = c;
+                                },
+                                onChange: function(c){                                                 
+                                }                                              
+                       });                     
+                       //temporary hack (@@todo need to debug why rsd_res_item gets moved )
+                       $j('#clip_edit_disp .rsd_res_item').css({
+                               'top':'0px', 
+                               'left':'0px'
+                       });                     
+               }                       
+               //load the jcrop library if needed:
+               mvJsLoader.doLoad([
+                       '$j.Jcrop'
+               ],function(){
+                       doEnableCrop();
+               });                                     
+       }
+}
+
+// mv_lock_vid_updates defined in mv_stream.js (we need to do some more refactoring )
+if(typeof mv_lock_vid_updates == 'undefined')
+       mv_lock_vid_updates= false;
+
+function add_adjust_hooks(mvd_id, adj_callback){
+       /*myClipEdit = new mvClipEdit({
+               'control_ct': '#mvd_form_'+mvd_id
+       });
+       $j('#mvd_form_'+mvd_id).html(
+               mvClipEdit.getSetInOutHtml({
+                       'start_ntp'     :  $j('#mv_start_hr_' + mvd_id).val(), 
+                       'end_ntp'       :  $j('#mv_end_hr_' + mvd_id).val() 
+               })              
+       );
+       mvClipEdit.setInOutBindings();*/
+       
+       var start_sec = npt2seconds($j('#mv_start_hr_' + mvd_id).val() );
+       var end_sec   = npt2seconds($j('#mv_end_hr_' + mvd_id).val()  );
+               
+       //if we don't have 0 as start then assume we are in a range request and give some buffer area:            
+       var min_slider =  (start_sec - 60 < 0 ) ? 0 : start_sec - 60;
+       if(min_slider!=0){
+               var max_slider =  end_sec+60;
+       }else{
+               max_slider = end_sec;
+       }               
+       //pre-destroy just in case:
+       $j('#mvd_form_' + mvd_id + ' .inOutSlider').slider( 'destroy' ).slider({
+               range: true,
+               min: min_slider,
+               max: max_slider,
+               values: [start_sec, end_sec],
+               slide: function(event, ui) {
+                       js_log(" vals:"+  seconds2npt( ui.values[0] ) + ' : ' + seconds2npt( ui.values[1]) );
+                       $j('#mv_start_hr_' + mvd_id).val( seconds2npt( ui.values[0] ) );
+                       $j('#mv_end_hr_' + mvd_id).val( seconds2npt( ui.values[1] ) );
+               },
+               change:function(event, ui){
+                       do_video_time_update( seconds2npt( ui.values[0]), seconds2npt( ui.values[1] ) );
+               }                       
+       });
+       $j('.mv_adj_hr').change(function(){
+               //preserve track duration for nav and seq:
+               //ie seems to crash so no interface updates for IE for the time being
+               if(!$j.browser.msie){
+                       if(mvd_id=='nav'||mvd_id=='seq'){
+                               add_adjust_hooks(mvd_id); // (no adj_callback)
+                       }else{
+                               add_adjust_hooks(mvd_id)
+                       }
+               }
+               //update the video time for onChange
+               do_video_time_update( $j('#mv_start_hr_'+mvd_id).val(), $j('#mv_end_hr_'+mvd_id).val() );
+       });
+}
+
+function do_video_time_update(start_time, end_time, mvd_id)    {
+       js_log('do_video_time_update: ' +start_time +' '+ end_time);
+       
+       if(mv_lock_vid_updates==false){
+               //update the vid title:
+               $j('#mv_videoPlayerTime').html( start_time + ' to ' + end_time );
+               var ebvid = $j('#embed_vid').get(0);
+               if( ebvid ){
+                       if(ebvid.isPaused())
+                               ebvid.stop();
+                       ebvid.updateVideoTime(start_time, end_time);
+                       js_log('update thumb: '+ start_time);           
+                       ebvid.updateThumbTimeNTP( start_time );
+               }
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-editor/editor.js b/js2/mwEmbed/libClipEdit/pixastic-editor/editor.js
new file mode 100644 (file)
index 0000000..6edba1a
--- /dev/null
@@ -0,0 +1,968 @@
+\r
+var PixasticEditor = (function () {\r
+\r
+       var $frame;     // iframe container element\r
+       var $editor;    // editor container element\r
+\r
+       // various UI structures\r
+       var accordionElements = {};\r
+       var tabElements = {};\r
+       var activeTabId;\r
+       var $activeTabContent;\r
+\r
+       var isRunning = false;\r
+\r
+       var $loadingScreen;\r
+\r
+       var $imageCanvas;       // the canvas holding the current state of the image\r
+       var $displayCanvas;     // the canvas element displayed on the screen, also the working canvas (where preview operations are performed)\r
+       var imageCtx;\r
+\r
+       var imageWidth = 0;     // dimensions of the current image state\r
+       var imageHeight = 0;\r
+\r
+       var undoImages = [];    // canvas elements holding previous image states\r
+       var undoLevels = 10;\r
+\r
+       var doc;\r
+\r
+       var $;\r
+\r
+       // test for valid file formats for toDataURL()\r
+       // we do that by calling it with each of the mime types in testFormats\r
+       // and then doing string checking on the resulting data: URI to see if it succeeded\r
+       var saveFormats = [];\r
+       var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]];\r
+       var testCanvas = document.createElement("canvas");\r
+       if (testCanvas.toDataURL) {\r
+               testCanvas.width = testCanvas.height = 1;\r
+               for (var i=0;i<testFormats.length;i++) {\r
+                       var data = testCanvas.toDataURL(testFormats[i][0]);\r
+                       if (data.substr(0, 5 + testFormats[i][0].length) == "data:" + testFormats[i][0])\r
+                               saveFormats.push({mime:testFormats[i][0], name:testFormats[i][1]});\r
+               }\r
+       }\r
+\r
+\r
+       // pops up an error dialog with the specified text (errTxt),\r
+       // if no context is provided, the name of the calling function is used.\r
+       // The final message is returned for easy throwing of actual errors\r
+       function errorDialog(errTxt, context) {\r
+               if (!($editor && $editor.get && $editor.get(0)))\r
+                       throw new Error("errorDialog(): $editor doesn't exist");\r
+\r
+               var caller = errorDialog.caller.toString().split(" ")[1];\r
+               caller = caller.substring(0, caller.indexOf("("));\r
+               context = context || caller;\r
+               errTxt = context + "(): " + errTxt;\r
+               var dialog = $j("<div></div>", doc)\r
+                       .addClass("error-dialog")\r
+                       .attr("title", "Oops!")\r
+                       .html(errTxt)\r
+                       .dialog();\r
+               // the dialog is added outside the Pixastic container, so get it back in.\r
+               var dialogParent = $j(dialog.get(0).parentNode);\r
+               dialogParent.appendTo($editor);\r
+\r
+               return errTxt;\r
+       }\r
+       \r
+       function enableTab(id, refresh) {\r
+               if (id == activeTabId && !refresh)\r
+                       return;\r
+\r
+               activeTabId = id;\r
+\r
+               var activeIndex = 0;\r
+\r
+               if ($activeTabContent) {\r
+                       if ($activeTabContent.get(0)) {\r
+                               var $parent = $j($activeTabContent.get(0).parentNode);\r
+                               activeIndex = $parent.data("accordionindex");\r
+                               if ($parent.data("ondeactivate")) {\r
+                                       $parent.data("ondeactivate")();\r
+                               }\r
+                               if ($parent.data("previewCheckbox"))\r
+                                       $parent.data("previewCheckbox").attr("checked", false);\r
+                               $parent.data("uidesc").previewEnabled = false;\r
+                               if ($parent.data("uidesc").forcePreview)\r
+                                       $parent.data("uidesc").previewEnabled = true;\r
+                       }\r
+               }\r
+\r
+\r
+               for (var a in accordionElements) {\r
+                       if (accordionElements.hasOwnProperty(a)) {\r
+                               accordionElements[a].accordion("option", "animated", false);\r
+                               accordionElements[a].accordion("activate", -1);\r
+                               accordionElements[a].hide();\r
+                               tabElements[a].removeClass("active");\r
+\r
+                       }\r
+               }\r
+\r
+               accordionElements[id].accordion("option", "animated", false);\r
+               accordionElements[id].accordion("activate", refresh ? activeIndex : 0);\r
+               tabElements[id].addClass("active");\r
+               accordionElements[id].show();\r
+               accordionElements[id].accordion("option", "animated", "slide");\r
+               resetDisplayCanvas();\r
+       }\r
+\r
+       // revert to a previous image state\r
+       function undo(idx) {\r
+               var undoImage = undoImages[idx];\r
+\r
+               if (!undoImage) \r
+                       throw new Error(errorDialog("Invalid undo state"));\r
+               if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
+                       throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
+\r
+               var canvas = $imageCanvas.get(0);\r
+               addUndo(canvas);\r
+               canvas.width = imageWidth = undoImage.width;\r
+               canvas.height = imageHeight = undoImage.height;\r
+               canvas.getContext("2d").drawImage(undoImage,0,0);\r
+\r
+               enableTab(activeTabId, true);\r
+               resetDisplayCanvas();\r
+       }\r
+\r
+       function addUndo(canvasElement) {\r
+               if (!canvasElement)\r
+                       throw new Error(errorDialog("No undo image state provided"));\r
+\r
+               if (undoImages.length == undoLevels) {\r
+                       undoImages.shift();\r
+               }\r
+               var undoCanvas = document.createElement("canvas");\r
+               undoCanvas.width = canvasElement.width;\r
+               undoCanvas.height = canvasElement.height;\r
+               undoCanvas.getContext("2d").drawImage(canvasElement,0,0);\r
+               $j(undoCanvas).addClass("undo-canvas");\r
+               undoImages.push(undoCanvas);\r
+               updateUndoList();\r
+       }\r
+\r
+       function updateUndoList() {\r
+               var $listCtr = $j("#undo-bar", doc)\r
+                       .html("");\r
+\r
+               var ctrHeight = $listCtr.height();\r
+\r
+               var $testCanvas = $j("<canvas></canvas>", doc)\r
+                       .addClass("undo-canvas-small")\r
+                       .addClass("far-far-away")\r
+                       .appendTo("body");\r
+\r
+               var canvasHeight = $testCanvas.height();\r
+               var canvasWidth = $testCanvas.width();\r
+               var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10);\r
+\r
+               $testCanvas.remove();\r
+\r
+               var undoRatio = canvasWidth / canvasHeight;\r
+\r
+               for (var i=undoImages.length-1;i>=0;i--) {\r
+                       (function(){\r
+                               var canvas = document.createElement("canvas");\r
+                               $j(canvas)\r
+                                       .addClass("undo-canvas-small")\r
+                                       .attr("width", canvasWidth)\r
+                                       .attr("height", canvasHeight);\r
+\r
+                               var image = undoImages[i];\r
+                               $j(image).show();\r
+                               \r
+                               var undoWidth, undoHeight;\r
+                               var imageRatio = image.width / image.height;\r
+\r
+                               if (imageRatio > undoRatio) {   // image too wide\r
+                                       undoWidth = canvasWidth;\r
+                                       undoHeight = canvasWidth / imageRatio;\r
+                               } else {\r
+                                       undoWidth = canvasHeight * imageRatio;\r
+                                       undoHeight = canvasHeight;\r
+                               }\r
+\r
+                               var restWidth = canvasWidth - undoWidth;\r
+                               var restHeight = canvasHeight - undoHeight;\r
+\r
+                               canvas.getContext("2d").drawImage(\r
+                                       image,\r
+                                       0,0,image.width,image.height,\r
+                                       restWidth*0.5, restHeight*0.5,\r
+                                       undoWidth, undoHeight\r
+                               );\r
+\r
+\r
+                               $link = $j("<a href='#'></a>", doc)\r
+                                       .addClass("undo-link")\r
+                                       .appendTo($listCtr)\r
+                                       .mouseover(function(){ $j(this).addClass("hover") })\r
+                                       .mouseout(function(){ $j(this).removeClass("hover") });\r
+                               $j(canvas).appendTo($link);\r
+\r
+                               var displayShowing;\r
+                               var undoIndex = i;\r
+                               $link.click(function() {\r
+                                       $j(image).hide();\r
+                                       $j(image).remove();\r
+                                       undo(undoIndex);\r
+                                       if (displayShowing)\r
+                                               $displayCanvas.show();\r
+                                       $j(".jcrop-holder", doc).show();\r
+                               });\r
+\r
+                               $link.mouseover(function() {\r
+                                       displayShowing = $displayCanvas.css("display") != "none";\r
+                                       var $imagectr = $j("#image-container", doc);\r
+\r
+                                       $j(".jcrop-holder", doc).hide();\r
+                                       $displayCanvas.hide();\r
+                                       $j(image).appendTo($imagectr);\r
+\r
+                                       var h1 = $j("#image-area", doc).height();\r
+                                       var h2 = image.height;\r
+                                       var m = Math.max(0, (h1 - h2) / 2);\r
+                                       $imagectr.css("marginTop", m);\r
+                       \r
+                                       $imagectr.height(image.height);\r
+                               });\r
+\r
+                               $link.mouseout(function() {\r
+                                       $j(image).remove();\r
+                                       if (displayShowing)\r
+                                               $displayCanvas.show();\r
+                                       $j(".jcrop-holder", doc).show();\r
+                                       updateDisplayCanvas();\r
+                               });\r
+\r
+\r
+                               $j(canvas).attr("title", "Click to revert to this previous image");\r
+\r
+                       })();\r
+               }\r
+       }\r
+\r
+\r
+       function applyAction(id, options, afteraction) {\r
+               if (!Pixastic.Actions[id])\r
+                       throw new Error("applyAction(): unknown action [" + id + "]");\r
+\r
+               $j("#action-bar-overlay", doc).show();\r
+\r
+               setTimeout(function() {\r
+                       options.leaveDOM = true;\r
+                       var canvasElement = $imageCanvas.get(0);\r
+                       addUndo(canvasElement)\r
+       \r
+                       var res = Pixastic.process(\r
+                               canvasElement, id, options,\r
+                               function(resCanvas) {\r
+                                       canvasElement.width = imageWidth = resCanvas.width;\r
+                                       canvasElement.height = imageHeight = resCanvas.height;\r
+       \r
+                                       var ctx = canvasElement.getContext("2d");\r
+                                       ctx.clearRect(0,0,imageWidth,imageHeight);\r
+                                       ctx.drawImage(resCanvas,0,0);\r
+                                       $imageCanvas = $j(canvasElement);\r
+                                       resetDisplayCanvas();\r
+       \r
+                                       $j("#action-bar-overlay", doc).hide();\r
+\r
+                                       if (afteraction)\r
+                                               afteraction();\r
+                               }\r
+                       );\r
+                       if (!res)\r
+                               throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]");\r
+               },1);\r
+       }\r
+\r
+\r
+       function previewAction(id, options, afteraction) {\r
+               if (!Pixastic.Actions[id])\r
+                       throw new Error("applyAction(): unknown action [" + id + "]");\r
+\r
+               $j("#action-bar-overlay", doc).show();\r
+\r
+               resetDisplayCanvas();\r
+\r
+               options.leaveDOM = true;\r
+               var canvasElement = $displayCanvas.get(0);\r
+\r
+               var res = Pixastic.process(\r
+                       canvasElement, id, options,\r
+                       function(resCanvas) {\r
+\r
+                               canvasElement.width = resCanvas.width;\r
+                               canvasElement.height = resCanvas.height;\r
+\r
+                               var ctx = canvasElement.getContext("2d");\r
+                               ctx.clearRect(0,0,canvasElement.width,canvasElement.height);\r
+                               ctx.drawImage(resCanvas,0,0);\r
+                               updateDisplayCanvas();\r
+                               updateOverlay();\r
+\r
+                               $j("#action-bar-overlay", doc).hide();\r
+\r
+                               if (afteraction)\r
+                                       afteraction();\r
+                       }\r
+               );\r
+       }\r
+\r
+       var onwindowresize = function() {\r
+               updateDisplayCanvas();\r
+               updateOverlay();\r
+       }\r
+\r
+       var baseUrl = ""\r
+\r
+       function buildEditor() {\r
+               var styles = [\r
+                       "jquery-ui-1.7.1.custom.css",\r
+                       "jquery.Jcrop.css",\r
+                       "pixastic.css"\r
+               ];\r
+\r
+               for (var i=0;i<styles.length;i++) {\r
+                       var s = doc.createElement("link");\r
+                       s.href = baseUrl + styles[i];\r
+                       s.type = "text/css";\r
+                       s.rel = "stylesheet";\r
+                       doc.getElementsByTagName("head")[0].appendChild( s );\r
+               }\r
+\r
+               undoImages = [];\r
+               accordionElements = {};\r
+               tabElements = {};\r
+               activeTabId = -1;\r
+               $activeTabContent = null;\r
+\r
+               // setup DOM UI skeleton\r
+               $editor = $j("<div />", doc)\r
+                       .attr("id", "pixastic-editor")\r
+                       .appendTo($j(doc.body));\r
+\r
+               $editor.append(\r
+                       $j("<div id='background' />", doc),\r
+                       $j("<div id='edit-ctr-1' />", doc).append(\r
+                               $j("<div id='edit-ctr-2' />", doc).append(\r
+                                       $j("<div id='controls-bar' />", doc).append(\r
+                                               $j("<div id='action-bar' />", doc).append(\r
+                                                       $j("<div id='action-bar-overlay' />", doc)\r
+                                               ),\r
+                                               $j("<div id='undo-bar' />", doc)\r
+                                       ),\r
+                                       $j("<div id='image-area' />", doc).append(\r
+                                               $j("<div id='image-area-sub' />", doc).append(\r
+                                                       $j("<div id='image-container' />", doc),\r
+                                                       $j("<div id='image-overlay-container' />", doc).append(\r
+                                                               $j("<div id='image-overlay' />", doc)\r
+                                                       )\r
+                                               )\r
+                                       )\r
+                               )\r
+                       ),\r
+                       $j("<div id='main-bar' />", doc),\r
+                       $j("<div id='powered-by-pixastic'><a href=\"http://www.pixastic.com/\" target=\"_blank\">Powered by Pixastic</a></div>", doc)\r
+               );\r
+\r
+               $j("#image-container", doc).append(\r
+                       $displayCanvas = $j("<canvas />", doc)\r
+                               .addClass("display-canvas")\r
+               );\r
+\r
+               // loop through all  defined UI action controls\r
+               var tabs = PixasticEditor.UI.data.tabs;\r
+\r
+               for (var i=0;i<tabs.length;i++) {\r
+                       (function() {\r
+       \r
+                       var tab = tabs[i];\r
+\r
+                       var $tabElement = $j("<a href=\"#\">" + tab.title + "</a>", doc)\r
+                               .attr("id", "main-tab-button-" + tab.id)\r
+                               .addClass("main-tab")\r
+                               .click(function() {\r
+                                       enableTab(tab.id);\r
+                               })\r
+                               .mouseover(function(){ $j(this).addClass("hover") })\r
+                               .mouseout(function(){ $j(this).removeClass("hover") });\r
+       \r
+                       $j("#main-bar", doc).append($tabElement);\r
+\r
+                       tabElements[tab.id] = $tabElement;\r
+\r
+                       var $menu = $j("<div/>", doc);\r
+                       accordionElements[tab.id] = $menu;\r
+\r
+                       for (var j=0;j<tab.actions.length;j++) {\r
+                               (function() {\r
+\r
+                               var action = tab.actions[j];\r
+\r
+                               var $actionElement = $j("<div><h3><a href=\"#\">" + action.title + "</a></h3></div>", doc)\r
+\r
+                               $menu.append($actionElement);\r
+\r
+                               var $content = $j("<div></div>", doc)\r
+                                       .attr("id", "pixastic-action-tab-content-" + action.id)\r
+                                       .appendTo($actionElement);\r
+\r
+                               var controlOptions = [];\r
+\r
+                               action.previewEnabled = false;\r
+                               if (action.forcePreview)\r
+                                       action.previewEnabled = true;\r
+\r
+                               function togglePreview(enable, doAction) {\r
+                                       if (enable && !action.previewEnabled && doAction)\r
+                                               doAction(true);\r
+                                       if (!enable && action.previewEnabled)\r
+                                               resetDisplayCanvas();\r
+                       \r
+                                       action.previewEnabled = enable;\r
+                               }\r
+\r
+                               var reset = function() {\r
+                                       for (var i in controlOptions) {\r
+                                               if (controlOptions.hasOwnProperty(i)) {\r
+                                                       controlOptions[i].reset();\r
+                                               }\r
+                                       }\r
+                                       if (action.previewEnabled)\r
+                                               doAction(true);\r
+                               }\r
+                               var doAction = function(isPreview) {\r
+                                       var options = {};\r
+                                       for (var i in controlOptions) {\r
+                                               if (controlOptions.hasOwnProperty(i)) {\r
+                                                       options[i] = controlOptions[i].valueField.val();\r
+                                               }\r
+                                       }\r
+\r
+                                       var afteraction = function() {\r
+                                               if (action.onafteraction)\r
+                                                       action.onafteraction(action, isPreview);\r
+                                               if (!isPreview)\r
+                                                       resetDisplayCanvas();\r
+       \r
+                                               if (!isPreview && !action.forcePreview) {\r
+                                                       $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false);\r
+                                                       togglePreview(false);\r
+                                                       reset();\r
+                                               }\r
+                                       }\r
+\r
+                                       if (isPreview) {\r
+                                               previewAction(action.id, options, afteraction);\r
+                                       } else {\r
+                                               applyAction(action.id, options, afteraction);\r
+                                       }\r
+\r
+                               }\r
+\r
+                               var hadInputs = false;\r
+\r
+                               if (action.controls) {\r
+                                       var onChange = function() {};\r
+                                       if (action.isAction && action.preview) {\r
+                                               onChange = function() {\r
+                                                       if (action.previewEnabled)\r
+                                                               doAction(true)\r
+                                               };\r
+                                       }\r
+\r
+                                       for (var k=0;k<action.controls.length;k++) {\r
+                                               var control = action.controls[k];\r
+                                               if (typeof control.defaultValue != "function") {\r
+                                                       (function(){\r
+                                                       var defVal = control.defaultValue;\r
+                                                       control.defaultValue = function() {\r
+                                                               return defVal;\r
+                                                       }\r
+                                                       })();\r
+                                               }\r
+                                               var controlId = action.id + "-" + control.option;\r
+\r
+                                               if (control.type != "output")\r
+                                                       hadInputs = true;\r
+\r
+                                               switch (control.type) {\r
+                                                       case "number" :\r
+                                                               switch (control.ui) {\r
+                                                                       case "slider" : \r
+                                                                               var slider = PixasticEditor.UI.makeSlider(\r
+                                                                                       control.label, controlId, \r
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
+                                                                               );\r
+               \r
+                                                                               slider.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = slider;\r
+                                                                               break;\r
+                                                                       case "text" : \r
+                                                                               var text = PixasticEditor.UI.makeNumericInput(\r
+                                                                                       control.label, control.labelRight, controlId, \r
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
+                                                                               );\r
+                                                                               text.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = text;\r
+                                                                               break;\r
+                                                               }\r
+                                                               break;\r
+                                                       case "boolean" :\r
+                                                               switch (control.ui) {\r
+                                                                       case "checkbox" : \r
+                                                                               var checkbox = PixasticEditor.UI.makeCheckbox(\r
+                                                                                       control.label, controlId, control.defaultValue, onChange\r
+                                                                               );\r
+               \r
+                                                                               checkbox.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = checkbox;\r
+                                                                               break;\r
+                                                               }\r
+                                                       case "string" :\r
+                                                               switch (control.ui) {\r
+                                                                       case "select" : \r
+                                                                               var select = PixasticEditor.UI.makeSelect(\r
+                                                                                       control.label, controlId, control.values, control.defaultValue, onChange\r
+                                                                               );\r
+               \r
+                                                                               select.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = select;\r
+                                                                               break;\r
+                                                               }\r
+                                                               break;\r
+                                                       case "output" :\r
+                                                               var outputText = $j("<div></div>", doc)\r
+                                                                       .addClass("ui-action-output")\r
+                                                                       .html(control.content)\r
+                                                                       .appendTo($content);\r
+                                                               break;\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               if (action.isAction) {\r
+\r
+                                       var $applyButton = PixasticEditor.UI.makeButton("Apply")\r
+                                               .addClass("pixastic-option-button-apply")\r
+                                               .click(function() {doAction();});\r
+\r
+                                       $content.append($applyButton);\r
+\r
+                                       if (hadInputs) {\r
+                                               var $resetButton = PixasticEditor.UI.makeButton("Reset")\r
+                                                       .addClass("pixastic-option-button-reset")\r
+                                                       .click(reset);\r
+       \r
+                                               $content.append($resetButton)\r
+                                       }\r
+\r
+                                       if (action.preview && !action.forcePreview) {\r
+                                               var $checkctr = $j("<div></div>", doc)\r
+                                                       .addClass("ui-checkbox-container")\r
+                                                       .addClass("ui-preview-checkbox-container");\r
+\r
+                                               var $label = $j("<label></label>", doc)\r
+                                                       .addClass("ui-checkbox-label")\r
+                                                       .attr("for", "pixastic-input-preview-" + action.id)\r
+                                                       .html("Preview:")\r
+                                                       .appendTo($checkctr);\r
+\r
+                                               var $checkbox = $j("<input type=\"checkbox\"></input>", doc)\r
+                                                       .addClass("ui-checkbox")\r
+                                                       .attr("id", "pixastic-input-preview-" + action.id)\r
+                                                       .appendTo($checkctr)\r
+                                                       .change(function() {\r
+                                                               togglePreview(this.checked, doAction)\r
+                                                       });\r
+\r
+                                               $content.append($checkctr);\r
+\r
+                                               $content.data("previewCheckbox", $checkbox);\r
+                                       }\r
+\r
+                               }\r
+\r
+\r
+                               if (typeof action.content == "function") {\r
+                                       action.content($content);\r
+                               }\r
+\r
+                               // stupid hack to make it possible to get $content in change event (below)\r
+                               $j("<span></span>", doc).appendTo($content);\r
+\r
+                               $content.data("controlOptions", controlOptions);\r
+                               $content.data("onactivate", action.onactivate);\r
+                               $content.data("ondeactivate", action.ondeactivate);\r
+                               $content.data("onoverlayupdate", action.onoverlayupdate);\r
+                               $content.data("accordionindex", j);\r
+                               $content.data("uidesc", action);\r
+\r
+                               })();\r
+                       }\r
+       \r
+                       $j("#action-bar", doc).append($menu);\r
+\r
+                       $menu.hide().accordion({\r
+                               header: "h3",\r
+                               autoHeight : false,\r
+                               collapsible : true,\r
+                               active: -1\r
+                       })\r
+                       .bind("accordionchange", \r
+                               function(event, ui) {\r
+                                       resetDisplayCanvas();\r
+\r
+                                       // oldContent / newContent are arrays of whatever elements are present in the content area\r
+                                       // We need the parent element (the one holding the content) but if there is no content, how do we get it?\r
+                                       // fixed above by always appending a <span> but that's ugly and needs to be done in some other way\r
+                                       if (ui.oldContent.get(0)) {\r
+                                               var $parent = $j(ui.oldContent.get(0).parentNode);\r
+                                               if ($parent.data("ondeactivate")) {\r
+                                                       $parent.data("ondeactivate")();\r
+                                               }\r
+                                       }\r
+                                       $activeTabContent = ui.newContent;\r
+\r
+                                       if (ui.newContent.get(0)) {\r
+                                               var $parent = $j(ui.newContent.get(0).parentNode);\r
+                                               if ($parent.data("previewCheckbox"))\r
+                                                       $parent.data("previewCheckbox").attr("checked", false);\r
+                                               $parent.data("uidesc").previewEnabled = false;\r
+                                               if ($parent.data("uidesc").forcePreview)\r
+                                                       $parent.data("uidesc").previewEnabled = true;\r
+\r
+                                               var controlOptions = $parent.data("controlOptions");\r
+                                               for (var i in controlOptions) {\r
+                                                       if (controlOptions.hasOwnProperty(i)) {\r
+                                                               controlOptions[i].reset();\r
+                                                       }\r
+                                               }\r
+                                               if ($parent.data("onactivate")) {\r
+                                                       $parent.data("onactivate")();\r
+                                               }\r
+                                       }\r
+                                       updateDisplayCanvas();\r
+\r
+                               }\r
+                       );\r
+\r
+       \r
+                       })();\r
+               }\r
+\r
+               $j(window).bind("resize", onwindowresize);\r
+       }\r
+\r
+       function showLoadingScreen() {\r
+               if ($loadingScreen) {\r
+                       $loadingScreen.show();\r
+                       return;\r
+               }\r
+               $loadingScreen = $j("<div id=\"loading-screen\" />")\r
+               var $ctr = $j("<div id=\"loading-screen-cell\" />");\r
+               $j("<div />")\r
+                       .addClass("spinner")\r
+                       .appendTo($ctr);\r
+               $loadingScreen.append($ctr);\r
+               $loadingScreen.appendTo("body");\r
+       }\r
+\r
+       function hideLoadingScreen() {\r
+               setTimeout(function() {\r
+                       $loadingScreen.hide();\r
+               }, 1);\r
+       }\r
+\r
+       var oldScrollLeft;\r
+       var oldScrollTop;\r
+       var oldOverflow;\r
+\r
+       // fire it up\r
+       function init(callback) {\r
+               isRunning = true;\r
+\r
+               showLoadingScreen();\r
+\r
+               oldScrollLeft = document.body.scrollLeft;\r
+               oldScrollTop = document.body.scrollTop;\r
+               oldOverflow = document.body.style.overflow;\r
+\r
+               document.body.scrollLeft = 0;\r
+               document.body.scrollTop = 0;\r
+               document.body.style.overflow = "hidden";\r
+\r
+               $frame = $j("<iframe />");\r
+               $frame.hide();\r
+               $frame.css({\r
+                       position : "absolute",\r
+                       left : document.body.scrollLeft + "px",\r
+                       top : document.body.scrollTop + "px",\r
+                       width : "100%",\r
+                       height : "100%",\r
+                       zIndex : "11"\r
+               });\r
+               $frame.load(function(){\r
+                       doc = $frame.get(0).contentDocument;\r
+\r
+                       buildEditor();\r
+                       callback();\r
+                       $frame.show();\r
+                       hideLoadingScreen();\r
+                       setTimeout(function(){\r
+                               updateDisplayCanvas();\r
+                       },10);\r
+               });\r
+               $frame.appendTo("body");\r
+       }\r
+\r
+       // unload the editor, remove all elements added to the page and restore whatever properties we messed with\r
+       function unload() {\r
+               $j(window).unbind("resize", onwindowresize);\r
+               $frame.hide();\r
+               $editor.hide();\r
+               $editor.remove();\r
+               $frame.remove();\r
+\r
+               document.body.scrollLeft = oldScrollLeft;\r
+               document.body.scrollTop = oldScrollTop;\r
+               document.body.style.overflow = oldOverflow;\r
+\r
+               isRunning = false;\r
+       }\r
+\r
+\r
+       // resets the display canvas (clears the canvas and repaints the current state)\r
+       // then updates display and overlay\r
+       function resetDisplayCanvas() {\r
+               if (!($displayCanvas && $displayCanvas.get))    throw new Error(errorDialog("$displayCanvas doesn't exist"));\r
+               if (!($imageCanvas && $imageCanvas.get))        throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
+\r
+               var display = $displayCanvas.get(0);\r
+               var image = $imageCanvas.get(0);\r
+\r
+               if (!display)   throw new Error(errorDialog("resetDisplayCanvas(): No elements in $displayCanvas"));\r
+               if (!image)     throw new Error(errorDialog("resetDisplayCanvas(): No elements in $imageCanvas"));\r
+\r
+               display.width = imageWidth;\r
+               display.height = imageHeight;\r
+               display.getContext("2d").drawImage( image, 0, 0 );\r
+\r
+               updateDisplayCanvas();\r
+               updateOverlay();\r
+       }\r
+\r
+       // updates the display by resetting the height and margin of the image container\r
+       // this is mainly to keep vertical centering\r
+       function updateDisplayCanvas() {\r
+               var $imageCtr = $j("#image-container", doc);\r
+               var $editArea = $j("#image-area", doc);\r
+\r
+               if (!$imageCtr.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $imageCtr doesn't exist"));\r
+               if (!$displayCanvas.get(0))     throw new Error(errorDialog("updateDisplayCanvas(): $displayCanvas doesn't exist"));\r
+               if (!$editArea.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $editArea doesn't exist"));\r
+\r
+               var h2 = $displayCanvas.get(0).height;\r
+               var h1 = $j("#image-area", doc).height();\r
+               var m = Math.max(0, (h1 - h2) / 2);\r
+               $imageCtr.height(h2);\r
+               $imageCtr.css("marginTop", m);\r
+       }\r
+\r
+       // basically the same as updateDisplayCanvas but for the image overlay\r
+       function updateOverlay() {\r
+               var $overlay = $j("#image-overlay-container", doc);\r
+               var $imagectr = $j("#image-container", doc);\r
+               $overlay.height($imagectr.height());\r
+               $overlay.css("marginTop", $imagectr.css("marginTop"));\r
+\r
+               if ($activeTabContent && $activeTabContent.get(0)) {\r
+                       var $tabContent = $j($activeTabContent.get(0).parentNode);\r
+                       if (typeof $tabContent.data("onoverlayupdate") == "function")\r
+                               $tabContent.data("onoverlayupdate")();\r
+               }\r
+       }\r
+\r
+       var imageIsLoading = false;\r
+       var originalImageElement;\r
+       var $tmpImg;\r
+\r
+       function loadImage(imgEl) {\r
+               if (imageIsLoading) \r
+                       return;\r
+\r
+               imageIsLoading = true;\r
+\r
+               originalImageElement = imgEl;\r
+\r
+               $imageCanvas = $j("<canvas />", doc);\r
+               imageCtx = $imageCanvas.get(0).getContext("2d");\r
+\r
+               imageWidth = 0;\r
+               imageHeight = 0;\r
+               $imageCanvas.attr("width", 0);\r
+               $imageCanvas.attr("height", 0);\r
+\r
+               if (imgEl.tagName.toLowerCase() == "img" && !imgEl._pixasticCanvas) {\r
+                       var onload = function(el) {\r
+                               imageWidth = el.offsetWidth;\r
+                               imageHeight = el.offsetHeight;\r
+                               $imageCanvas.attr("width", imageWidth);\r
+                               $imageCanvas.attr("height", imageHeight);\r
+                               imageCtx.drawImage(el,0,0);\r
+                               $tmpImg.remove();\r
+                               imageIsLoading = false;\r
+                               enableTab("reshape");\r
+                               setTimeout(function() {\r
+                                       resetDisplayCanvas();\r
+                               }, 10);\r
+                       }\r
+                       $tmpImg = $j("<img />", doc)\r
+                               .css("position", "absolute")\r
+                               .css("left", "-9999px")\r
+                               .css("top", "-9999px")\r
+                               .appendTo("body")\r
+                               .load(function(){onload(this);})\r
+                               .error(function(){\r
+                                       throw new Error("Could not load temporary copy image. Is provided image valid?");\r
+                                       unload();\r
+                               })\r
+                               .attr("src", imgEl.src);\r
+                               if ($tmpImg.attr("complete")) {\r
+                                       onload($tmpImg.get(0));\r
+                               }\r
+               } else {\r
+                       var $canvas = imgEl._pixasticCanvas || imgEl;\r
+                       imageWidth = $canvas.attr("width");\r
+                       imageHeight = $canvas.attr("height");\r
+                       $imageCanvas.attr("width", imageWidth);\r
+                       $imageCanvas.attr("height", imageHeight);\r
+                       imageCtx.drawImage($canvas.get(0), 0, 0);\r
+                       imageIsLoading = false;\r
+                       enableTab("reshape");\r
+                       resetDisplayCanvas();\r
+               }\r
+       }\r
+\r
+       // return public interface\r
+       return {\r
+               /*\r
+               // don't call. For now we must load the image immediately via load()\r
+               loadImage : function(imgEl) {\r
+                       if (!isRunning) return false;\r
+                       loadImage(imgEl);\r
+               },\r
+               */\r
+               saveToPage : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::saveToPage(): Editor is not running");\r
+\r
+                       var $canvas = PixasticEditor.getImageCanvas();\r
+                       var img = PixasticEditor.getOriginalImage();\r
+                       if (img.tagName.toLowerCase() == "canvas") {\r
+                               img.width = $canvas.attr("width");\r
+                               img.height = $canvas.attr("height");\r
+                               img.getContext("2d").drawImage($canvas.get(0), 0, 0);\r
+                       } else {\r
+                               img.src = PixasticEditor.getDataURI();\r
+                       }\r
+                       img._pixasticCanvas = PixasticEditor.getImageCanvas();\r
+               },\r
+               load : function(img, customBaseUrl) {\r
+                       if (isRunning) return false;\r
+\r
+                       if (!img)\r
+                               throw new Error("Must be called with an image or canvas as its first argument", "PixasticEditor::load")\r
+\r
+                       $ = PixasticEditor.jQuery;\r
+\r
+                       baseUrl = customBaseUrl || "http://www.pixastic.com/editor-test/";\r
+\r
+                       init(function() {\r
+                               if (img && img.tagName.toLowerCase() == "img" || img.tagName.toLowerCase() == "canvas") {\r
+                                       loadImage(img);\r
+                               }\r
+                       });\r
+               },\r
+\r
+               unload : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::unload(): Editor is not running");\r
+                       unload();\r
+               },\r
+\r
+               getDocument : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDocument(): Editor is not running");\r
+\r
+                       return doc;\r
+               },\r
+\r
+               validSaveFormats : function() {\r
+                       return saveFormats;\r
+               },\r
+\r
+               getOriginalImage : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getOriginalImage(): Editor is not running");\r
+                       return originalImageElement;\r
+               },\r
+\r
+               getDataURI : function(mime) {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDataURI(): Editor is not running");\r
+\r
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
+\r
+                       return $imageCanvas.get(0).toDataURL(mime||"image/png");\r
+               },\r
+\r
+               getImageCanvas : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getImageCanvas(): Editor is not running");\r
+\r
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
+\r
+                       return $imageCanvas;\r
+               },\r
+               getOverlay : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getOverlay(): Editor is not running");\r
+\r
+                       return $j("#image-overlay", doc);\r
+               },\r
+               getDisplayCanvas : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayCanvas(): Editor is not running");\r
+\r
+                       if (!($displayCanvas && $displayCanvas.get && $displayCanvas.get(0)))\r
+                               throw new Error(errorDialog("$displayCanvas doesn't exist", "getDisplayCanvas"));\r
+                       return $displayCanvas;\r
+               },\r
+               getDisplayWidth : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayWidth(): Editor is not running");\r
+\r
+                       return displayWidth;\r
+               },\r
+               getDisplayHeight : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayHeight(): Editor is not running");\r
+\r
+                       return displayHeight;\r
+               },\r
+               getImageWidth : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getImageWidth(): Editor is not running");\r
+\r
+                       return imageWidth;\r
+               },\r
+               getImageHeight : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getImageHeight(): Editor is not running");\r
+\r
+                       return imageHeight;\r
+               },\r
+               errorDialog : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::errorDialog(): Editor is not running");\r
+\r
+                       return errorDialog.apply(null, arguments);\r
+               }\r
+       }\r
+\r
+})();
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.all.js b/js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.all.js
new file mode 100644 (file)
index 0000000..fa38d04
--- /dev/null
@@ -0,0 +1,3169 @@
+/*\r
+ * Pixastic Lib - Core Functions - v0.1.3\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+var Pixastic = (function() {\r
+\r
+\r
+       function addEvent(el, event, handler) {\r
+               if (el.addEventListener)\r
+                       el.addEventListener(event, handler, false); \r
+               else if (el.attachEvent)\r
+                       el.attachEvent("on" + event, handler); \r
+       }\r
+\r
+       function onready(handler) {\r
+               var handlerDone = false;\r
+               var execHandler = function() {\r
+                       if (!handlerDone) {\r
+                               handlerDone = true;\r
+                               handler();\r
+                       }\r
+               }\r
+               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");\r
+               var script = document.getElementById("__onload_ie_sumbox__");\r
+               script.onreadystatechange = function() {\r
+                       if (script.readyState == "complete") {\r
+                               script.parentNode.removeChild(script);\r
+                               execHandler();\r
+                       }\r
+               }\r
+               if (document.addEventListener)\r
+                       document.addEventListener("DOMContentLoaded", execHandler, false); \r
+               addEvent(window, "load", execHandler);\r
+       }\r
+\r
+       function init() {\r
+               if (!Pixastic.parseOnLoad) return;\r
+               var imgEls = getElementsByClass("pixastic", null, "img");\r
+               var canvasEls = getElementsByClass("pixastic", null, "canvas");\r
+               var elements = imgEls.concat(canvasEls);\r
+               for (var i=0;i<elements.length;i++) {\r
+                       (function() {\r
+\r
+                       var el = elements[i];\r
+                       var actions = [];\r
+                       var classes = el.className.split(" ");\r
+                       for (var c=0;c<classes.length;c++) {\r
+                               var cls = classes[c];\r
+                               if (cls.substring(0,9) == "pixastic-") {\r
+                                       var actionName = cls.substring(9);\r
+                                       if (actionName != "")\r
+                                               actions.push(actionName);\r
+                               }\r
+                       }\r
+                       if (actions.length) {\r
+                               if (el.tagName.toLowerCase() == "img") {\r
+                                       var dataImg = new Image();\r
+                                       dataImg.src = el.src;\r
+                                       if (dataImg.complete) {\r
+                                               for (var a=0;a<actions.length;a++) {\r
+                                                       var res = Pixastic.applyAction(el, el, actions[a], null);\r
+                                                       if (res) \r
+                                                               el = res;\r
+                                               }\r
+                                       } else {\r
+                                               dataImg.onload = function() {\r
+                                                       for (var a=0;a<actions.length;a++) {\r
+                                                               var res = Pixastic.applyAction(el, el, actions[a], null)\r
+                                                               if (res) \r
+                                                                       el = res;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } else {\r
+                                       setTimeout(function() {\r
+                                               for (var a=0;a<actions.length;a++) {\r
+                                                       var res = Pixastic.applyAction(\r
+                                                               el, el, actions[a], null\r
+                                                       );\r
+                                                       if (res) \r
+                                                               el = res;\r
+                                               }\r
+                                       },1);\r
+                               }\r
+                       }\r
+\r
+                       })();\r
+               }\r
+       }\r
+\r
+//     if (typeof pixastic_no_onready == "undefined") // yuck.\r
+//             onready(init);\r
+\r
+       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/\r
+       function getElementsByClass(searchClass,node,tag) {\r
+               var classElements = new Array();\r
+               if ( node == null )\r
+                       node = document;\r
+               if ( tag == null )\r
+                       tag = '*';\r
+\r
+               var els = node.getElementsByTagName(tag);\r
+               var elsLen = els.length;\r
+               var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");\r
+               for (i = 0, j = 0; i < elsLen; i++) {\r
+                       if ( pattern.test(els[i].className) ) {\r
+                               classElements[j] = els[i];\r
+                               j++;\r
+                       }\r
+               }\r
+               return classElements;\r
+       }\r
+\r
+       var debugElement;\r
+\r
+       function writeDebug(text, level) {\r
+               if (!Pixastic.debug) return;\r
+               try {\r
+                       switch (level) {\r
+                               case "warn" : \r
+                                       console.warn("Pixastic:", text);\r
+                                       break;\r
+                               case "error" :\r
+                                       console.error("Pixastic:", text);\r
+                                       break;\r
+                               default:\r
+                                       console.log("Pixastic:", text);\r
+                       }\r
+               } catch(e) {\r
+               }\r
+               if (!debugElement) {\r
+                       \r
+               }\r
+       }\r
+\r
+\r
+       return {\r
+\r
+               parseOnLoad : false,\r
+\r
+               debug : false,\r
+               \r
+               applyAction : function(img, dataImg, actionName, options) {\r
+\r
+                       options = options || {};\r
+\r
+                       var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");\r
+                       if (imageIsCanvas && Pixastic.Client.isIE()) {\r
+                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");\r
+                               return false;\r
+                       }\r
+\r
+                       var canvas, ctx;\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               canvas = document.createElement("canvas");\r
+                               ctx = canvas.getContext("2d");\r
+                       }\r
+\r
+                       var w = parseInt(img.offsetWidth);\r
+                       var h = parseInt(img.offsetHeight);\r
+\r
+                       if (imageIsCanvas) {\r
+                               w = img.width;\r
+                               h = img.height;\r
+                       }\r
+\r
+                       if (actionName.indexOf("(") > -1) {\r
+                               var tmp = actionName;\r
+                               actionName = tmp.substr(0, tmp.indexOf("("));\r
+                               var arg = tmp.match(/\((.*?)\)/);\r
+                               if (arg[1]) {\r
+                                       arg = arg[1].split(";");\r
+                                       for (var a=0;a<arg.length;a++) {\r
+                                               thisArg = arg[a].split("=");\r
+                                               if (thisArg.length == 2) {\r
+                                                       if (thisArg[0] == "rect") {\r
+                                                               var rectVal = thisArg[1].split(",");\r
+                                                               options[thisArg[0]] = {\r
+                                                                       left : parseInt(rectVal[0],10)||0,\r
+                                                                       top : parseInt(rectVal[1],10)||0,\r
+                                                                       width : parseInt(rectVal[2],10)||0,\r
+                                                                       height : parseInt(rectVal[3],10)||0\r
+                                                               }\r
+                                                       } else {\r
+                                                               options[thisArg[0]] = thisArg[1];\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if (!options.rect) {\r
+                               options.rect = {\r
+                                       left : 0, top : 0, width : w, height : h\r
+                               };\r
+                       }\r
+                       var validAction = false;\r
+                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {\r
+                               validAction = true;\r
+                       }\r
+                       if (!validAction) {\r
+                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");\r
+                               return false;\r
+                       }\r
+                       if (!Pixastic.Actions[actionName].checkSupport()) {\r
+                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");\r
+                               return false;\r
+                       }\r
+\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               canvas.width = w;\r
+                               canvas.height = h;\r
+                               canvas.style.width = w+"px";\r
+                               canvas.style.height = h+"px";\r
+                               ctx.drawImage(dataImg,0,0,w,h);\r
+\r
+                               if (!img.__pixastic_org_image) {\r
+                                       canvas.__pixastic_org_image = img;\r
+                                       canvas.__pixastic_org_width = w;\r
+                                       canvas.__pixastic_org_height = h;\r
+                               } else {\r
+                                       canvas.__pixastic_org_image = img.__pixastic_org_image;\r
+                                       canvas.__pixastic_org_width = img.__pixastic_org_width;\r
+                                       canvas.__pixastic_org_height = img.__pixastic_org_height;\r
+                               }\r
+\r
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {\r
+                               img.__pixastic_org_style = img.style.cssText;\r
+                       }\r
+\r
+                       var params = {\r
+                               image : img,\r
+                               canvas : canvas,\r
+                               width : w,\r
+                               height : h,\r
+                               useData : true,\r
+                               options : options\r
+                       }\r
+\r
+                       // Ok, let's do it!\r
+\r
+                       var res = Pixastic.Actions[actionName].process(params);\r
+\r
+                       if (!res) {\r
+                               return false;\r
+                       }\r
+\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               if (params.useData) {\r
+                                       if (Pixastic.Client.hasCanvasImageData()) {\r
+                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);\r
+\r
+                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.\r
+                                               canvas.getContext("2d").fillRect(0,0,0,0);\r
+                                       }\r
+                               }\r
+\r
+                               if (!options.leaveDOM) {\r
+                                       // copy properties and stuff from the source image\r
+                                       canvas.title = img.title;\r
+                                       canvas.imgsrc = img.imgsrc;\r
+                                       if (!imageIsCanvas) canvas.alt  = img.alt;\r
+                                       if (!imageIsCanvas) canvas.imgsrc = img.src;\r
+                                       canvas.className = img.className;\r
+                                       canvas.style.cssText = img.style.cssText;\r
+                                       canvas.name = img.name;\r
+                                       canvas.tabIndex = img.tabIndex;\r
+                                       canvas.id = img.id;\r
+                                       if (img.parentNode && img.parentNode.replaceChild) {\r
+                                               img.parentNode.replaceChild(canvas, img);\r
+                                       }\r
+                               }\r
+\r
+                               options.resultCanvas = canvas;\r
+\r
+                               return canvas;\r
+                       }\r
+\r
+                       return img;\r
+               },\r
+\r
+               prepareData : function(params, getCopy) {\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       var rect = params.options.rect;\r
+                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);\r
+                       var data = dataDesc.data;\r
+                       if (!getCopy) params.canvasData = dataDesc;\r
+                       return data;\r
+               },\r
+\r
+               // load the image file\r
+               process : function(img, actionName, options, callback)\r
+               {\r
+                       if (img.tagName.toLowerCase() == "img") {\r
+                               var dataImg = new Image();\r
+                               dataImg.src = img.src;\r
+                               if (dataImg.complete) {\r
+                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);\r
+                                       if (callback) callback(res);\r
+                                       return res;\r
+                               } else {\r
+                                       dataImg.onload = function() {\r
+                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)\r
+                                               if (callback) callback(res);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (img.tagName.toLowerCase() == "canvas") {\r
+                               var res = Pixastic.applyAction(img, img, actionName, options);\r
+                               if (callback) callback(res);\r
+                               return res;\r
+                       }\r
+               },\r
+\r
+               revert : function(img) {\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {\r
+                                       img.width = img.__pixastic_org_width;\r
+                                       img.height = img.__pixastic_org_height;\r
+                                       img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);\r
+\r
+                                       if (img.parentNode && img.parentNode.replaceChild) {\r
+                                               img.parentNode.replaceChild(img.__pixastic_org_image, img);\r
+                                       }\r
+\r
+                                       return img;\r
+                               }\r
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {\r
+                               img.style.cssText = img.__pixastic_org_style;\r
+                       }\r
+               },\r
+\r
+               Client : {\r
+                       hasCanvas : (function() {\r
+                               var c = document.createElement("canvas");\r
+                               var val = false;\r
+                               try {\r
+                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));\r
+                               } catch(e) {}\r
+                               return function() {\r
+                                       return val;\r
+                               }\r
+                       })(),\r
+\r
+                       hasCanvasImageData : (function() {\r
+                               var c = document.createElement("canvas");\r
+                               var val = false;\r
+                               var ctx;\r
+                               try {\r
+                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {\r
+                                               val = (typeof ctx.getImageData == "function");\r
+                                       }\r
+                               } catch(e) {}\r
+                               return function() {\r
+                                       return val;\r
+                               }\r
+                       })(),\r
+\r
+                       isIE : function() {\r
+                               return !!document.all && !!window.attachEvent && !window.opera;\r
+                       }\r
+               },\r
+\r
+               Actions : {}\r
+       }\r
+\r
+\r
+})();\r
+/*\r
+ * Pixastic Lib - jQuery plugin\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {\r
+       jQuery.fn.pixastic = function(action, options) {\r
+               var newElements = [];\r
+               this.each(\r
+                       function () {\r
+                               if (this.tagName.toLowerCase() == "img" && !this.complete) {\r
+                                       return;\r
+                               }\r
+                               var res = Pixastic.process(this, action, options);\r
+                               if (res) {\r
+                                       newElements.push(res);\r
+                               }\r
+                       }\r
+               );\r
+               if (newElements.length > 0)\r
+                       return jQuery(newElements);\r
+               else\r
+                       return this;\r
+       };\r
+\r
+};\r
+/*\r
+ * Pixastic Lib - Blend - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.blend = {\r
+\r
+       process : function(params) {\r
+               var amount = parseFloat(params.options.amount);\r
+               var mode = (params.options.mode || "normal").toLowerCase();\r
+               var image = params.options.image;\r
+\r
+               amount = Math.max(0,Math.min(1,amount));\r
+\r
+               if (!image) return false;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+                       var data = Pixastic.prepareData(params);\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       params.useData = false;\r
+\r
+                       var otherCanvas = document.createElement("canvas");\r
+                       otherCanvas.width = params.canvas.width;\r
+                       otherCanvas.height = params.canvas.height;\r
+                       var otherCtx = otherCanvas.getContext("2d");\r
+                       otherCtx.drawImage(image,0,0);\r
+\r
+                       var params2 = {canvas:otherCanvas,options:params.options};\r
+                       var data2 = Pixastic.prepareData(params2);\r
+                       var dataDesc2 = params2.canvasData;\r
+\r
+                       var p = w*h;\r
+                       var pix = p*4;\r
+                       var pix1, pix2;\r
+                       var r1, g1, b1;\r
+                       var r2, g2, b2;\r
+                       var r3, g3, b3;\r
+                       var r4, g4, b4;\r
+\r
+                       var dataChanged = false;\r
+\r
+                       switch (mode) {\r
+                               case "normal" : \r
+                                       //while (p--) {\r
+                                       //      data2[pix-=4] = data2[pix];\r
+                                       //      data2[pix1=pix+1] = data2[pix1];\r
+                                       //      data2[pix2=pix+2] = data2[pix2];\r
+                                       //}\r
+                                       break;\r
+\r
+                               case "multiply" : \r
+                                       while (p--) {\r
+                                               data2[pix-=4] = data[pix] * data2[pix] / 255;\r
+                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;\r
+                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "lighten" : \r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) > data2[pix])\r
+                                                       data2[pix] = r1;\r
+                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])\r
+                                                       data2[pix1] = g1;\r
+                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])\r
+                                                       data2[pix2] = b1;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "darken" : \r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) < data2[pix])\r
+                                                       data2[pix] = r1;\r
+                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])\r
+                                                       data2[pix1] = g1;\r
+                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])\r
+                                                       data2[pix2] = b1;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "darkercolor" : \r
+                                       while (p--) {\r
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
+                                                       data2[pix] = r1;\r
+                                                       data2[pix1] = g1;\r
+                                                       data2[pix2] = b1;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "lightercolor" : \r
+                                       while (p--) {\r
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
+                                                       data2[pix] = r1;\r
+                                                       data2[pix1] = g1;\r
+                                                       data2[pix2] = b1;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "lineardodge" : \r
+                                       otherCtx.globalCompositeOperation = "source-over";\r
+                                       otherCtx.drawImage(params.canvas, 0, 0);\r
+                                       otherCtx.globalCompositeOperation = "lighter";\r
+                                       otherCtx.drawImage(image, 0, 0);\r
+\r
+                                       /*\r
+                                       while (p--) {\r
+                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)\r
+                                                       data2[pix] = 255;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)\r
+                                                       data2[pix1] = 255;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)\r
+                                                       data2[pix2] = 255;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       */\r
+\r
+                                       break;\r
+\r
+                               case "linearburn" : \r
+                                       while (p--) {\r
+                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)\r
+                                                       data2[pix] = 0;\r
+                                               else\r
+                                                       data2[pix] = (r3 - 255);\r
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)\r
+                                                       data2[pix1] = 0;\r
+                                               else\r
+                                                       data2[pix1] = (g3 - 255);\r
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)\r
+                                                       data2[pix2] = 0;\r
+                                               else\r
+                                                       data2[pix2] = (b3 - 255);\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "difference" : \r
+                                       while (p--) {\r
+                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)\r
+                                                       data2[pix] = -r3;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)\r
+                                                       data2[pix1] = -g3;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)\r
+                                                       data2[pix2] = -b3;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "screen" : \r
+                                       while (p--) {\r
+                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));\r
+                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));\r
+                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "exclusion" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];\r
+                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];\r
+                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "overlay" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) < 128)\r
+                                                       data2[pix] = data2[pix]*r1*div_2_255;\r
+                                               else\r
+                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;\r
+\r
+                                               if ((g1 = data[pix1=pix+1]) < 128)\r
+                                                       data2[pix1] = data2[pix1]*g1*div_2_255;\r
+                                               else\r
+                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;\r
+\r
+                                               if ((b1 = data[pix2=pix+2]) < 128)\r
+                                                       data2[pix2] = data2[pix2]*b1*div_2_255;\r
+                                               else\r
+                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "softlight" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) < 128)\r
+                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;\r
+                                               else\r
+                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;\r
+\r
+                                               if ((g1 = data[pix1=pix+1]) < 128)\r
+                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;\r
+                                               else\r
+                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;\r
+\r
+                                               if ((b1 = data[pix2=pix+2]) < 128)\r
+                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;\r
+                                               else\r
+                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "hardlight" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               if ((r2 = data2[pix-=4]) < 128)\r
+                                                       data2[pix] = data[pix] * r2 * div_2_255;\r
+                                               else\r
+                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;\r
+\r
+                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
+                                                       data2[pix1] = data[pix1] * g2 * div_2_255;\r
+                                               else\r
+                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;\r
+\r
+                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
+                                                       data2[pix2] = data[pix2] * b2 * div_2_255;\r
+                                               else\r
+                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "colordodge" : \r
+                                       while (p--) {\r
+                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)\r
+                                                       data2[pix] = 255;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+\r
+                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)\r
+                                                       data2[pix1] = 255;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+\r
+                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)\r
+                                                       data2[pix2] = 255;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "colorburn" : \r
+                                       while (p--) {\r
+                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)\r
+                                                       data2[pix] = 0;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+\r
+                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)\r
+                                                       data2[pix1] = 0;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+\r
+                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)\r
+                                                       data2[pix2] = 0;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "linearlight" : \r
+                                       while (p--) {\r
+                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {\r
+                                                       data2[pix] = 0\r
+                                               } else {\r
+                                                       if (r3 > 255)\r
+                                                               data2[pix] = 255;\r
+                                                       else\r
+                                                               data2[pix] = r3;\r
+                                               }\r
+                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {\r
+                                                       data2[pix1] = 0\r
+                                               } else {\r
+                                                       if (g3 > 255)\r
+                                                               data2[pix1] = 255;\r
+                                                       else\r
+                                                               data2[pix1] = g3;\r
+                                               }\r
+                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {\r
+                                                       data2[pix2] = 0\r
+                                               } else {\r
+                                                       if (b3 > 255)\r
+                                                               data2[pix2] = 255;\r
+                                                       else\r
+                                                               data2[pix2] = b3;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "vividlight" : \r
+                                       while (p--) {\r
+                                               if ((r2=data2[pix-=4]) < 128) {\r
+                                                       if (r2) {\r
+                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) \r
+                                                                       data2[pix] = 0;\r
+                                                               else\r
+                                                                       data2[pix] = r3\r
+                                                       } else {\r
+                                                               data2[pix] = 0;\r
+                                                       }\r
+                                               } else if ((r3 = (r4=2*r2-256)) < 255) {\r
+                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) \r
+                                                               data2[pix] = 255;\r
+                                                       else\r
+                                                               data2[pix] = r3;\r
+                                               } else {\r
+                                                       if (r3 < 0) \r
+                                                               data2[pix] = 0;\r
+                                                       else\r
+                                                               data2[pix] = r3\r
+                                               }\r
+\r
+                                               if ((g2=data2[pix1=pix+1]) < 128) {\r
+                                                       if (g2) {\r
+                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) \r
+                                                                       data2[pix1] = 0;\r
+                                                               else\r
+                                                                       data2[pix1] = g3;\r
+                                                       } else {\r
+                                                               data2[pix1] = 0;\r
+                                                       }\r
+                                               } else if ((g3 = (g4=2*g2-256)) < 255) {\r
+                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)\r
+                                                               data2[pix1] = 255;\r
+                                                       else\r
+                                                               data2[pix1] = g3;\r
+                                               } else {\r
+                                                       if (g3 < 0) \r
+                                                               data2[pix1] = 0;\r
+                                                       else\r
+                                                               data2[pix1] = g3;\r
+                                               }\r
+\r
+                                               if ((b2=data2[pix2=pix+2]) < 128) {\r
+                                                       if (b2) {\r
+                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) \r
+                                                                       data2[pix2] = 0;\r
+                                                               else\r
+                                                                       data2[pix2] = b3;\r
+                                                       } else {\r
+                                                               data2[pix2] = 0;\r
+                                                       }\r
+                                               } else if ((b3 = (b4=2*b2-256)) < 255) {\r
+                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) \r
+                                                               data2[pix2] = 255;\r
+                                                       else\r
+                                                               data2[pix2] = b3;\r
+                                               } else {\r
+                                                       if (b3 < 0) \r
+                                                               data2[pix2] = 0;\r
+                                                       else\r
+                                                               data2[pix2] = b3;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "pinlight" : \r
+                                       while (p--) {\r
+                                               if ((r2=data2[pix-=4]) < 128)\r
+                                                       if ((r1=data[pix]) < (r4=2*r2))\r
+                                                               data2[pix] = r1;\r
+                                                       else\r
+                                                               data2[pix] = r4;\r
+                                               else\r
+                                                       if ((r1=data[pix]) > (r4=2*r2-256))\r
+                                                               data2[pix] = r1;\r
+                                                       else\r
+                                                               data2[pix] = r4;\r
+\r
+                                               if ((g2=data2[pix1=pix+1]) < 128)\r
+                                                       if ((g1=data[pix1]) < (g4=2*g2))\r
+                                                               data2[pix1] = g1;\r
+                                                       else\r
+                                                               data2[pix1] = g4;\r
+                                               else\r
+                                                       if ((g1=data[pix1]) > (g4=2*g2-256))\r
+                                                               data2[pix1] = g1;\r
+                                                       else\r
+                                                               data2[pix1] = g4;\r
+\r
+                                               if ((r2=data2[pix2=pix+2]) < 128)\r
+                                                       if ((r1=data[pix2]) < (r4=2*r2))\r
+                                                               data2[pix2] = r1;\r
+                                                       else\r
+                                                               data2[pix2] = r4;\r
+                                               else\r
+                                                       if ((r1=data[pix2]) > (r4=2*r2-256))\r
+                                                               data2[pix2] = r1;\r
+                                                       else\r
+                                                               data2[pix2] = r4;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "hardmix" : \r
+                                       while (p--) {\r
+                                               if ((r2 = data2[pix-=4]) < 128)\r
+                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)\r
+                                                               data2[pix] = 0;\r
+                                                       else\r
+                                                               data2[pix] = 255;\r
+                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)\r
+                                                       data2[pix] = 0;\r
+                                               else\r
+                                                       data2[pix] = 255;\r
+\r
+                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
+                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)\r
+                                                               data2[pix1] = 0;\r
+                                                       else\r
+                                                               data2[pix1] = 255;\r
+                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)\r
+                                                       data2[pix1] = 0;\r
+                                               else\r
+                                                       data2[pix1] = 255;\r
+\r
+                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
+                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)\r
+                                                               data2[pix2] = 0;\r
+                                                       else\r
+                                                               data2[pix2] = 255;\r
+                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)\r
+                                                       data2[pix2] = 0;\r
+                                               else\r
+                                                       data2[pix2] = 255;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+                       }\r
+\r
+                       if (dataChanged) \r
+                               otherCtx.putImageData(dataDesc2,0,0);\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.save();\r
+                       ctx.globalAlpha = amount;\r
+                       ctx.drawImage(\r
+                               otherCanvas,\r
+                               0,0,rect.width,rect.height,\r
+                               rect.left,rect.top,rect.width,rect.height\r
+                       );\r
+                       ctx.globalAlpha = 1;\r
+                       ctx.restore();\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Blur filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.blur = {\r
+       process : function(params) {\r
+\r
+               if (typeof params.options.fixMargin == "undefined")\r
+                       params.options.fixMargin = true;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       /*\r
+                       var kernel = [\r
+                               [0.5,   1,      0.5],\r
+                               [1,     2,      1],\r
+                               [0.5,   1,      0.5]\r
+                       ];\r
+                       */\r
+\r
+                       var kernel = [\r
+                               [0,     1,      0],\r
+                               [1,     2,      1],\r
+                               [0,     1,      0]\r
+                       ];\r
+\r
+                       var weight = 0;\r
+                       for (var i=0;i<3;i++) {\r
+                               for (var j=0;j<3;j++) {\r
+                                       weight += kernel[i][j];\r
+                               }\r
+                       }\r
+\r
+                       weight = 1 / (weight*2);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+       \r
+                                       data[offset] = (\r
+                                               /*\r
+                                               dataCopy[offsetPrev - 4]\r
+                                               + dataCopy[offsetPrev+4] \r
+                                               + dataCopy[offsetNext - 4]\r
+                                               + dataCopy[offsetNext+4]\r
+                                               + \r
+                                               */\r
+                                               (dataCopy[offsetPrev]\r
+                                               + dataCopy[offset-4]\r
+                                               + dataCopy[offset+4]\r
+                                               + dataCopy[offsetNext])         * 2\r
+                                               + dataCopy[offset]              * 4\r
+                                               ) * weight;\r
+\r
+                                       data[offset+1] = (\r
+                                               /*\r
+                                               dataCopy[offsetPrev - 3]\r
+                                               + dataCopy[offsetPrev+5] \r
+                                               + dataCopy[offsetNext - 3] \r
+                                               + dataCopy[offsetNext+5]\r
+                                               + \r
+                                               */\r
+                                               (dataCopy[offsetPrev+1]\r
+                                               + dataCopy[offset-3]\r
+                                               + dataCopy[offset+5]\r
+                                               + dataCopy[offsetNext+1])       * 2\r
+                                               + dataCopy[offset+1]            * 4\r
+                                               ) * weight;\r
+\r
+                                       data[offset+2] = (\r
+                                               /*\r
+                                               dataCopy[offsetPrev - 2] \r
+                                               + dataCopy[offsetPrev+6] \r
+                                               + dataCopy[offsetNext - 2] \r
+                                               + dataCopy[offsetNext+6]\r
+                                               + \r
+                                               */\r
+                                               (dataCopy[offsetPrev+2]\r
+                                               + dataCopy[offset-2]\r
+                                               + dataCopy[offset+6]\r
+                                               + dataCopy[offsetNext+2])       * 2\r
+                                               + dataCopy[offset+2]            * 4\r
+                                               ) * weight;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";\r
+\r
+                       if (params.options.fixMargin) {\r
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";\r
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";\r
+                       }\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Blur Fast - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.blurfast = {\r
+       process : function(params) {\r
+\r
+               var amount = parseFloat(params.options.amount)||0;\r
+               var clear = !!(params.options.clear && params.options.clear != "false");\r
+\r
+               amount = Math.max(0,Math.min(5,amount));\r
+\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.save();\r
+                       ctx.beginPath();\r
+                       ctx.rect(rect.left, rect.top, rect.width, rect.height);\r
+                       ctx.clip();\r
+\r
+                       var scale = 2;\r
+                       var smallWidth = Math.round(params.width / scale);\r
+                       var smallHeight = Math.round(params.height / scale);\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = smallWidth;\r
+                       copy.height = smallHeight;\r
+\r
+                       var clear = false;\r
+                       var steps = Math.round(amount * 20);\r
+\r
+                       var copyCtx = copy.getContext("2d");\r
+                       for (var i=0;i<steps;i++) {\r
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
+       \r
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
+       \r
+                               copyCtx.drawImage(\r
+                                       params.canvas,\r
+                                       0,0,params.width,params.height,\r
+                                       0,0,scaledWidth,scaledHeight\r
+                               );\r
+       \r
+                               if (clear)\r
+                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);\r
+       \r
+                               ctx.drawImage(\r
+                                       copy,\r
+                                       0,0,scaledWidth,scaledHeight,\r
+                                       0,0,params.width,params.height\r
+                               );\r
+                       }\r
+\r
+                       ctx.restore();\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       var radius = 10 * amount;\r
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";\r
+\r
+                       if (params.options.fixMargin || 1) {\r
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";\r
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";\r
+                       }\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Brightness/Contrast filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.brightness = {\r
+\r
+       process : function(params) {\r
+\r
+               var brightness = parseInt(params.options.brightness,10) || 0;\r
+               var contrast = parseFloat(params.options.contrast)||0;\r
+               var legacy = !!(params.options.legacy && params.options.legacy != "false");\r
+\r
+               if (legacy) {\r
+                       brightness = Math.min(150,Math.max(-150,brightness));\r
+               } else {\r
+                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;\r
+               }\r
+               contrast = Math.max(0,contrast+1);\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var p = w*h;\r
+                       var pix = p*4, pix1, pix2;\r
+\r
+                       var mul, add;\r
+                       if (contrast != 1) {\r
+                               if (legacy) {\r
+                                       mul = contrast;\r
+                                       add = (brightness - 128) * contrast + 128;\r
+                               } else {\r
+                                       mul = brightMul * contrast;\r
+                                       add = - contrast * 128 + 128;\r
+                               }\r
+                       } else {  // this if-then is not necessary anymore, is it?\r
+                               if (legacy) {\r
+                                       mul = 1;\r
+                                       add = brightness;\r
+                               } else {\r
+                                       mul = brightMul;\r
+                                       add = 0;\r
+                               }\r
+                       }\r
+                       var r, g, b;\r
+                       while (p--) {\r
+                               if ((r = data[pix-=4] * mul + add) > 255 )\r
+                                       data[pix] = 255;\r
+                               else if (r < 0)\r
+                                       data[pix] = 0;\r
+                               else\r
+                                       data[pix] = r;\r
+\r
+                               if ((g = data[pix1=pix+1] * mul + add) > 255 ) \r
+                                       data[pix1] = 255;\r
+                               else if (g < 0)\r
+                                       data[pix1] = 0;\r
+                               else\r
+                                       data[pix1] = g;\r
+\r
+                               if ((b = data[pix2=pix+2] * mul + add) > 255 ) \r
+                                       data[pix2] = 255;\r
+                               else if (b < 0)\r
+                                       data[pix2] = 0;\r
+                               else\r
+                                       data[pix2] = b;\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Color adjust filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.coloradjust = {\r
+\r
+       process : function(params) {\r
+               var red = parseFloat(params.options.red) || 0;\r
+               var green = parseFloat(params.options.green) || 0;\r
+               var blue = parseFloat(params.options.blue) || 0;\r
+\r
+               red = Math.round(red*255);\r
+               green = Math.round(green*255);\r
+               blue = Math.round(blue*255);\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+\r
+                       var p = rect.width*rect.height;\r
+                       var pix = p*4, pix1, pix2;\r
+\r
+                       var r, g, b;\r
+                       while (p--) {\r
+                               pix -= 4;\r
+\r
+                               if (red) {\r
+                                       if ((r = data[pix] + red) < 0 ) \r
+                                               data[pix] = 0;\r
+                                       else if (r > 255 ) \r
+                                               data[pix] = 255;\r
+                                       else\r
+                                               data[pix] = r;\r
+                               }\r
+\r
+                               if (green) {\r
+                                       if ((g = data[pix1=pix+1] + green) < 0 ) \r
+                                               data[pix1] = 0;\r
+                                       else if (g > 255 ) \r
+                                               data[pix1] = 255;\r
+                                       else\r
+                                               data[pix1] = g;\r
+                               }\r
+\r
+                               if (blue) {\r
+                                       if ((b = data[pix2=pix+2] + blue) < 0 ) \r
+                                               data[pix2] = 0;\r
+                                       else if (b > 255 ) \r
+                                               data[pix2] = 255;\r
+                                       else\r
+                                               data[pix2] = b;\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Histogram - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+\r
+Pixastic.Actions.colorhistogram = {\r
+\r
+       array256 : function(default_value) {\r
+               arr = [];\r
+               for (var i=0; i<256; i++) { arr[i] = default_value; }\r
+               return arr\r
+       },\r
\r
+       process : function(params) {\r
+               var values = [];\r
+               if (typeof params.options.returnValue != "object") {\r
+                       params.options.returnValue = {rvals:[], gvals:[], bvals:[]};\r
+               }\r
+               var paint = !!(params.options.paint);\r
+\r
+               var returnValue = params.options.returnValue;\r
+               if (typeof returnValue.values != "array") {\r
+                       returnValue.rvals = [];\r
+                       returnValue.gvals = [];\r
+                       returnValue.bvals = [];\r
+               }\r
\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       params.useData = false;\r
\r
+                       var rvals = this.array256(0);\r
+                       var gvals = this.array256(0);\r
+                       var bvals = this.array256(0);\r
\r
+                       var rect = params.options.rect;\r
+\r
+                       var p = rect.width*rect.height;\r
+                       var pix = p*4;\r
+                       while (p--) {\r
+                               rvals[data[pix-=4]]++;\r
+                               gvals[data[pix+1]]++;\r
+                               bvals[data[pix+2]]++;\r
+                       }\r
\r
+                       returnValue.rvals = rvals;\r
+                       returnValue.gvals = gvals;\r
+                       returnValue.bvals = bvals;\r
+\r
+                       if (paint) {\r
+                               var ctx = params.canvas.getContext("2d");\r
+                               var vals = [rvals, gvals, bvals];\r
+                               for (var v=0;v<3;v++) {\r
+                                       var yoff = (v+1) * params.height / 3;\r
+                                       var maxValue = 0;\r
+                                       for (var i=0;i<256;i++) {\r
+                                               if (vals[v][i] > maxValue)\r
+                                                       maxValue = vals[v][i];\r
+                                       }\r
+                                       var heightScale = params.height / 3 / maxValue;\r
+                                       var widthScale = params.width / 256;\r
+                                       if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";\r
+                                       else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";\r
+                                       else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";\r
+                                       for (var i=0;i<256;i++) {\r
+                                               ctx.fillRect(\r
+                                                       i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,\r
+                                                       widthScale, vals[v][i] * heightScale\r
+                                               );\r
+                                       }\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Crop - v0.1.1\r
+ * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.crop = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var width = rect.width;\r
+                       var height = rect.height;\r
+                       var top = rect.top;\r
+                       var left = rect.left;\r
+\r
+                       if (typeof params.options.left != "undefined")\r
+                               left = parseInt(params.options.left,10);\r
+                       if (typeof params.options.top != "undefined")\r
+                               top = parseInt(params.options.top,10);\r
+                       if (typeof params.options.height != "undefined")\r
+                               width = parseInt(params.options.width,10);\r
+                       if (typeof params.options.height != "undefined")\r
+                               height = parseInt(params.options.height,10);\r
+\r
+                       if (left < 0) left = 0;\r
+                       if (left > params.width-1) left = params.width-1;\r
+\r
+                       if (top < 0) top = 0;\r
+                       if (top > params.height-1) top = params.height-1;\r
+\r
+                       if (width < 1) width = 1;\r
+                       if (left + width > params.width)\r
+                               width = params.width - left;\r
+\r
+                       if (height < 1) height = 1;\r
+                       if (top + height > params.height)\r
+                               height = params.height - top;\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = params.width;\r
+                       copy.height = params.height;\r
+                       copy.getContext("2d").drawImage(params.canvas,0,0);\r
+\r
+                       params.canvas.width = width;\r
+                       params.canvas.height = height;\r
+                       params.canvas.getContext("2d").clearRect(0,0,width,height);\r
+\r
+                       params.canvas.getContext("2d").drawImage(copy,\r
+                               left,top,width,height,\r
+                               0,0,width,height\r
+                       );\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Desaturation filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.desaturate = {\r
+\r
+       process : function(params) {\r
+               var useAverage = !!(params.options.average && params.options.average != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var p = w*h;\r
+                       var pix = p*4, pix1, pix2;\r
+\r
+                       if (useAverage) {\r
+                               while (p--) \r
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3\r
+                       } else {\r
+                               while (p--)\r
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);\r
+                       }\r
+                       return true;\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " gray";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Edge detection filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.edges = {\r
+       process : function(params) {\r
+\r
+               var mono = !!(params.options.mono && params.options.mono != "false");\r
+               var invert = !!(params.options.invert && params.options.invert != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var c = -1/8;\r
+                       var kernel = [\r
+                               [c,     c,      c],\r
+                               [c,     1,      c],\r
+                               [c,     c,      c]\r
+                       ];\r
+\r
+                       weight = 1/c;\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+       \r
+                                       var r = ((dataCopy[offsetPrev-4]\r
+                                               + dataCopy[offsetPrev]\r
+                                               + dataCopy[offsetPrev+4]\r
+                                               + dataCopy[offset-4]\r
+                                               + dataCopy[offset+4]\r
+                                               + dataCopy[offsetNext-4]\r
+                                               + dataCopy[offsetNext]\r
+                                               + dataCopy[offsetNext+4]) * c\r
+                                               + dataCopy[offset]\r
+                                               ) \r
+                                               * weight;\r
+       \r
+                                       var g = ((dataCopy[offsetPrev-3]\r
+                                               + dataCopy[offsetPrev+1]\r
+                                               + dataCopy[offsetPrev+5]\r
+                                               + dataCopy[offset-3]\r
+                                               + dataCopy[offset+5]\r
+                                               + dataCopy[offsetNext-3]\r
+                                               + dataCopy[offsetNext+1]\r
+                                               + dataCopy[offsetNext+5]) * c\r
+                                               + dataCopy[offset+1])\r
+                                               * weight;\r
+       \r
+                                       var b = ((dataCopy[offsetPrev-2]\r
+                                               + dataCopy[offsetPrev+2]\r
+                                               + dataCopy[offsetPrev+6]\r
+                                               + dataCopy[offset-2]\r
+                                               + dataCopy[offset+6]\r
+                                               + dataCopy[offsetNext-2]\r
+                                               + dataCopy[offsetNext+2]\r
+                                               + dataCopy[offsetNext+6]) * c\r
+                                               + dataCopy[offset+2])\r
+                                               * weight;\r
+\r
+                                       if (mono) {\r
+                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;\r
+                                               if (invert) brightness = 255 - brightness;\r
+                                               if (brightness < 0 ) brightness = 0;\r
+                                               if (brightness > 255 ) brightness = 255;\r
+                                               r = g = b = brightness;\r
+                                       } else {\r
+                                               if (invert) {\r
+                                                       r = 255 - r;\r
+                                                       g = 255 - g;\r
+                                                       b = 255 - b;\r
+                                               }\r
+                                               if (r < 0 ) r = 0;\r
+                                               if (g < 0 ) g = 0;\r
+                                               if (b < 0 ) b = 0;\r
+                                               if (r > 255 ) r = 255;\r
+                                               if (g > 255 ) g = 255;\r
+                                               if (b > 255 ) b = 255;\r
+                                       }\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Edge detection 2 - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ * \r
+ * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!\r
+ *\r
+ */\r
+\r
+Pixastic.Actions.edges2 = {\r
+       process : function(params) {\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w * 4;\r
+                       var pixel = w4 + 4; // Start at (1,1)\r
+                       var hm1 = h - 1;\r
+                       var wm1 = w - 1;\r
+                       for (var y = 1; y < hm1; ++y) {\r
+                               // Prepare initial cached values for current row\r
+                               var centerRow = pixel - 4;\r
+                               var priorRow = centerRow - w4;\r
+                               var nextRow = centerRow + w4;\r
+                               \r
+                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];\r
+                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
+                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
+                               \r
+                               var rp = dataCopy[priorRow += 2];\r
+                               var gp = dataCopy[++priorRow];\r
+                               var bp = dataCopy[++priorRow];\r
+                               \r
+                               var rc = dataCopy[centerRow += 2];\r
+                               var gc = dataCopy[++centerRow];\r
+                               var bc = dataCopy[++centerRow];\r
+                               \r
+                               var rn = dataCopy[nextRow += 2];\r
+                               var gn = dataCopy[++nextRow];\r
+                               var bn = dataCopy[++nextRow];\r
+                               \r
+                               var r2 = - rp - rc - rn;\r
+                               var g2 = - gp - gc - gn;\r
+                               var b2 = - bp - bc - bn;\r
+                               \r
+                               // Main convolution loop\r
+                               for (var x = 1; x < wm1; ++x) {\r
+                                       centerRow = pixel + 4;\r
+                                       priorRow = centerRow - w4;\r
+                                       nextRow = centerRow + w4;\r
+                                       \r
+                                       var r = 127 + r1 - rp - (rc * -8) - rn;\r
+                                       var g = 127 + g1 - gp - (gc * -8) - gn;\r
+                                       var b = 127 + b1 - bp - (bc * -8) - bn;\r
+                                       \r
+                                       r1 = r2;\r
+                                       g1 = g2;\r
+                                       b1 = b2;\r
+                                       \r
+                                       rp = dataCopy[  priorRow];\r
+                                       gp = dataCopy[++priorRow];\r
+                                       bp = dataCopy[++priorRow];\r
+                                       \r
+                                       rc = dataCopy[  centerRow];\r
+                                       gc = dataCopy[++centerRow];\r
+                                       bc = dataCopy[++centerRow];\r
+                                       \r
+                                       rn = dataCopy[  nextRow];\r
+                                       gn = dataCopy[++nextRow];\r
+                                       bn = dataCopy[++nextRow];\r
+                                       \r
+                                       r += (r2 = - rp - rc - rn);\r
+                                       g += (g2 = - gp - gc - gn);\r
+                                       b += (b2 = - bp - bc - bn);\r
+\r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+                                       if (r < 0) r = 0;\r
+                                       if (g < 0) g = 0;\r
+                                       if (b < 0) b = 0;\r
+\r
+                                       data[pixel] = r;\r
+                                       data[++pixel] = g;\r
+                                       data[++pixel] = b;\r
+                                       //data[++pixel] = 255; // alpha\r
+\r
+                                       pixel+=2;\r
+                               }\r
+                               pixel += 8;\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Emboss filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.emboss = {\r
+       process : function(params) {\r
+\r
+               var strength = parseFloat(params.options.strength)||1;\r
+               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;\r
+               var direction = params.options.direction||"topleft";\r
+               var blend = !!(params.options.blend && params.options.blend != "false");\r
+\r
+               var dirY = 0;\r
+               var dirX = 0;\r
+\r
+               switch (direction) {\r
+                       case "topleft":                 // top left\r
+                               dirY = -1;\r
+                               dirX = -1;\r
+                               break;\r
+                       case "top":                     // top\r
+                               dirY = -1;\r
+                               dirX = 0;\r
+                               break;\r
+                       case "topright":                        // top right\r
+                               dirY = -1;\r
+                               dirX = 1;\r
+                               break;\r
+                       case "right":                   // right\r
+                               dirY = 0;\r
+                               dirX = 1;\r
+                               break;\r
+                       case "bottomright":                     // bottom right\r
+                               dirY = 1;\r
+                               dirX = 1;\r
+                               break;\r
+                       case "bottom":                  // bottom\r
+                               dirY = 1;\r
+                               dirX = 0;\r
+                               break;\r
+                       case "bottomleft":                      // bottom left\r
+                               dirY = 1;\r
+                               dirX = -1;\r
+                               break;\r
+                       case "left":                    // left\r
+                               dirY = 0;\r
+                               dirX = -1;\r
+                               break;\r
+               }\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var invertAlpha = !!params.options.invertAlpha;\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var otherY = dirY;\r
+                               if (y + otherY < 1) otherY = 0;\r
+                               if (y + otherY > h) otherY = 0;\r
+\r
+                               var offsetYOther = (y-1+otherY)*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                               var offset = offsetY + (x-1)*4;\r
+\r
+                                               var otherX = dirX;\r
+                                               if (x + otherX < 1) otherX = 0;\r
+                                               if (x + otherX > w) otherX = 0;\r
+\r
+                                               var offsetOther = offsetYOther + (x-1+otherX)*4;\r
+\r
+                                               var dR = dataCopy[offset] - dataCopy[offsetOther];\r
+                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];\r
+                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];\r
+\r
+                                               var dif = dR;\r
+                                               var absDif = dif > 0 ? dif : -dif;\r
+\r
+                                               var absG = dG > 0 ? dG : -dG;\r
+                                               var absB = dB > 0 ? dB : -dB;\r
+\r
+                                               if (absG > absDif) {\r
+                                                       dif = dG;\r
+                                               }\r
+                                               if (absB > absDif) {\r
+                                                       dif = dB;\r
+                                               }\r
+\r
+                                               dif *= strength;\r
+\r
+                                               if (blend) {\r
+                                                       var r = data[offset] + dif;\r
+                                                       var g = data[offset+1] + dif;\r
+                                                       var b = data[offset+2] + dif;\r
+\r
+                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);\r
+                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);\r
+                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);\r
+                                               } else {\r
+                                                       var grey = greyLevel - dif;\r
+                                                       if (grey < 0) {\r
+                                                               grey = 0;\r
+                                                       } else if (grey > 255) {\r
+                                                               grey = 255;\r
+                                                       }\r
+\r
+                                                       data[offset] = data[offset+1] = data[offset+2] = grey;\r
+                                               }\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+\r
+}\r
+/*\r
+ * Pixastic Lib - Flip - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.flip = {\r
+       process : function(params) {\r
+               var rect = params.options.rect;\r
+               var copyCanvas = document.createElement("canvas");\r
+               copyCanvas.width = rect.width;\r
+               copyCanvas.height = rect.height;\r
+               copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
+\r
+               var ctx = params.canvas.getContext("2d");\r
+               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+\r
+               if (params.options.axis == "horizontal") {\r
+                       ctx.scale(-1,1);\r
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
+               } else {\r
+                       ctx.scale(1,-1);\r
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
+               }\r
+\r
+               params.useData = false;\r
+\r
+               return true;            \r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Horizontal flip - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.fliph = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+                       var copyCanvas = document.createElement("canvas");\r
+                       copyCanvas.width = rect.width;\r
+                       copyCanvas.height = rect.height;\r
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+                       ctx.scale(-1,1);\r
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
+                       params.useData = false;\r
+\r
+                       return true;            \r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " fliph";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Vertical flip - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.flipv = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+                       var copyCanvas = document.createElement("canvas");\r
+                       copyCanvas.width = rect.width;\r
+                       copyCanvas.height = rect.height;\r
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+                       ctx.scale(1,-1);\r
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
+                       params.useData = false;\r
+\r
+                       return true;            \r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " flipv";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Glow - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+\r
+Pixastic.Actions.glow = {\r
+       process : function(params) {\r
+\r
+               var amount = (parseFloat(params.options.amount)||0);\r
+               var blurAmount = parseFloat(params.options.radius)||0;\r
+\r
+               amount = Math.min(1,Math.max(0,amount));\r
+               blurAmount = Math.min(5,Math.max(0,blurAmount));\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var blurCanvas = document.createElement("canvas");\r
+                       blurCanvas.width = params.width;\r
+                       blurCanvas.height = params.height;\r
+                       var blurCtx = blurCanvas.getContext("2d");\r
+                       blurCtx.drawImage(params.canvas,0,0);\r
+\r
+                       var scale = 2;\r
+                       var smallWidth = Math.round(params.width / scale);\r
+                       var smallHeight = Math.round(params.height / scale);\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = smallWidth;\r
+                       copy.height = smallHeight;\r
+\r
+                       var clear = true;\r
+                       var steps = Math.round(blurAmount * 20);\r
+\r
+                       var copyCtx = copy.getContext("2d");\r
+                       for (var i=0;i<steps;i++) {\r
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
+       \r
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
+       \r
+                               copyCtx.drawImage(\r
+                                       blurCanvas,\r
+                                       0,0,params.width,params.height,\r
+                                       0,0,scaledWidth,scaledHeight\r
+                               );\r
+       \r
+                               blurCtx.clearRect(0,0,params.width,params.height);\r
+       \r
+                               blurCtx.drawImage(\r
+                                       copy,\r
+                                       0,0,scaledWidth,scaledHeight,\r
+                                       0,0,params.width,params.height\r
+                               );\r
+                       }\r
+\r
+                       var data = Pixastic.prepareData(params);\r
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var r = data[offset] + amount * blurData[offset];\r
+                                       var g = data[offset+1] + amount * blurData[offset+1];\r
+                                       var b = data[offset+2] + amount * blurData[offset+2];\r
+       \r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+                                       if (r < 0) r = 0;\r
+                                       if (g < 0) g = 0;\r
+                                       if (b < 0) b = 0;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Histogram - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.histogram = {\r
+       process : function(params) {\r
+\r
+               var average = !!(params.options.average && params.options.average != "false");\r
+               var paint = !!(params.options.paint && params.options.paint != "false");\r
+               var color = params.options.color || "rgba(255,255,255,0.5)";\r
+               var values = [];\r
+               if (typeof params.options.returnValue != "object") {\r
+                       params.options.returnValue = {values:[]};\r
+               }\r
+               var returnValue = params.options.returnValue;\r
+               if (typeof returnValue.values != "array") {\r
+                       returnValue.values = [];\r
+               }\r
+               values = returnValue.values;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       params.useData = false;\r
+\r
+                       for (var i=0;i<256;i++) {\r
+                               values[i] = 0;\r
+                       }\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+                                       var brightness = average ? \r
+                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)\r
+                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);\r
+                                       values[brightness]++;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       if (paint) {\r
+                               var maxValue = 0;\r
+                               for (var i=0;i<256;i++) {\r
+                                       if (values[i] > maxValue) {\r
+                                               maxValue = values[i];\r
+                                       }\r
+                               }\r
+                               var heightScale = params.height / maxValue;\r
+                               var widthScale = params.width / 256;\r
+                               var ctx = params.canvas.getContext("2d");\r
+                               ctx.fillStyle = color;\r
+                               for (var i=0;i<256;i++) {\r
+                                       ctx.fillRect(\r
+                                               i * widthScale, params.height - heightScale * values[i],\r
+                                               widthScale, values[i] * heightScale\r
+                                       );\r
+                               }\r
+                       }\r
+\r
+                       returnValue.values = values;\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - HSL Adjust  - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.hsl = {\r
+       process : function(params) {\r
+\r
+               var hue = parseInt(params.options.hue,10)||0;\r
+               var saturation = (parseInt(params.options.saturation,10)||0) / 100;\r
+               var lightness = (parseInt(params.options.lightness,10)||0) / 100;\r
+\r
+\r
+               // this seems to give the same result as Photoshop\r
+               if (saturation < 0) {\r
+                       var satMul = 1+saturation;\r
+               } else {\r
+                       var satMul = 1+saturation*2;\r
+               }\r
+\r
+               hue = (hue%360) / 360;\r
+               var hue6 = hue * 6;\r
+\r
+               var rgbDiv = 1 / 255;\r
+\r
+               var light255 = lightness * 255;\r
+               var lightp1 = 1 + lightness;\r
+               var lightm1 = 1 - lightness;\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var r = data[offset];\r
+                                       var g = data[offset+1];\r
+                                       var b = data[offset+2];\r
+\r
+                                       if (hue != 0 || saturation != 0) {\r
+                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. \r
+                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.\r
+                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.\r
+                                               var vs = r;\r
+                                               if (g > vs) vs = g;\r
+                                               if (b > vs) vs = b;\r
+                                               var ms = r;\r
+                                               if (g < ms) ms = g;\r
+                                               if (b < ms) ms = b;\r
+                                               var vm = (vs-ms);\r
+                                               var l = (ms+vs)/255 * 0.5;\r
+                                               if (l > 0) {\r
+                                                       if (vm > 0) {\r
+                                                               if (l <= 0.5) {\r
+                                                                       var s = vm / (vs+ms) * satMul;\r
+                                                                       if (s > 1) s = 1;\r
+                                                                       var v = (l * (1+s));\r
+                                                               } else {\r
+                                                                       var s = vm / (510-vs-ms) * satMul;\r
+                                                                       if (s > 1) s = 1;\r
+                                                                       var v = (l+s - l*s);\r
+                                                               }\r
+                                                               if (r == vs) {\r
+                                                                       if (g == ms)\r
+                                                                               var h = 5 + ((vs-b)/vm) + hue6;\r
+                                                                       else\r
+                                                                               var h = 1 - ((vs-g)/vm) + hue6;\r
+                                                               } else if (g == vs) {\r
+                                                                       if (b == ms)\r
+                                                                               var h = 1 + ((vs-r)/vm) + hue6;\r
+                                                                       else\r
+                                                                               var h = 3 - ((vs-b)/vm) + hue6;\r
+                                                               } else {\r
+                                                                       if (r == ms)\r
+                                                                               var h = 3 + ((vs-g)/vm) + hue6;\r
+                                                                       else\r
+                                                                               var h = 5 - ((vs-r)/vm) + hue6;\r
+                                                               }\r
+                                                               if (h < 0) h+=6;\r
+                                                               if (h >= 6) h-=6;\r
+                                                               var m = (l+l-v);\r
+                                                               var sextant = h>>0;\r
+                                                               switch (sextant) {\r
+                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;\r
+                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;\r
+                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;\r
+                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;\r
+                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;\r
+                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                                       if (lightness < 0) {\r
+                                               r *= lightp1;\r
+                                               g *= lightp1;\r
+                                               b *= lightp1;\r
+                                       } else if (lightness > 0) {\r
+                                               r = r * lightm1 + light255;\r
+                                               g = g * lightm1 + light255;\r
+                                               b = b * lightm1 + light255;\r
+                                       }\r
+\r
+                                       if (r < 0) r = 0;\r
+                                       if (g < 0) g = 0;\r
+                                       if (b < 0) b = 0;\r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+\r
+}\r
+/*\r
+ * Pixastic Lib - Invert filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.invert = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       var invertAlpha = !!params.options.invertAlpha;\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+                                       data[offset] = 255 - data[offset];\r
+                                       data[offset+1] = 255 - data[offset+1];\r
+                                       data[offset+2] = 255 - data[offset+2];\r
+                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " invert";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Laplace filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.laplace = {\r
+       process : function(params) {\r
+\r
+               var strength = 1.0;\r
+               var invert = !!(params.options.invert && params.options.invert != "false");\r
+               var contrast = parseFloat(params.options.edgeStrength)||0;\r
+\r
+               var greyLevel = parseInt(params.options.greyLevel)||0;\r
+\r
+               contrast = -contrast;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var kernel = [\r
+                               [-1,    -1,     -1],\r
+                               [-1,    8,      -1],\r
+                               [-1,    -1,     -1]\r
+                       ];\r
+\r
+                       var weight = 1/8;\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+       \r
+                                       var r = ((-dataCopy[offsetPrev-4]\r
+                                               - dataCopy[offsetPrev]\r
+                                               - dataCopy[offsetPrev+4]\r
+                                               - dataCopy[offset-4]\r
+                                               - dataCopy[offset+4]\r
+                                               - dataCopy[offsetNext-4]\r
+                                               - dataCopy[offsetNext]\r
+                                               - dataCopy[offsetNext+4])\r
+                                               + dataCopy[offset] * 8) \r
+                                               * weight;\r
+       \r
+                                       var g = ((-dataCopy[offsetPrev-3]\r
+                                               - dataCopy[offsetPrev+1]\r
+                                               - dataCopy[offsetPrev+5]\r
+                                               - dataCopy[offset-3]\r
+                                               - dataCopy[offset+5]\r
+                                               - dataCopy[offsetNext-3]\r
+                                               - dataCopy[offsetNext+1]\r
+                                               - dataCopy[offsetNext+5])\r
+                                               + dataCopy[offset+1] * 8)\r
+                                               * weight;\r
+       \r
+                                       var b = ((-dataCopy[offsetPrev-2]\r
+                                               - dataCopy[offsetPrev+2]\r
+                                               - dataCopy[offsetPrev+6]\r
+                                               - dataCopy[offset-2]\r
+                                               - dataCopy[offset+6]\r
+                                               - dataCopy[offsetNext-2]\r
+                                               - dataCopy[offsetNext+2]\r
+                                               - dataCopy[offsetNext+6])\r
+                                               + dataCopy[offset+2] * 8)\r
+                                               * weight;\r
+\r
+                                       var brightness = ((r + g + b)/3) + greyLevel;\r
+\r
+                                       if (contrast != 0) {\r
+                                               if (brightness > 127) {\r
+                                                       brightness += ((brightness + 1) - 128) * contrast;\r
+                                               } else if (brightness < 127) {\r
+                                                       brightness -= (brightness + 1) * contrast;\r
+                                               }\r
+                                       }\r
+                                       if (invert) {\r
+                                               brightness = 255 - brightness;\r
+                                       }\r
+                                       if (brightness < 0 ) brightness = 0;\r
+                                       if (brightness > 255 ) brightness = 255;\r
+\r
+                                       data[offset] = data[offset+1] = data[offset+2] = brightness;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Lighten filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.lighten = {\r
+\r
+       process : function(params) {\r
+               var amount = parseFloat(params.options.amount) || 0;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       var r = data[offset];\r
+                                       var g = data[offset+1];\r
+                                       var b = data[offset+2];\r
+\r
+                                       r += r*amount;\r
+                                       g += g*amount;\r
+                                       b += b*amount;\r
+\r
+                                       if (r < 0 ) r = 0;\r
+                                       if (g < 0 ) g = 0;\r
+                                       if (b < 0 ) b = 0;\r
+                                       if (r > 255 ) r = 255;\r
+                                       if (g > 255 ) g = 255;\r
+                                       if (b > 255 ) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       var img = params.image;\r
+                       if (amount < 0) {\r
+                               img.style.filter += " light()";\r
+                               img.filters[img.filters.length-1].addAmbient(\r
+                                       255,255,255,\r
+                                       100 * -amount\r
+                               );\r
+                       } else if (amount > 0) {\r
+                               img.style.filter += " light()";\r
+                               img.filters[img.filters.length-1].addAmbient(\r
+                                       255,255,255,\r
+                                       100\r
+                               );\r
+                               img.filters[img.filters.length-1].addAmbient(\r
+                                       255,255,255,\r
+                                       100 * amount\r
+                               );\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Mosaic filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.mosaic = {\r
+\r
+       process : function(params) {\r
+               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+\r
+                       var pixel = document.createElement("canvas");\r
+                       pixel.width = pixel.height = 1;\r
+                       var pixelCtx = pixel.getContext("2d");\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = w;\r
+                       copy.height = h;\r
+                       var copyCtx = copy.getContext("2d");\r
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
+\r
+                       for (var y=0;y<h;y+=blockSize) {\r
+                               for (var x=0;x<w;x+=blockSize) {\r
+                                       var blockSizeX = blockSize;\r
+                                       var blockSizeY = blockSize;\r
+               \r
+                                       if (blockSizeX + x > w)\r
+                                               blockSizeX = w - x;\r
+                                       if (blockSizeY + y > h)\r
+                                               blockSizeY = h - y;\r
+\r
+                                       pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);\r
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
+                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);\r
+                               }\r
+                       }\r
+                       params.useData = false;\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Noise filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.noise = {\r
+\r
+       process : function(params) {\r
+               var amount = 0;\r
+               var strength = 0;\r
+               var mono = false;\r
+\r
+               if (typeof params.options.amount != "undefined")\r
+                       amount = parseFloat(params.options.amount)||0;\r
+               if (typeof params.options.strength != "undefined")\r
+                       strength = parseFloat(params.options.strength)||0;\r
+               if (typeof params.options.mono != "undefined")\r
+                       mono = !!(params.options.mono && params.options.mono != "false");\r
+\r
+               amount = Math.max(0,Math.min(1,amount));\r
+               strength = Math.max(0,Math.min(1,strength));\r
+\r
+               var noise = 128 * strength;\r
+               var noise2 = noise / 2;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       var random = Math.random;\r
+\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+                                       if (random() < amount) {\r
+                                               if (mono) {\r
+                                                       var pixelNoise = - noise2 + random() * noise;\r
+                                                       var r = data[offset] + pixelNoise;\r
+                                                       var g = data[offset+1] + pixelNoise;\r
+                                                       var b = data[offset+2] + pixelNoise;\r
+                                               } else {\r
+                                                       var r = data[offset] - noise2 + (random() * noise);\r
+                                                       var g = data[offset+1] - noise2 + (random() * noise);\r
+                                                       var b = data[offset+2] - noise2 + (random() * noise);\r
+                                               }\r
+\r
+                                               if (r < 0 ) r = 0;\r
+                                               if (g < 0 ) g = 0;\r
+                                               if (b < 0 ) b = 0;\r
+                                               if (r > 255 ) r = 255;\r
+                                               if (g > 255 ) g = 255;\r
+                                               if (b > 255 ) b = 255;\r
+\r
+                                               data[offset] = r;\r
+                                               data[offset+1] = g;\r
+                                               data[offset+2] = b;\r
+                                       }\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Posterize effect - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.posterize = {\r
+\r
+       process : function(params) {\r
+\r
+               \r
+               var numLevels = 256;\r
+               if (typeof params.options.levels != "undefined")\r
+                       numLevels = parseInt(params.options.levels,10)||1;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       numLevels = Math.max(2,Math.min(256,numLevels));\r
+       \r
+                       var numAreas = 256 / numLevels;\r
+                       var numValues = 256 / (numLevels-1);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       var r = numValues * ((data[offset] / numAreas)>>0);\r
+                                       var g = numValues * ((data[offset+1] / numAreas)>>0);\r
+                                       var b = numValues * ((data[offset+2] / numAreas)>>0);\r
+\r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Pointillize filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.pointillize = {\r
+\r
+       process : function(params) {\r
+               var radius = Math.max(1,parseInt(params.options.radius,10));\r
+               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));\r
+               var noise = Math.max(0,parseFloat(params.options.noise)||0);\r
+               var transparent = !!(params.options.transparent && params.options.transparent != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       var canvasWidth = params.canvas.width;\r
+                       var canvasHeight = params.canvas.height;\r
+\r
+                       var pixel = document.createElement("canvas");\r
+                       pixel.width = pixel.height = 1;\r
+                       var pixelCtx = pixel.getContext("2d");\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = w;\r
+                       copy.height = h;\r
+                       var copyCtx = copy.getContext("2d");\r
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
+\r
+                       var diameter = radius * 2;\r
+\r
+                       if (transparent)\r
+                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+\r
+                       var noiseRadius = radius * noise;\r
+\r
+                       var dist = 1 / density;\r
+\r
+                       for (var y=0;y<h+radius;y+=diameter*dist) {\r
+                               for (var x=0;x<w+radius;x+=diameter*dist) {\r
+                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;\r
+                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;\r
+\r
+                                       var pixX = rndX - radius;\r
+                                       var pixY = rndY - radius;\r
+                                       if (pixX < 0) pixX = 0;\r
+                                       if (pixY < 0) pixY = 0;\r
+\r
+                                       var cx = rndX + rect.left;\r
+                                       var cy = rndY + rect.top;\r
+                                       if (cx < 0) cx = 0;\r
+                                       if (cx > canvasWidth) cx = canvasWidth;\r
+                                       if (cy < 0) cy = 0;\r
+                                       if (cy > canvasHeight) cy = canvasHeight;\r
+\r
+                                       var diameterX = diameter;\r
+                                       var diameterY = diameter;\r
+\r
+                                       if (diameterX + pixX > w)\r
+                                               diameterX = w - pixX;\r
+                                       if (diameterY + pixY > h)\r
+                                               diameterY = h - pixY;\r
+                                       if (diameterX < 1) diameterX = 1;\r
+                                       if (diameterY < 1) diameterY = 1;\r
+\r
+                                       pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);\r
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
+\r
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
+                                       ctx.beginPath();\r
+                                       ctx.arc(cx, cy, radius, 0, Math.PI*2, true);\r
+                                       ctx.closePath();\r
+                                       ctx.fill();\r
+                               }\r
+                       }\r
+\r
+                       params.useData = false;\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Resize - v0.1.0\r
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.resize = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var width = parseInt(params.options.width,10);\r
+                       var height = parseInt(params.options.height,10);\r
+                       var canvas = params.canvas;\r
+\r
+                       if (width < 1) width = 1;\r
+                       if (width < 2) width = 2;\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = width;\r
+                       copy.height = height;\r
+\r
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
+                       canvas.width = width;\r
+                       canvas.height = height;\r
+\r
+                       canvas.getContext("2d").drawImage(copy,0,0);\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Remove noise - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.removenoise = {\r
+       process : function(params) {\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+\r
+                                       var minR, maxR, minG, maxG, minB, maxB;\r
+\r
+                                       minR = maxR = data[offsetPrev];\r
+                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];\r
+                                       if (r1 < minR) minR = r1;\r
+                                       if (r2 < minR) minR = r2;\r
+                                       if (r3 < minR) minR = r3;\r
+                                       if (r1 > maxR) maxR = r1;\r
+                                       if (r2 > maxR) maxR = r2;\r
+                                       if (r3 > maxR) maxR = r3;\r
+\r
+                                       minG = maxG = data[offsetPrev+1];\r
+                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];\r
+                                       if (g1 < minG) minG = g1;\r
+                                       if (g2 < minG) minG = g2;\r
+                                       if (g3 < minG) minG = g3;\r
+                                       if (g1 > maxG) maxG = g1;\r
+                                       if (g2 > maxG) maxG = g2;\r
+                                       if (g3 > maxG) maxG = g3;\r
+\r
+                                       minB = maxB = data[offsetPrev+2];\r
+                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];\r
+                                       if (b1 < minB) minB = b1;\r
+                                       if (b2 < minB) minB = b2;\r
+                                       if (b3 < minB) minB = b3;\r
+                                       if (b1 > maxB) maxB = b1;\r
+                                       if (b2 > maxB) maxB = b2;\r
+                                       if (b3 > maxB) maxB = b3;\r
+\r
+                                       if (data[offset] > maxR) {\r
+                                               data[offset] = maxR;\r
+                                       } else if (data[offset] < minR) {\r
+                                               data[offset] = minR;\r
+                                       }\r
+                                       if (data[offset+1] > maxG) {\r
+                                               data[offset+1] = maxG;\r
+                                       } else if (data[offset+1] < minG) {\r
+                                               data[offset+1] = minG;\r
+                                       }\r
+                                       if (data[offset+2] > maxB) {\r
+                                               data[offset+2] = maxB;\r
+                                       } else if (data[offset+2] < minB) {\r
+                                               data[offset+2] = minB;\r
+                                       }\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Rotate - v0.1.0\r
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.rotate = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var canvas = params.canvas;\r
+\r
+                       var width = params.width;\r
+                       var height = params.height;\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = width;\r
+                       copy.height = height;\r
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
+\r
+                       var angle = -parseFloat(params.options.angle) * Math.PI / 180;\r
+\r
+                       var dimAngle = angle;\r
+                       if (dimAngle > Math.PI*0.5)\r
+                               dimAngle = Math.PI - dimAngle;\r
+                       if (dimAngle < -Math.PI*0.5)\r
+                               dimAngle = -Math.PI - dimAngle;\r
+\r
+                       var diag = Math.sqrt(width*width + height*height);\r
+\r
+                       var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));\r
+                       var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));\r
+\r
+                       var newWidth = Math.abs(Math.cos(diagAngle1) * diag);\r
+                       var newHeight = Math.abs(Math.sin(diagAngle2) * diag);\r
+\r
+                       canvas.width = newWidth;\r
+                       canvas.height = newHeight;\r
+\r
+                       var ctx = canvas.getContext("2d");\r
+                       ctx.translate(newWidth/2, newHeight/2);\r
+                       ctx.rotate(angle);\r
+                       ctx.drawImage(copy,-width/2,-height/2);\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Sepia filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.sepia = {\r
+\r
+       process : function(params) {\r
+               var mode = (parseInt(params.options.mode,10)||0);\r
+               if (mode < 0) mode = 0;\r
+               if (mode > 1) mode = 1;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       if (mode) {\r
+                                               // a bit faster, but not as good\r
+                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;\r
+                                               var r = (d + 39);\r
+                                               var g = (d + 14);\r
+                                               var b = (d - 36);\r
+                                       } else {\r
+                                               // Microsoft\r
+                                               var or = data[offset];\r
+                                               var og = data[offset+1];\r
+                                               var ob = data[offset+2];\r
+       \r
+                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);\r
+                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);\r
+                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);\r
+                                       }\r
+\r
+                                       if (r < 0) r = 0; if (r > 255) r = 255;\r
+                                       if (g < 0) g = 0; if (g > 255) g = 255;\r
+                                       if (b < 0) b = 0; if (b > 255) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Sharpen filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.sharpen = {\r
+       process : function(params) {\r
+\r
+               var strength = 0;\r
+               if (typeof params.options.amount != "undefined")\r
+                       strength = parseFloat(params.options.amount)||0;\r
+\r
+               if (strength < 0) strength = 0;\r
+               if (strength > 1) strength = 1;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var mul = 15;\r
+                       var mulOther = 1 + 3*strength;\r
+\r
+                       var kernel = [\r
+                               [0,     -mulOther,      0],\r
+                               [-mulOther,     mul,    -mulOther],\r
+                               [0,     -mulOther,      0]\r
+                       ];\r
+\r
+                       var weight = 0;\r
+                       for (var i=0;i<3;i++) {\r
+                               for (var j=0;j<3;j++) {\r
+                                       weight += kernel[i][j];\r
+                               }\r
+                       }\r
+\r
+                       weight = 1 / weight;\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       mul *= weight;\r
+                       mulOther *= weight;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w4;\r
+                               var offsetYNext = nextY*w4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+\r
+                                       var r = ((\r
+                                               - dataCopy[offsetPrev]\r
+                                               - dataCopy[offset-4]\r
+                                               - dataCopy[offset+4]\r
+                                               - dataCopy[offsetNext])         * mulOther\r
+                                               + dataCopy[offset]      * mul\r
+                                               );\r
+\r
+                                       var g = ((\r
+                                               - dataCopy[offsetPrev+1]\r
+                                               - dataCopy[offset-3]\r
+                                               - dataCopy[offset+5]\r
+                                               - dataCopy[offsetNext+1])       * mulOther\r
+                                               + dataCopy[offset+1]    * mul\r
+                                               );\r
+\r
+                                       var b = ((\r
+                                               - dataCopy[offsetPrev+2]\r
+                                               - dataCopy[offset-2]\r
+                                               - dataCopy[offset+6]\r
+                                               - dataCopy[offsetNext+2])       * mulOther\r
+                                               + dataCopy[offset+2]    * mul\r
+                                               );\r
+\r
+\r
+                                       if (r < 0 ) r = 0;\r
+                                       if (g < 0 ) g = 0;\r
+                                       if (b < 0 ) b = 0;\r
+                                       if (r > 255 ) r = 255;\r
+                                       if (g > 255 ) g = 255;\r
+                                       if (b > 255 ) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Solarize filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.solarize = {\r
+\r
+       process : function(params) {\r
+               var useAverage = !!(params.options.average && params.options.average != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       var r = data[offset];\r
+                                       var g = data[offset+1];\r
+                                       var b = data[offset+2];\r
+\r
+                                       if (r > 127) r = 255 - r;\r
+                                       if (g > 127) g = 255 - g;\r
+                                       if (b > 127) b = 255 - b;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}/*\r
+ * Pixastic Lib - USM - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+\r
+Pixastic.Actions.unsharpmask = {\r
+       process : function(params) {\r
+\r
+               var amount = (parseFloat(params.options.amount)||0);\r
+               var blurAmount = parseFloat(params.options.radius)||0;\r
+               var threshold = parseFloat(params.options.threshold)||0;\r
+\r
+               amount = Math.min(500,Math.max(0,amount)) / 2;\r
+               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;\r
+               threshold = Math.min(255,Math.max(0,threshold));\r
+\r
+               threshold--;\r
+               var thresholdNeg = -threshold;\r
+\r
+               amount *= 0.016;\r
+               amount++;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var blurCanvas = document.createElement("canvas");\r
+                       blurCanvas.width = params.width;\r
+                       blurCanvas.height = params.height;\r
+                       var blurCtx = blurCanvas.getContext("2d");\r
+                       blurCtx.drawImage(params.canvas,0,0);\r
+\r
+                       var scale = 2;\r
+                       var smallWidth = Math.round(params.width / scale);\r
+                       var smallHeight = Math.round(params.height / scale);\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = smallWidth;\r
+                       copy.height = smallHeight;\r
+\r
+                       var steps = Math.round(blurAmount * 20);\r
+\r
+                       var copyCtx = copy.getContext("2d");\r
+                       for (var i=0;i<steps;i++) {\r
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
+\r
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
+\r
+                               copyCtx.drawImage(\r
+                                       blurCanvas,\r
+                                       0,0,params.width,params.height,\r
+                                       0,0,scaledWidth,scaledHeight\r
+                               );\r
+       \r
+                               blurCtx.clearRect(0,0,params.width,params.height);\r
+       \r
+                               blurCtx.drawImage(\r
+                                       copy,\r
+                                       0,0,scaledWidth,scaledHeight,\r
+                                       0,0,params.width,params.height\r
+                               );\r
+                       }\r
+\r
+                       var data = Pixastic.prepareData(params);\r
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var difR = data[offset] - blurData[offset];\r
+                                       if (difR > threshold || difR < thresholdNeg) {\r
+                                               var blurR = blurData[offset];\r
+                                               blurR = amount * difR + blurR;\r
+                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);\r
+                                       }\r
+\r
+                                       var difG = data[offset+1] - blurData[offset+1];\r
+                                       if (difG > threshold || difG < thresholdNeg) {\r
+                                               var blurG = blurData[offset+1];\r
+                                               blurG = amount * difG + blurG;\r
+                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);\r
+                                       }\r
+\r
+                                       var difB = data[offset+2] - blurData[offset+2];\r
+                                       if (difB > threshold || difB < thresholdNeg) {\r
+                                               var blurB = blurData[offset+2];\r
+                                               blurB = amount * difB + blurB;\r
+                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);\r
+                                       }\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
diff --git a/js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.css b/js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.css
new file mode 100644 (file)
index 0000000..a487ba2
--- /dev/null
@@ -0,0 +1,423 @@
+/* http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */\r
+\r
+html, body, div, span, applet, object, iframe,\r
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,\r
+a, abbr, acronym, address, big, cite, code,\r
+del, dfn, em, font, img, ins, kbd, q, s, samp,\r
+small, strike, strong, sub, sup, tt, var,\r
+dl, dt, dd, ol, ul, li,\r
+fieldset, form, label, legend,\r
+table, caption, tbody, tfoot, thead, tr, th, td {\r
+       margin: 0;\r
+       padding: 0;\r
+       border: 0;\r
+       outline: 0;\r
+       font-weight: inherit;\r
+       font-style: inherit;\r
+       font-size: 100%;\r
+       font-family: inherit;\r
+       vertical-align: baseline;\r
+}\r
+/* remember to define focus styles! */\r
+:focus {\r
+       outline: 0;\r
+}\r
+body {\r
+       line-height: 1;\r
+       color: black;\r
+       background: white;\r
+}\r
+ol, ul {\r
+       list-style: none;\r
+}\r
+/* tables still need 'cellspacing="0"' in the markup */\r
+table {\r
+       border-collapse: separate;\r
+       border-spacing: 0;\r
+}\r
+caption, th, td {\r
+       text-align: left;\r
+       font-weight: normal;\r
+}\r
+blockquote:before, blockquote:after,\r
+q:before, q:after {\r
+       content: "";\r
+}\r
+blockquote, q {\r
+       quotes: "" "";\r
+}\r
+/* end reset */\r
+\r
+/* -----------------------\r
+ *   Base\r
+ * -----------------------\r
+ */\r
+\r
+/* main container element for editor app */\r
+#pixastic-editor {\r
+       margin : 0;\r
+       position : absolute;\r
+       left : 0;\r
+       top : 0;\r
+       padding: 0px;\r
+       width: 100%;\r
+       height: 100%;\r
+       font-family : Helvetica,Arial,sans-serif;\r
+       overflow : hidden;\r
+       z-index : 10000000;\r
+} \r
+\r
+\r
+/* -----------------------\r
+ *   Loading screen\r
+ * -----------------------\r
+ */\r
+\r
+/* container for loading screen */\r
+#loading-screen {\r
+       margin : 0;\r
+       position : absolute;\r
+       left : 0;\r
+       top : 0;\r
+       padding: 0px;\r
+       width: 100%;\r
+       height: 100%;\r
+       font-family : Helvetica,Arial,sans-serif;\r
+       overflow : hidden;\r
+       z-index : 10000000;\r
+       background-color : #111;\r
+       opacity : 0.9;\r
+       display : table;\r
+       text-align : center;\r
+} \r
+\r
+/* container for spinner in loading screen */\r
+#loading-screen-cell {\r
+       display : table-cell;\r
+       vertical-align : middle;\r
+       text-align : center;\r
+}\r
+\r
+\r
+/* -----------------------\r
+ *   Misc\r
+ * -----------------------\r
+ */\r
+\r
+\r
+// UI error dialog\r
+.ui-dialog .error-dialog {\r
+       background-color : #544;\r
+}\r
+\r
+/* loading spinner */\r
+.spinner {\r
+       width : 31px;\r
+       height : 31px;\r
+       display : inline-block;\r
+       background: url(spinner.gif);\r
+       overflow : hidden;\r
+}\r
+\r
+canvas.display-canvas,\r
+canvas.undo-canvas {\r
+       /*\r
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1JREFUeNpiPHPmDAM2YGxsjFWciYFEMKqBGMD4//9/rBJnz54dDSX6aQAIMABCtQiAsDRF+wAAAABJRU5ErkJggg==');\r
+       */\r
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC5JREFUeNpiPHPmTAMDHmBsbIxPmoGJgUIwasBgMICFUDyfPXt2NBCHvwEAAQYAICIGn294LYEAAAAASUVORK5CYII=');\r
+\r
+}\r
+\r
+.far-far-away {\r
+       position : absolute;\r
+       left : -9999px;\r
+       top : -9999px;\r
+}\r
+\r
+#powered-by-pixastic {\r
+       position : absolute;\r
+       bottom : 0px;\r
+       margin-bottom : 23px;\r
+       margin-left : 42px;\r
+}\r
+#powered-by-pixastic a {\r
+       font-size : 12px;\r
+       font-family : Helvetica,Arial,sans-serif;\r
+       letter-spacing : 0.1em;\r
+       color : rgb(100,100,100);\r
+       color : rgba(255,255,255,0.2);\r
+       text-decoration : none;\r
+}\r
+\r
+#powered-by-pixastic a:hover {\r
+       color : rgb(200,200,200);\r
+       color : rgba(255,255,255,0.7);\r
+       text-decoration : underline;\r
+}\r
+\r
+\r
+/* -----------------------\r
+ *   Skeleton structure\r
+ * -----------------------\r
+ */\r
+\r
+/* editor background underlay */\r
+#background {\r
+       background-color : #111;\r
+       opacity : 0.9;\r
+       width : 100%;\r
+       height : 100%;\r
+       position : absolute;\r
+       z-index : -1;\r
+}\r
+\r
+#image-area {\r
+       position : relative;\r
+       background-color : #222;\r
+       border : 1px solid #444;\r
+       width : 100%;\r
+       height : 100%;\r
+       -moz-box-sizing:border-box;\r
+       overflow : auto;\r
+       text-align : center;\r
+}\r
+\r
+#image-area-sub {\r
+}\r
+\r
+#image-container {\r
+}\r
+\r
+#image-overlay-container {\r
+       -moz-box-sizing:border-box;\r
+       width:100%;\r
+       height:100%;\r
+       position:absolute;\r
+       top:0;\r
+       left:0;\r
+}\r
+\r
+#image-overlay {\r
+}\r
+\r
+\r
+/* structure elements */\r
+#edit-ctr-1 {\r
+       position : absolute;\r
+       top : 0;\r
+       left : 0;\r
+       width : 100%;\r
+       height : 100%;\r
+}\r
+\r
+#edit-ctr-2 {\r
+       -moz-box-sizing : border-box;\r
+       box-sizing : border-box;\r
+       padding-left:40px;\r
+       padding-right:420px;\r
+       padding-top:70px;\r
+       padding-bottom : 40px;\r
+       height : 100%;\r
+       width : 100%;\r
+}\r
+\r
+\r
+/* main menu bar */\r
+#main-bar {\r
+       position : absolute;\r
+       width : 100%;\r
+       text-align : right;\r
+       margin-top : 20px;\r
+       margin-right : 30px;\r
+}\r
+\r
+/* area on the right with accordion widgets and undo bar */\r
+#controls-bar {\r
+       margin-right : -385px;\r
+       width : 372px;\r
+       float : right;\r
+       height : 100%;\r
+}\r
+\r
+/* accordion area */\r
+#action-bar {\r
+       padding : 10px;\r
+       width : 290px;\r
+       background-color : #222;\r
+       border : 1px solid #444;\r
+       -moz-box-sizing : border-box;\r
+       box-sizing : border-box;\r
+       height : 100%;\r
+       overflow-x : hidden;\r
+       overflow-y : auto;\r
+       float: right; \r
+       position : relative;\r
+}\r
+\r
+#action-bar-overlay {\r
+       position : absolute;\r
+       z-index : 1000000;\r
+       width : 100%;\r
+       height : 100%;\r
+       left : 0;\r
+       top : 0;\r
+       background-color : #444;\r
+       opacity : 0.2;\r
+       display : none;\r
+}\r
+\r
+\r
+/* vertical bar with undo image states */\r
+#undo-bar {\r
+       -moz-box-sizing : border-box;\r
+       box-sizing : border-box;\r
+       background-color : #222;\r
+       border : 1px solid #444;\r
+       width: 70px; \r
+       height: 100%;\r
+       overflow: hidden;\r
+       padding-top : 3px;\r
+}\r
+\r
+\r
+\r
+/* -----------------------\r
+ *   Main menu styles\r
+ * -----------------------\r
+ */\r
+\r
+.main-tab {\r
+       color : #999;\r
+       display : inline-block;\r
+       width : 150px;\r
+       text-transform : lowercase;\r
+       font-size : 22px;\r
+       cursor : pointer;\r
+       text-align : center;\r
+       text-decoration : none;\r
+       padding-top : 4px;\r
+       padding-bottom : 5px;\r
+       outline : 0;\r
+}\r
+\r
+.main-tab.hover {\r
+       color : white !important;\r
+}\r
+\r
+.main-tab.active {\r
+       color : white;\r
+}\r
+\r
+\r
+\r
+/* -----------------------\r
+ *   Undo list\r
+ * -----------------------\r
+ */\r
+\r
+\r
+.undo-canvas-small {\r
+       width : 60px;\r
+       height : 40px;\r
+       cursor : pointer;\r
+}\r
+\r
+.undo-link {\r
+       width : 60px;\r
+       height : 40px;\r
+       display : block;\r
+       margin : 4px;\r
+       cursor : pointer;\r
+       opacity : 0.8;\r
+}\r
+\r
+.undo-link.hover {\r
+       opacity : 1;\r
+}\r
+\r
+\r
+\r
+/* -----------------------\r
+ *   Action UI controls\r
+ * -----------------------\r
+ */\r
+\r
+\r
+.ui-slider-label, \r
+.ui-checkbox-label, \r
+.ui-textinput-label, \r
+.ui-select-label {\r
+       width : 70px;\r
+       text-align : right;\r
+       margin-right : 5px;\r
+       display : inline-block;\r
+}\r
+\r
+.ui-textinput-label-right {\r
+       margin-left : 5px;\r
+}\r
+\r
+.ui-textinput {\r
+}\r
+\r
+.ui-numericinput {\r
+       width : 35px;\r
+}\r
+\r
+.ui-slider {\r
+       width : 125px;\r
+       display : inline-block;\r
+       margin-left : 3px;\r
+       background-color : #222;\r
+}\r
+\r
+.ui-slider-value {\r
+       font-size : 11px;\r
+       width : 25px;\r
+       display : inline-block;\r
+       margin-left : 10px;\r
+}\r
+\r
+.ui-action-output {\r
+       margin-bottom : 10px;\r
+}\r
+\r
+.ui-accordion .ui-accordion-content-active {\r
+       font-size : 11px;\r
+       overflow : hidden;\r
+}\r
+\r
+.ui-slider-horizontal {\r
+}\r
+\r
+.ui-slider-container, \r
+.ui-checkbox-container, \r
+.ui-textinput-container, \r
+.ui-select-container {\r
+       margin-top : 0px;\r
+       margin-bottom : 10px;\r
+       white-space : nowrap;\r
+}\r
+\r
+.ui-preview-checkbox-container {\r
+       display : inline-block;\r
+}\r
+\r
+.ui-checkbox {\r
+       margin-bottom:3px;\r
+       margin-left:5px;\r
+       margin-right:5px;\r
+       margin-top:0px;\r
+       vertical-align:middle;\r
+}\r
+\r
+input::-moz-focus-inner { border: 0; }\r
+\r
+.action-output-text {\r
+       margin-bottom : 5px;\r
+}\r
+\r
+button {\r
+       margin-right : 5px;\r
+}\r
+\r
diff --git a/js2/mwEmbed/libClipEdit/pixastic-editor/ui.js b/js2/mwEmbed/libClipEdit/pixastic-editor/ui.js
new file mode 100644 (file)
index 0000000..a0a20ba
--- /dev/null
@@ -0,0 +1,237 @@
+(function($) {\r
+\r
+       var PE = PixasticEditor;\r
+\r
+       function makeSlider(label, id, min, max, step, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-slider-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-slider-label")\r
+                       .attr("for", "input-slider-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $value = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-slider-value")\r
+                       .html(defaultVal());\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               var $slider = $j("<div class='ui-slider'><div class='ui-slider-handle'></div><div class='ui-slider-range'></div></div>", PE.getDocument())\r
+                       .appendTo($ctr)\r
+                       .attr("id", "input-slider-" + id)\r
+                       .slider({\r
+                               slide: function() {\r
+                                       $value.html($j(this).slider("value"));\r
+                                       $valueField.val($j(this).slider("value"));\r
+                               },\r
+                               change : function() {\r
+                                       $value.html($j(this).slider("value"));\r
+                                       $valueField.val($j(this).slider("value"));\r
+                                       if (onChange && performOnChange)\r
+                                               onChange();\r
+                               },\r
+                               min : min,\r
+                               max : max,\r
+                               step : step,\r
+                               value : defaultVal()\r
+                       });\r
+\r
+               $value.appendTo($ctr);\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       slider : $slider,\r
+                       valueText : $value,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               $value.html(defaultVal());\r
+                               $valueField.val(defaultVal());\r
+                               $slider.slider("value", defaultVal());\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeCheckbox(label, id, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-checkbox-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-checkbox-label")\r
+                       .attr("for", "input-checkbox-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               var $checkbox = $j("<input type=\"checkbox\"></input>", PE.getDocument())\r
+                       .addClass("ui-checkbox")\r
+                       .attr("id", "input-checkbox-" + id)\r
+                       .attr("checked", defaultVal())\r
+                       .appendTo($ctr)\r
+                       .change(function() {\r
+                               $valueField.val(this.checked);\r
+                               if (onChange && performOnChange)\r
+                                       onChange();\r
+                       });\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       checkbox : $checkbox,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               $checkbox.attr("checked", defaultVal());\r
+                               $valueField.val(defaultVal());\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeSelect(label, id, values, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-select-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-checkbox-label")\r
+                       .attr("for", "input-checkbox-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var selectHtml = "<select>";\r
+               for (var i=0;i<values.length;i++) {\r
+                       selectHtml += "<option value='" + values[i].value + "' " \r
+                               + (defaultVal() == values[i].value ? "selected" : "") \r
+                               + ">" + values[i].name + "</option>";\r
+               }\r
+               selectHtml += "</select>";\r
+\r
+               var $select = $j(selectHtml).appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               $select.change(\r
+                       function() {\r
+                               $valueField.val(this.options[this.selectedIndex].value);\r
+                               if (onChange && performOnChange)\r
+                                       onChange();\r
+                       }\r
+               );\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       select : $select,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               var defVal = defaultVal();\r
+                               $select.val(defVal);\r
+                               $valueField.val(defVal);\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeNumericInput(label, labelRight, id, min, max, step, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-textinput-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-textinput-label")\r
+                       .attr("for", "input-numeric-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               function setVal(val) {\r
+                       val = Math.min(max, val);\r
+                       val = Math.max(min, val);\r
+                       $textInput.val(val);\r
+                       $valueField.val(val);\r
+               }\r
+\r
+               var $textInput = $j("<input type=\"text\"></input>", PE.getDocument())\r
+                       .addClass("ui-textinput")\r
+                       .addClass("ui-numericinput")\r
+                       .appendTo($ctr)\r
+                       .val(defaultVal())\r
+                       .attr("id", "input-numeric-" + id)\r
+                       .change(function() {\r
+                               var val = parseFloat(this.value);\r
+                               setVal(val);\r
+                               if (onChange && performOnChange)\r
+                                       onChange();\r
+                       })\r
+                       .keydown(function(e) {\r
+                               var val = parseFloat($j(this).val());\r
+                               if (e.keyCode == 38) { // up\r
+                                       setVal(val + step);\r
+                               }\r
+                               if (e.keyCode == 40) { // down\r
+                                       setVal(val - step);\r
+                               }\r
+                       });\r
+\r
+               if (labelRight) {\r
+                       var $labelRight = $j("<label></label>", PE.getDocument())\r
+                               .addClass("ui-textinput-label-right")\r
+                               .html(labelRight)\r
+                               .appendTo($ctr);\r
+               }\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       textinput : $textInput,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               setVal(defaultVal());\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeButton(text) {\r
+               var $button = $j("<button></button>", PE.getDocument()).html(text);\r
+               return $button;\r
+       }\r
+\r
+\r
+       PE.UI = {\r
+               makeSlider : makeSlider,\r
+               makeCheckbox : makeCheckbox,\r
+               makeNumericInput : makeNumericInput,\r
+               makeSelect : makeSelect,\r
+               makeButton : makeButton\r
+       }\r
+\r
+})(PixasticEditor.jQuery);\r
+\r
diff --git a/js2/mwEmbed/libClipEdit/pixastic-editor/uidata.js b/js2/mwEmbed/libClipEdit/pixastic-editor/uidata.js
new file mode 100644 (file)
index 0000000..03f50b7
--- /dev/null
@@ -0,0 +1,966 @@
+(function($) {\r
+\r
+var PE = PixasticEditor;\r
+\r
+PE.UI.data = {\r
+       tabs : [\r
+               {\r
+                       title : "Reshape",\r
+                       id : "reshape",\r
+                       actions : [\r
+                               {\r
+                                       title : "Resize",\r
+                                       id : "resize",\r
+                                       isAction : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Enter new dimensions below."\r
+                                               },\r
+                                               {\r
+                                                       label : "Width",\r
+                                                       labelRight : "px",\r
+                                                       option : "width",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageWidth(); },\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Height",\r
+                                                       labelRight : "px",\r
+                                                       option : "height",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageHeight(); },\r
+                                                       ui : "text"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Crop",\r
+                                       id : "crop",\r
+                                       isAction : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Enter new crop values below or use mouse to select crop area."\r
+                                               },\r
+                                               {\r
+                                                       label : "X",\r
+                                                       labelRight : "px",\r
+                                                       option : "left",\r
+                                                       type : "number", \r
+                                                       range : [0,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : 0,\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Y",\r
+                                                       labelRight : "px",\r
+                                                       option : "top",\r
+                                                       type : "number", \r
+                                                       range : [0,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : 0,\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Width",\r
+                                                       labelRight : "px",\r
+                                                       option : "width",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageWidth(); },\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Height",\r
+                                                       labelRight : "px",\r
+                                                       option : "height",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageHeight(); },\r
+                                                       ui : "text"\r
+                                               }\r
+                                       ],\r
+                                       onactivate : function() {\r
+                                               var $canvas = PE.getDisplayCanvas();\r
+                                               var onchange = function(c) {\r
+                                                       var doc = PE.getDocument();\r
+                                                       $j("#input-numeric-crop-left", doc).val(c.x).change();\r
+                                                       $j("#input-numeric-crop-top", doc).val(c.y).change();\r
+                                                       $j("#input-numeric-crop-width", doc).val(c.w).change();\r
+                                                       $j("#input-numeric-crop-height", doc).val(c.h).change();\r
+                                                       $j("#input-hidden-crop-left", doc).val(c.x).change();\r
+                                                       $j("#input-hidden-crop-top", doc).val(c.y).change();\r
+                                                       $j("#input-hidden-crop-width", doc).val(c.w).change();\r
+                                                       $j("#input-hidden-crop-height", doc).val(c.h).change();\r
+                                               }\r
+                                               $canvas.data("Jcrop-onchange", onchange);\r
+                                               $canvas.Jcrop({onChange:onchange}, PE.getDocument());\r
+                                       },\r
+                                       ondeactivate : function() {\r
+                                               var $canvas = PE.getDisplayCanvas();\r
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
+                                                       $canvas.data("Jcrop").destroy();\r
+                                       },\r
+                                       onafteraction : function(action, isPreview) {\r
+                                               action.ondeactivate();\r
+                                               action.onactivate();\r
+                                               /*\r
+                                               var $canvas = PE.getDisplayCanvas();\r
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
+                                                       $canvas.data("Jcrop").destroy();\r
+                                               var onchange = $canvas.data("Jcrop-onchange");\r
+                                               $canvas.Jcrop({onChange:onchange});\r
+                                               */\r
+                                       }\r
+                               },\r
+                               {\r
+                                       title : "Rotate",\r
+                                       id : "rotate",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       forcePreview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Enter the angle (-180&deg; to 180&deg;) you want to rotate the picture. Use negative values for clockwise rotation, positive for counterclockwise."\r
+                                               },\r
+                                               {\r
+                                                       label : "Angle",\r
+                                                       labelRight : "&deg;",\r
+                                                       option : "angle",\r
+                                                       type : "number", \r
+                                                       range : [-180,180], \r
+                                                       step : 1,\r
+                                                       defaultValue : 0,\r
+                                                       ui : "text"\r
+                                               }\r
+                                       ],\r
+                                       onactivate : function() {\r
+                                               var doc = PE.getDocument();\r
+                                               var $displayCanvas = PE.getDisplayCanvas();\r
+                                               var dim = Math.min($displayCanvas.attr("height"), 200);\r
+                                               var $canvas = $j("<canvas></canvas>", doc);\r
+                                               PE.getOverlay().append($canvas);\r
+\r
+                                               $canvas.attr("width", dim);\r
+                                               $canvas.attr("height", dim);\r
+                                               $canvas.width(dim);\r
+                                               $canvas.height(dim);\r
+\r
+                                               $canvas.css("marginTop", (($displayCanvas.attr("height") - dim) * 0.5) + "px");\r
+\r
+                                               var lineWidth = 20;\r
+                                               var radius = dim/2 - lineWidth;\r
+                                               if (radius < 1) radius = 1;\r
+\r
+                                               var ctx = $canvas.get(0).getContext("2d");\r
+                                               ctx.beginPath()\r
+                                               ctx.arc(dim/2, dim/2, radius, 0, Math.PI*2, true);\r
+                                               ctx.closePath();\r
+                                               ctx.fillStyle = "rgba(200,200,200,0.2)";\r
+                                               ctx.fill();\r
+                                               ctx.strokeStyle = "rgba(200,200,200,0.5)";\r
+                                               ctx.lineWidth = 20;\r
+                                               ctx.stroke();\r
+\r
+                                               $j("#image-area", doc).css("cursor", "move");\r
+\r
+                                               $overlay = PE.getOverlay();\r
+\r
+                                               $canvas.get(0).ondragstart = function() {return false;}\r
+                                               $canvas.get(0).onselectstart = function() {return false;}\r
+\r
+                                               var mx = 0, my = 0;\r
+                                               var startMouseAngle = 0;\r
+                                               var startAngle = 0;\r
+                                               var deltaAngle = 0;\r
+                                               var angle = 0;\r
+\r
+                                               var mouseIsDown = false;\r
+                                               var onmousedown = function(e) {\r
+                                                       mouseIsDown = true;\r
+                                                       var offset = $displayCanvas.offset();\r
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
+                                                       startMouseAngle = Math.atan2(my, mx);\r
+                                                       startAngle = parseInt($j("#input-numeric-rotate-angle", doc).val(), 10) * Math.PI / 180;\r
+                                               }\r
+                                               var onmousemove = function(e) {\r
+                                                       if (!mouseIsDown) return;\r
+\r
+                                                       var offset = $displayCanvas.offset();\r
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
+                                                       deltaAngle = Math.atan2(my, mx) - startMouseAngle;\r
+                                                       angle = startAngle - deltaAngle;\r
+                                                       if (angle < -Math.PI) angle += 2*Math.PI;\r
+                                                       if (angle > Math.PI) angle -= 2*Math.PI;\r
+                                                       $j("#input-numeric-rotate-angle", doc).val(Math.round(angle * 180 / Math.PI));\r
+                                                       $j("#input-numeric-rotate-angle", doc).change();\r
+                                               }\r
+                                               var onmouseup = function() {\r
+                                                       mouseIsDown = false;\r
+                                               }\r
+\r
+                                               $j("#image-area", doc).bind("mousedown", onmousedown);\r
+                                               $j("#image-area", doc).bind("mousemove", onmousemove);\r
+                                               $j("#image-area", doc).bind("mouseup", onmouseup);\r
+                                               $canvas.data("onmousedown", onmousedown);\r
+                                               $canvas.data("onmousemove", onmousemove);\r
+                                               $canvas.data("onmouseup", onmouseup);\r
+                                               $displayCanvas.data("rotateCanvas", $canvas);\r
+                                       },\r
+                                       ondeactivate : function() {\r
+                                               var doc = PE.getDocument();\r
+                                               var $displayCanvas = PE.getDisplayCanvas();\r
+                                               $overlay = PE.getOverlay();\r
+                                               $j("#image-area", doc).css("cursor", "default");\r
+\r
+                                               var $canvas = $displayCanvas.data("rotateCanvas");\r
+\r
+                                               $j("#image-area", doc).unbind("mousedown", $canvas.data("onmousedown"));\r
+                                               $j("#image-area", doc).unbind("mousemove", $canvas.data("onmousemove"));\r
+                                               $j("#image-area", doc).unbind("mouseup", $canvas.data("onmouseup"));\r
+                                               $displayCanvas.removeData("rotateCanvas");\r
+                                               $canvas.remove();\r
+                                       },\r
+                                       onafteraction : function(action, isPreview) {\r
+                                               if (!isPreview) { // rebuild the rotate widget\r
+                                                       action.ondeactivate();\r
+                                                       action.onactivate();\r
+                                               }\r
+                                       },\r
+                                       onoverlayupdate : function() {\r
+                                               var $canvas = PE.getDisplayCanvas().data("rotateCanvas");\r
+                                               if ($canvas) {\r
+                                                       $canvas.css("marginTop", ((PE.getDisplayCanvas().get(0).height - $canvas.get(0).height) * 0.5) + "px");\r
+                                               }\r
+                                       }\r
+                               },\r
+                               {\r
+                                       title : "Flip",\r
+                                       id : "flip",\r
+                                       isAction : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       label : "Axis",\r
+                                                       option : "axis",\r
+                                                       type : "string", \r
+                                                       values : [\r
+                                                               {name:"Horizontal", value:"horizontal"},\r
+                                                               {name:"Vertical", value:"vertical"}\r
+                                                       ],\r
+                                                       defaultValue : "vertical",\r
+                                                       ui : "select"\r
+                                               }\r
+                                       ]\r
+                               }\r
+                       ]\r
+               },\r
+               {\r
+                       title : "Develop",\r
+                       id : "develop",\r
+                       actions : [\r
+                               {\r
+                                       title : "Brightness & Contrast",\r
+                                       id : "brightness",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to adjust the brightness and/or contrast of the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Brightness",\r
+                                                       option : "brightness",\r
+                                                       type : "number", \r
+                                                       range : [-100,100], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Contrast",\r
+                                                       option : "contrast",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Legacy mode",\r
+                                                       option : "legacy",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Hue/Saturation/Lightness",\r
+                                       id : "hsl",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to adjust the hue, saturation and/or lightness of the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Hue",\r
+                                                       option : "hue",\r
+                                                       type : "number", \r
+                                                       range : [-180,180], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Saturation",\r
+                                                       option : "saturation",\r
+                                                       type : "number", \r
+                                                       range : [-100,100], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Lightness",\r
+                                                       option : "lightness",\r
+                                                       type : "number", \r
+                                                       range : [-100,100], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Adjust colors",\r
+                                       id : "coloradjust",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to shift the R, G and B channels of the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Red",\r
+                                                       option : "red",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Green",\r
+                                                       option : "green",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Blue",\r
+                                                       option : "blue",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Desaturate",\r
+                                       id : "desaturate",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "This will desaturate the image. Select \"Use average\" to use the average value of the R, G and B channels rather than the default mix of 30% red, 59% green and 11% blue."\r
+                                               },\r
+                                               {\r
+                                                       label : "Use average",\r
+                                                       option : "average",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Sepia toning",\r
+                                       id : "sepia",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Applies a sepia toning effect to the image."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Invert",\r
+                                       id : "invert",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "This will invert the colors of the image."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Lighten",\r
+                                       id : "lighten",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the slider below to lighten or darken the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Unsharp mask",\r
+                                       id : "unsharpmask",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to adjust the unsharp mask parameters."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,500], \r
+                                                       defaultValue : 200,\r
+                                                       ui : "slider",\r
+                                                       step : 2\r
+                                               },\r
+                                               {\r
+                                                       label : "Radius",\r
+                                                       option : "radius",\r
+                                                       type : "number", \r
+                                                       range : [0,5], \r
+                                                       defaultValue : 2,\r
+                                                       ui : "slider",\r
+                                                       step : 0.1\r
+                                               },\r
+                                               {\r
+                                                       label : "Threshold",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,255], \r
+                                                       defaultValue : 25,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               }\r
+\r
+                       ]\r
+               },\r
+               {\r
+                       title : "Effects",\r
+                       id : "effects",\r
+                       actions : [\r
+                               {\r
+                                       title : "Blur",\r
+                                       id : "blurfast",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the slider to set the blur amount."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+\r
+                               },\r
+                               {\r
+                                       title : "Edge detection",\r
+                                       id : "edges",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Performs edge detection on the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Greyscale",\r
+                                                       option : "mono",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               },\r
+                                               {\r
+                                                       label : "Invert",\r
+                                                       option : "invert",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Emboss",\r
+                                       id : "emboss",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Adds an emboss-like effect to the image. Use the controls below to control the appearance of the effect. Choose \"Blend\" to blend the effect with the original image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Strength",\r
+                                                       option : "strength",\r
+                                                       type : "number", \r
+                                                       range : [0,10], \r
+                                                       defaultValue : 1,\r
+                                                       ui : "slider",\r
+                                                       step : 0.1\r
+                                               },\r
+                                               {\r
+                                                       label : "Grey level",\r
+                                                       option : "greyLevel",\r
+                                                       type : "number", \r
+                                                       range : [0,255], \r
+                                                       defaultValue : 180,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Direction",\r
+                                                       option : "direction",\r
+                                                       type : "string", \r
+                                                       values : [\r
+                                                               {name:"Top left", value:"topleft"},\r
+                                                               {name:"Top", value:"top"},\r
+                                                               {name:"Top right", value:"topright"},\r
+                                                               {name:"Right", value:"right"},\r
+                                                               {name:"Bottom right", value:"bottomright"},\r
+                                                               {name:"Bottom", value:"bottom"},\r
+                                                               {name:"Bottom left", value:"bottomleft"},\r
+                                                               {name:"Left", value:"left"}\r
+                                                       ],\r
+                                                       defaultValue : "topleft",\r
+                                                       ui : "select"\r
+                                               },\r
+                                               {\r
+                                                       label : "Blend",\r
+                                                       option : "blend",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+\r
+                               },\r
+                               {\r
+                                       title : "Glow",\r
+                                       id : "glow",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Creates a glowing effect on the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Radius",\r
+                                                       option : "radius",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Add noise",\r
+                                       id : "noise",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Add random noise to the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Strength",\r
+                                                       option : "strength",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Greyscale",\r
+                                                       option : "mono",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Remove noise",\r
+                                       id : "removenoise",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Attempts to remove noise from the image. Works best for getting rid of single pixels that stand out."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Pointillize",\r
+                                       id : "pointillize",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Paints the picture with circular points."\r
+                                               },\r
+                                               {\r
+                                                       label : "Point radius",\r
+                                                       option : "radius",\r
+                                                       type : "number", \r
+                                                       range : [1,50], \r
+                                                       defaultValue : 5,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Density",\r
+                                                       option : "density",\r
+                                                       type : "number", \r
+                                                       range : [0,5], \r
+                                                       defaultValue : 1,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Noise",\r
+                                                       option : "noise",\r
+                                                       type : "number", \r
+                                                       range : [0,2], \r
+                                                       defaultValue : 1,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Transparent",\r
+                                                       option : "transparent",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Posterize",\r
+                                       id : "posterize",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Reduces the number of colours to a specified number of levels."\r
+                                               },\r
+                                               {\r
+                                                       label : "Levels",\r
+                                                       option : "levels",\r
+                                                       type : "number", \r
+                                                       range : [1,32], \r
+                                                       defaultValue : 5,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Solarize",\r
+                                       id : "solarize",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Applies a solarize effect to the image."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Mosaic",\r
+                                       id : "mosaic",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Creates a pixelated look."\r
+                                               },\r
+                                               {\r
+                                                       label : "Block size",\r
+                                                       option : "blockSize",\r
+                                                       type : "number", \r
+                                                       range : [1,100], \r
+                                                       defaultValue : 5,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               }\r
+\r
+\r
+                       ]\r
+               },\r
+               {\r
+                       title : "Done",\r
+                       id : "done",\r
+                       actions : [\r
+                               {\r
+                                       title : "Save to page",\r
+                                       id : "savepage",\r
+                                       content : function($ctr) {\r
+                                               var doc = PE.getDocument();\r
+                                               $j("<div></div>", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .html("This will save the image to the page.")\r
+                                                       .appendTo($ctr);\r
+\r
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($ctr);\r
+                                               var $saveButton = $j("<button></button>", doc)\r
+                                                       .html("Save image")\r
+                                                       .appendTo($buttonCtr)\r
+                                                       .click(function() {\r
+                                                               PE.saveToPage();\r
+                                                       });\r
+\r
+                                       }\r
+                               },\r
+                               {\r
+                                       title : "Save to file",\r
+                                       id : "savefile",\r
+                                       content : function(ctr) {\r
+                                               var doc = PE.getDocument();\r
+                                               $j("<div></div>", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .html("This will save the image to your local computer.")\r
+                                                       .appendTo(ctr);\r
+\r
+                                               var formats = PE.validSaveFormats();\r
+\r
+                                               var selectHtml = "<select>";\r
+                                               for (var i=0;i<formats.length;i++) {\r
+                                                       selectHtml += "<option value='" + formats[i].mime + "'>" + formats[i].name + "</option>";\r
+                                               }\r
+                                               selectHtml += "</select>";\r
+\r
+                                               var selectCtr = $j("<div></div>", doc)\r
+                                                       .addClass("ui-select-container");\r
+\r
+\r
+                                               var label = $j("<div></div>", doc)\r
+                                                       .addClass("ui-select-label")\r
+                                                       .html("Format:")\r
+                                                       .appendTo(selectCtr);\r
+\r
+                                               var formatSelect = $j(selectHtml, doc).appendTo(selectCtr);\r
+\r
+\r
+                                               selectCtr.appendTo(ctr);\r
+\r
+                                               var buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
+                                               var saveButton = $j("<button></button>", doc)\r
+                                                       .html("Save file")\r
+                                                       .appendTo(buttonCtr)\r
+\r
+                                               saveButton.click(function() {\r
+                                                       var selectElement = formatSelect.get(0);\r
+                                                       var formatMime = selectElement.options[selectElement.selectedIndex].value;\r
+                                                       var dataString = PE.getDataURI(formatMime);\r
+\r
+                                                       var dialog = $j("<div></div>", doc)\r
+                                                               .attr("id", "save-dialog")\r
+                                                               .attr("title", "Download file")\r
+                                                               .html(\r
+                                                                       "Right click the link below and select \"Save as...\" to save your file.<br/>"\r
+                                                                       + "<br/>"\r
+                                                                       + "<a href=\"" + dataString + "\">Image Link</a>"\r
+                                                               )\r
+                                                               .dialog();\r
+\r
+                                                       // the dialog is added outside the Pixastic container, so get it back in.\r
+                                                       var dialogParent = $j(dialog.get(0).parentNode);\r
+                                                       $j("#pixastic-editor", doc).append(dialogParent);\r
+                                               });\r
+                                       }\r
+                               },\r
+                               /*\r
+                               {\r
+                                       title : "Upload to Flickr",\r
+                                       id : "flickrupload",\r
+                                       content : function($ctr) {\r
+                                               var doc = PE.getDocument();\r
+\r
+                                               function flickrAuthed() {\r
+                                                       var $text = $j("<div />", doc)\r
+                                                               .addClass("action-output-text")\r
+                                                               .html("Authorized as: " + PE.Flickr.getAuthName());\r
+\r
+                                                       var $buttonCtr = $j("<div></div>", doc);\r
+                                                       var $uploadButton = $j("<button></button>", doc)\r
+                                                               .html("Upload image")\r
+                                                               .appendTo($buttonCtr)\r
+\r
+                                                       $uploadButton.click(function() {\r
+                                                               PE.Flickr.uploadImage(PE.getDataURI());\r
+                                                       });\r
+\r
+                                                       $ctr.append($text, $buttonCtr);\r
+                                               }\r
+\r
+                                               var $authCtr = $j("<div />", doc).appendTo($ctr);\r
+\r
+                                               $j("<div />", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .html("If you have a Flickr account you can now upload your image to Flickr. You will need to give access to your account first. Click the button below to open an authorization window.")\r
+                                                       .appendTo($authCtr);\r
+\r
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($authCtr);\r
+                                               var $authButton = $j("<button></button>", doc)\r
+                                                       .html("Authenticate")\r
+                                                       .appendTo($buttonCtr)\r
+\r
+                                               var checkButtonAdded = false;\r
+                                               $authButton.click(function() {\r
+                                                       PE.Flickr.auth();\r
+                                                       if (!checkButtonAdded) {\r
+                                                               checkButtonAdded = true;\r
+\r
+                                                               var $text = $j("<div />", doc)\r
+                                                                       .addClass("action-output-text")\r
+                                                                       .html("Now click the button below when you have authorized access to your Flickr account.");\r
+       \r
+                                                               var $buttonCtr = $j("<div></div>", doc);\r
+       \r
+                                                               $authCtr.append($text, $buttonCtr);\r
+       \r
+                                                               var $checkButton = $j("<button></button>", doc)\r
+                                                                       .html("I have authenticated!")\r
+                                                                       .appendTo($buttonCtr);\r
+       \r
+                                                               $checkButton.click(function() {\r
+                                                                       PE.Flickr.checkAuth(function(res) {\r
+                                                                               if (res.stat == "ok") {\r
+                                                                                       $authCtr.remove();\r
+                                                                                       flickrAuthed();\r
+                                                                               }\r
+                                                                       });\r
+                                                               });\r
+                                                       }\r
+\r
+                                               });\r
+                                       }\r
+                               },\r
+                               */\r
+                               {\r
+                                       title : "Quit",\r
+                                       id : "quit", \r
+                                       content : function(ctr) {\r
+                                               var doc = PE.getDocument();\r
+\r
+                                               $j("<div>Are you sure you want to quit?</div>", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .appendTo(ctr);\r
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
+\r
+                                               var $quitButton = PE.UI.makeButton("Yes, quit now!")\r
+                                                       .appendTo($buttonCtr)\r
+\r
+                                               $quitButton.click(function() {\r
+                                                       PE.unload();\r
+                                               });\r
+\r
+                                               var $saveButton = PE.UI.makeButton("Save to page and quit")\r
+                                                       .appendTo($buttonCtr)\r
+                                                       .click(function() {\r
+                                                               PE.saveToPage();\r
+                                                               PE.unload();\r
+                                                       });\r
+                                       }\r
+                               }\r
+                       ]\r
+               }\r
+       ]\r
+};\r
+\r
+\r
+})(PixasticEditor.jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/blend.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/blend.js
new file mode 100644 (file)
index 0000000..db057d1
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Pixastic Lib - Blend - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.blend = {
+
+       process : function(params) {
+               var amount = parseFloat(params.options.amount);
+               var mode = (params.options.mode || "normal").toLowerCase();
+               var image = params.options.image;
+
+               amount = Math.max(0,Math.min(1,amount));
+
+               if (!image) return false;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var data = Pixastic.prepareData(params);
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       params.useData = false;
+
+                       var otherCanvas = document.createElement("canvas");
+                       otherCanvas.width = params.canvas.width;
+                       otherCanvas.height = params.canvas.height;
+                       var otherCtx = otherCanvas.getContext("2d");
+                       otherCtx.drawImage(image,0,0);
+
+                       var params2 = {canvas:otherCanvas,options:params.options};
+                       var data2 = Pixastic.prepareData(params2);
+                       var dataDesc2 = params2.canvasData;
+
+                       var p = w*h;
+                       var pix = p*4;
+                       var pix1, pix2;
+                       var r1, g1, b1;
+                       var r2, g2, b2;
+                       var r3, g3, b3;
+                       var r4, g4, b4;
+
+                       switch (mode) {
+                               case "normal" : 
+                                       //while (p--) {
+                                       //      data2[pix-=4] = data2[pix];
+                                       //      data2[pix1=pix+1] = data2[pix1];
+                                       //      data2[pix2=pix+2] = data2[pix2];
+                                       //}
+                                       break;
+
+                               case "multiply" : 
+                                       while (p--) {
+                                               data2[pix-=4] = data[pix] * data2[pix] / 255;
+                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;
+                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;
+                                       }
+                                       break;
+
+                               case "lighten" : 
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) > data2[pix])
+                                                       data2[pix] = r1;
+                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])
+                                                       data2[pix1] = g1;
+                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])
+                                                       data2[pix2] = b1;
+                                       }
+                                       break;
+
+                               case "darken" : 
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < data2[pix])
+                                                       data2[pix] = r1;
+                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])
+                                                       data2[pix1] = g1;
+                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])
+                                                       data2[pix2] = b1;
+
+                                       }
+                                       break;
+
+                               case "darkercolor" : 
+                                       while (p--) {
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
+                                                       data2[pix] = r1;
+                                                       data2[pix1] = g1;
+                                                       data2[pix2] = b1;
+                                               }
+                                       }
+                                       break;
+
+                               case "lightercolor" : 
+                                       while (p--) {
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
+                                                       data2[pix] = r1;
+                                                       data2[pix1] = g1;
+                                                       data2[pix2] = b1;
+                                               }
+                                       }
+                                       break;
+
+                               case "lineardodge" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)
+                                                       data2[pix] = 255;
+                                               else
+                                                       data2[pix] = r3;
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)
+                                                       data2[pix1] = 255;
+                                               else
+                                                       data2[pix1] = g3;
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)
+                                                       data2[pix2] = 255;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       break;
+
+                               case "linearburn" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = (r3 - 255);
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = (g3 - 255);
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = (b3 - 255);
+                                       }
+                                       break;
+
+                               case "difference" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)
+                                                       data2[pix] = -r3;
+                                               else
+                                                       data2[pix] = r3;
+                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)
+                                                       data2[pix1] = -g3;
+                                               else
+                                                       data2[pix1] = g3;
+                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)
+                                                       data2[pix2] = -b3;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       break;
+
+                               case "screen" : 
+                                       while (p--) {
+                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));
+                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));
+                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));
+                                       }
+                                       break;
+
+                               case "exclusion" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];
+                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];
+                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];
+                                       }
+                                       break;
+
+                               case "overlay" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < 128)
+                                                       data2[pix] = data2[pix]*r1*div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;
+
+                                               if ((g1 = data[pix1=pix+1]) < 128)
+                                                       data2[pix1] = data2[pix1]*g1*div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;
+
+                                               if ((b1 = data[pix2=pix+2]) < 128)
+                                                       data2[pix2] = data2[pix2]*b1*div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;
+
+                                       }
+                                       break;
+
+                               case "softlight" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < 128)
+                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;
+
+                                               if ((g1 = data[pix1=pix+1]) < 128)
+                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;
+
+                                               if ((b1 = data[pix2=pix+2]) < 128)
+                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;
+
+                                       }
+                                       break;
+
+
+                               case "hardlight" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r2 = data2[pix-=4]) < 128)
+                                                       data2[pix] = data[pix] * r2 * div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;
+
+                                               if ((g2 = data2[pix1=pix+1]) < 128)
+                                                       data2[pix1] = data[pix1] * g2 * div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;
+
+                                               if ((b2 = data2[pix2=pix+2]) < 128)
+                                                       data2[pix2] = data[pix2] * b2 * div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;
+
+                                       }
+                                       break;
+
+                               case "colordodge" : 
+                                       while (p--) {
+                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)
+                                                       data2[pix] = 255;
+                                               else
+                                                       data2[pix] = r3;
+
+                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)
+                                                       data2[pix1] = 255;
+                                               else
+                                                       data2[pix1] = g3;
+
+                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)
+                                                       data2[pix2] = 255;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+
+                                       break;
+
+                               case "colorburn" : 
+                                       while (p--) {
+                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = r3;
+
+                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = g3;
+
+                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       break;
+
+                               case "linearlight" : 
+                                       while (p--) {
+                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {
+                                                       data2[pix] = 0
+                                               } else {
+                                                       if (r3 > 255)
+                                                               data2[pix] = 255;
+                                                       else
+                                                               data2[pix] = r3;
+                                               }
+                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {
+                                                       data2[pix1] = 0
+                                               } else {
+                                                       if (g3 > 255)
+                                                               data2[pix1] = 255;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               }
+                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {
+                                                       data2[pix2] = 0
+                                               } else {
+                                                       if (b3 > 255)
+                                                               data2[pix2] = 255;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               }
+                                       }
+
+                                       break;
+
+                               case "vividlight" : 
+                                       while (p--) {
+                                               if ((r2=data2[pix-=4]) < 128) {
+                                                       if (r2) {
+                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) 
+                                                                       data2[pix] = 0;
+                                                               else
+                                                                       data2[pix] = r3
+                                                       } else {
+                                                               data2[pix] = 0;
+                                                       }
+                                               } else if ((r3 = (r4=2*r2-256)) < 255) {
+                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) 
+                                                               data2[pix] = 255;
+                                                       else
+                                                               data2[pix] = r3;
+                                               } else {
+                                                       if (r3 < 0) 
+                                                               data2[pix] = 0;
+                                                       else
+                                                               data2[pix] = r3
+                                               }
+
+                                               if ((g2=data2[pix1=pix+1]) < 128) {
+                                                       if (g2) {
+                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) 
+                                                                       data2[pix1] = 0;
+                                                               else
+                                                                       data2[pix1] = g3;
+                                                       } else {
+                                                               data2[pix1] = 0;
+                                                       }
+                                               } else if ((g3 = (g4=2*g2-256)) < 255) {
+                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)
+                                                               data2[pix1] = 255;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               } else {
+                                                       if (g3 < 0) 
+                                                               data2[pix1] = 0;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               }
+
+                                               if ((b2=data2[pix2=pix+2]) < 128) {
+                                                       if (b2) {
+                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) 
+                                                                       data2[pix2] = 0;
+                                                               else
+                                                                       data2[pix2] = b3;
+                                                       } else {
+                                                               data2[pix2] = 0;
+                                                       }
+                                               } else if ((b3 = (b4=2*b2-256)) < 255) {
+                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) 
+                                                               data2[pix2] = 255;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               } else {
+                                                       if (b3 < 0) 
+                                                               data2[pix2] = 0;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               }
+                                       }
+                                       break;
+
+                               case "pinlight" : 
+                                       while (p--) {
+                                               if ((r2=data2[pix-=4]) < 128)
+                                                       if ((r1=data[pix]) < (r4=2*r2))
+                                                               data2[pix] = r1;
+                                                       else
+                                                               data2[pix] = r4;
+                                               else
+                                                       if ((r1=data[pix]) > (r4=2*r2-256))
+                                                               data2[pix] = r1;
+                                                       else
+                                                               data2[pix] = r4;
+
+                                               if ((g2=data2[pix1=pix+1]) < 128)
+                                                       if ((g1=data[pix1]) < (g4=2*g2))
+                                                               data2[pix1] = g1;
+                                                       else
+                                                               data2[pix1] = g4;
+                                               else
+                                                       if ((g1=data[pix1]) > (g4=2*g2-256))
+                                                               data2[pix1] = g1;
+                                                       else
+                                                               data2[pix1] = g4;
+
+                                               if ((r2=data2[pix2=pix+2]) < 128)
+                                                       if ((r1=data[pix2]) < (r4=2*r2))
+                                                               data2[pix2] = r1;
+                                                       else
+                                                               data2[pix2] = r4;
+                                               else
+                                                       if ((r1=data[pix2]) > (r4=2*r2-256))
+                                                               data2[pix2] = r1;
+                                                       else
+                                                               data2[pix2] = r4;
+                                       }
+                                       break;
+
+                               case "hardmix" : 
+                                       while (p--) {
+                                               if ((r2 = data2[pix-=4]) < 128)
+                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)
+                                                               data2[pix] = 0;
+                                                       else
+                                                               data2[pix] = 255;
+                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = 255;
+
+                                               if ((g2 = data2[pix1=pix+1]) < 128)
+                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)
+                                                               data2[pix1] = 0;
+                                                       else
+                                                               data2[pix1] = 255;
+                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = 255;
+
+                                               if ((b2 = data2[pix2=pix+2]) < 128)
+                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)
+                                                               data2[pix2] = 0;
+                                                       else
+                                                               data2[pix2] = 255;
+                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = 255;
+                                       }
+                                       break;
+                       }
+
+                       otherCtx.putImageData(dataDesc2,0,0);
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.save();
+                       ctx.globalAlpha = amount;
+                       ctx.drawImage(
+                               otherCanvas,
+                               0,0,rect.width,rect.height,
+                               rect.left,rect.top,rect.width,rect.height
+                       );
+                       ctx.globalAlpha = 1;
+                       ctx.restore();
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/blur.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/blur.js
new file mode 100644 (file)
index 0000000..eb70774
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Pixastic Lib - Blur filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.blur = {
+       process : function(params) {
+
+               if (typeof params.options.fixMargin == "undefined")
+                       params.options.fixMargin = true;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       /*
+                       var kernel = [
+                               [0.5,   1,      0.5],
+                               [1,     2,      1],
+                               [0.5,   1,      0.5]
+                       ];
+                       */
+
+                       var kernel = [
+                               [0,     1,      0],
+                               [1,     2,      1],
+                               [0,     1,      0]
+                       ];
+
+                       var weight = 0;
+                       for (var i=0;i<3;i++) {
+                               for (var j=0;j<3;j++) {
+                                       weight += kernel[i][j];
+                               }
+                       }
+
+                       weight = 1 / (weight*2);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var prevY = (y == 1) ? 0 : y-2;
+                               var nextY = (y == h) ? y - 1 : y;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       data[offset] = (
+                                               /*
+                                               dataCopy[offsetPrev - 4]
+                                               + dataCopy[offsetPrev+4] 
+                                               + dataCopy[offsetNext - 4]
+                                               + dataCopy[offsetNext+4]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev]
+                                               + dataCopy[offset-4]
+                                               + dataCopy[offset+4]
+                                               + dataCopy[offsetNext])         * 2
+                                               + dataCopy[offset]              * 4
+                                               ) * weight;
+
+                                       data[offset+1] = (
+                                               /*
+                                               dataCopy[offsetPrev - 3]
+                                               + dataCopy[offsetPrev+5] 
+                                               + dataCopy[offsetNext - 3] 
+                                               + dataCopy[offsetNext+5]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev+1]
+                                               + dataCopy[offset-3]
+                                               + dataCopy[offset+5]
+                                               + dataCopy[offsetNext+1])       * 2
+                                               + dataCopy[offset+1]            * 4
+                                               ) * weight;
+
+                                       data[offset+2] = (
+                                               /*
+                                               dataCopy[offsetPrev - 2] 
+                                               + dataCopy[offsetPrev+6] 
+                                               + dataCopy[offsetNext - 2] 
+                                               + dataCopy[offsetNext+6]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev+2]
+                                               + dataCopy[offset-2]
+                                               + dataCopy[offset+6]
+                                               + dataCopy[offsetNext+2])       * 2
+                                               + dataCopy[offset+2]            * 4
+                                               ) * weight;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";
+
+                       if (params.options.fixMargin) {
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";
+                       }
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/blurfast.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/blurfast.js
new file mode 100644 (file)
index 0000000..caf6b75
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Pixastic Lib - Blur Fast - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.blurfast = {
+       process : function(params) {
+
+               var amount = parseFloat(params.options.amount)||0;
+
+               amount = Math.max(0,Math.min(5,amount));
+
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.save();
+                       ctx.beginPath();
+                       ctx.moveTo(rect.left,rect.top);
+                       ctx.lineTo(rect.left+rect.width,rect.top);
+                       ctx.lineTo(rect.left+rect.width,rect.top+rect.height);
+                       ctx.lineTo(rect.left,rect.top+rect.height);
+                       ctx.lineTo(rect.left,rect.top);
+                       ctx.closePath();
+                       ctx.clip();
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var clear = true;
+                       var steps = Math.round(amount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+       
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+       
+                               copyCtx.drawImage(
+                                       params.canvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               if (clear)
+                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);
+       
+                               ctx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       ctx.restore();
+
+                       params.useData = false;
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       var radius = 10 * amount;
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";
+
+                       if (params.options.fixMargin || 1) {
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";
+                       }
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/brightness.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/brightness.js
new file mode 100644 (file)
index 0000000..7efc3b8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Pixastic Lib - Brightness/Contrast filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.brightness = {
+
+       process : function(params) {
+
+               var brightness = parseInt(params.options.brightness,10) || 0;
+               var contrast = parseFloat(params.options.contrast)||0;
+               var legacy = !!(params.options.legacy);
+
+               if (legacy) {
+                       brightness = Math.min(150,Math.max(-150,brightness));
+               } else {
+                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;
+               }
+               contrast = Math.max(0,contrast+1);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       if (legacy) {
+                                               var r = data[offset] + brightness;
+                                               var g = data[offset+1] + brightness;
+                                               var b = data[offset+2] + brightness;
+                                       } else {
+                                               var r = data[offset] * brightMul;
+                                               var g = data[offset+1] * brightMul;
+                                               var b = data[offset+2] * brightMul;
+                                       }
+
+                                       if (contrast != 1) {
+                                               r = (r - 128) * contrast + 128;
+                                               g = (g - 128) * contrast + 128;
+                                               b = (b - 128) * contrast + 128;
+                                       }
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/coloradjust.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/coloradjust.js
new file mode 100644 (file)
index 0000000..dfcb271
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Pixastic Lib - Color adjust filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.coloradjust = {
+
+       process : function(params) {
+               var red = parseFloat(params.options.red) || 0;
+               var green = parseFloat(params.options.green) || 0;
+               var blue = parseFloat(params.options.blue) || 0;
+
+               red = Math.round(red*255);
+               green = Math.round(green*255);
+               blue = Math.round(blue*255);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset] + red;
+                                       var g = data[offset+1] + green;
+                                       var b = data[offset+2] + blue;
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/crop.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/crop.js
new file mode 100644 (file)
index 0000000..b145be5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Pixastic Lib - Crop - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.crop = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = params.width;
+                       copy.height = params.height;
+                       copy.getContext("2d").drawImage(params.canvas,0,0);
+
+                       params.canvas.width = rect.width;
+                       params.canvas.height = rect.height;
+                       params.canvas.getContext("2d").clearRect(0,0,rect.width,rect.height);
+
+                       params.canvas.getContext("2d").drawImage(copy,
+                               rect.left,rect.top,rect.width,rect.height,
+                               0,0,rect.width,rect.height
+                       );
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/desaturate.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/desaturate.js
new file mode 100644 (file)
index 0000000..9466f56
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Pixastic Lib - Desaturation filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.desaturate = {
+
+       process : function(params) {
+               var useAverage = !!params.options.average;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       var brightness = useAverage ?
+                                               (data[offset]+data[offset+1]+data[offset+2])/3
+                                               : (data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);
+                                       data[offset] = data[offset+1] = data[offset+2] = brightness;
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " gray";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/edges.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/edges.js
new file mode 100644 (file)
index 0000000..8e0d860
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Pixastic Lib - Edge detection filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.edges = {
+       process : function(params) {
+
+               var mono = !!(params.options.mono);
+
+               var strength = 1.0;
+
+               //if (typeof params.options.strength != "undefined")
+               //      strength = parseFloat(params.options.strength)||0;
+
+               var invert = !!(params.options.invert);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var c = -strength/8;
+                       var kernel = [
+                               [c,     c,      c],
+                               [c,     1,      c],
+                               [c,     c,      c]
+                       ];
+
+                       weight = 1/c;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       var r = ((dataCopy[offsetPrev-4]
+                                               + dataCopy[offsetPrev]
+                                               + dataCopy[offsetPrev+4]
+                                               + dataCopy[offset-4]
+                                               + dataCopy[offset+4]
+                                               + dataCopy[offsetNext-4]
+                                               + dataCopy[offsetNext]
+                                               + dataCopy[offsetNext+4]) * c
+                                               + dataCopy[offset]
+                                               ) 
+                                               * weight;
+       
+                                       var g = ((dataCopy[offsetPrev-3]
+                                               + dataCopy[offsetPrev+1]
+                                               + dataCopy[offsetPrev+5]
+                                               + dataCopy[offset-3]
+                                               + dataCopy[offset+5]
+                                               + dataCopy[offsetNext-3]
+                                               + dataCopy[offsetNext+1]
+                                               + dataCopy[offsetNext+5]) * c
+                                               + dataCopy[offset+1])
+                                               * weight;
+       
+                                       var b = ((dataCopy[offsetPrev-2]
+                                               + dataCopy[offsetPrev+2]
+                                               + dataCopy[offsetPrev+6]
+                                               + dataCopy[offset-2]
+                                               + dataCopy[offset+6]
+                                               + dataCopy[offsetNext-2]
+                                               + dataCopy[offsetNext+2]
+                                               + dataCopy[offsetNext+6]) * c
+                                               + dataCopy[offset+2])
+                                               * weight;
+
+                                       if (mono) {
+                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;
+                                               if (invert) brightness = 255 - brightness;
+                                               if (brightness < 0 ) brightness = 0;
+                                               if (brightness > 255 ) brightness = 255;
+                                               r = g = b = brightness;
+                                       } else {
+                                               if (invert) {
+                                                       r = 255 - r;
+                                                       g = 255 - g;
+                                                       b = 255 - b;
+                                               }
+                                               if (r < 0 ) r = 0;
+                                               if (g < 0 ) g = 0;
+                                               if (b < 0 ) b = 0;
+                                               if (r > 255 ) r = 255;
+                                               if (g > 255 ) g = 255;
+                                               if (b > 255 ) b = 255;
+                                       }
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/edges2.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/edges2.js
new file mode 100644 (file)
index 0000000..bf15041
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Pixastic Lib - Edge detection 2 - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ * 
+ * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!
+ *
+ */
+
+Pixastic.Actions.edges2 = {
+       process : function(params) {
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w * 4;
+                       var pixel = w4 + 4; // Start at (1,1)
+                       var hm1 = h - 1;
+                       var wm1 = w - 1;
+                       for (var y = 1; y < hm1; ++y) {
+                               // Prepare initial cached values for current row
+                               var centerRow = pixel - 4;
+                               var priorRow = centerRow - w4;
+                               var nextRow = centerRow + w4;
+                               
+                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];
+                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
+                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
+                               
+                               var rp = dataCopy[priorRow += 2];
+                               var gp = dataCopy[++priorRow];
+                               var bp = dataCopy[++priorRow];
+                               
+                               var rc = dataCopy[centerRow += 2];
+                               var gc = dataCopy[++centerRow];
+                               var bc = dataCopy[++centerRow];
+                               
+                               var rn = dataCopy[nextRow += 2];
+                               var gn = dataCopy[++nextRow];
+                               var bn = dataCopy[++nextRow];
+                               
+                               var r2 = - rp - rc - rn;
+                               var g2 = - gp - gc - gn;
+                               var b2 = - bp - bc - bn;
+                               
+                               // Main convolution loop
+                               for (var x = 1; x < wm1; ++x) {
+                                       centerRow = pixel + 4;
+                                       priorRow = centerRow - w4;
+                                       nextRow = centerRow + w4;
+                                       
+                                       var r = 127 + r1 - rp - (rc * -8) - rn;
+                                       var g = 127 + g1 - gp - (gc * -8) - gn;
+                                       var b = 127 + b1 - bp - (bc * -8) - bn;
+                                       
+                                       r1 = r2;
+                                       g1 = g2;
+                                       b1 = b2;
+                                       
+                                       rp = dataCopy[  priorRow];
+                                       gp = dataCopy[++priorRow];
+                                       bp = dataCopy[++priorRow];
+                                       
+                                       rc = dataCopy[  centerRow];
+                                       gc = dataCopy[++centerRow];
+                                       bc = dataCopy[++centerRow];
+                                       
+                                       rn = dataCopy[  nextRow];
+                                       gn = dataCopy[++nextRow];
+                                       bn = dataCopy[++nextRow];
+                                       
+                                       r += (r2 = - rp - rc - rn);
+                                       g += (g2 = - gp - gc - gn);
+                                       b += (b2 = - bp - bc - bn);
+
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+
+                                       data[pixel] = r;
+                                       data[++pixel] = g;
+                                       data[++pixel] = b;
+                                       //data[++pixel] = 255; // alpha
+
+                                       pixel+=2;
+                               }
+                               pixel += 8;
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/emboss.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/emboss.js
new file mode 100644 (file)
index 0000000..51e4252
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Pixastic Lib - Emboss filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.emboss = {
+       process : function(params) {
+
+               var strength = parseFloat(params.options.strength)||1;
+               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;
+               var direction = params.options.direction||"topleft";
+               var blend = !!params.options.blend;
+
+               var dirY = 0;
+               var dirX = 0;
+
+               switch (direction) {
+                       case "topleft":                 // top left
+                               dirY = -1;
+                               dirX = -1;
+                               break;
+                       case "top":                     // top
+                               dirY = -1;
+                               dirX = 0;
+                               break;
+                       case "topright":                        // top right
+                               dirY = -1;
+                               dirX = 1;
+                               break;
+                       case "right":                   // right
+                               dirY = 0;
+                               dirX = 1;
+                               break;
+                       case "bottomright":                     // bottom right
+                               dirY = 1;
+                               dirX = 1;
+                               break;
+                       case "bottom":                  // bottom
+                               dirY = 1;
+                               dirX = 0;
+                               break;
+                       case "bottomleft":                      // bottom left
+                               dirY = 1;
+                               dirX = -1;
+                               break;
+                       case "left":                    // left
+                               dirY = 0;
+                               dirX = -1;
+                               break;
+               }
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var invertAlpha = !!params.options.invertAlpha;
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var otherY = dirY;
+                               if (y + otherY < 1) otherY = 0;
+                               if (y + otherY > h) otherY = 0;
+
+                               var offsetYOther = (y-1+otherY)*w*4;
+
+                               var x = w;
+                               do {
+                                               var offset = offsetY + (x-1)*4;
+
+                                               var otherX = dirX;
+                                               if (x + otherX < 1) otherX = 0;
+                                               if (x + otherX > w) otherX = 0;
+
+                                               var offsetOther = offsetYOther + (x-1+otherX)*4;
+
+                                               var dR = dataCopy[offset] - dataCopy[offsetOther];
+                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];
+                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];
+
+                                               var dif = dR;
+                                               var absDif = dif > 0 ? dif : -dif;
+
+                                               var absG = dG > 0 ? dG : -dG;
+                                               var absB = dB > 0 ? dB : -dB;
+
+                                               if (absG > absDif) {
+                                                       dif = dG;
+                                               }
+                                               if (absB > absDif) {
+                                                       dif = dB;
+                                               }
+
+                                               dif *= strength;
+
+                                               if (blend) {
+                                                       var r = data[offset] + dif;
+                                                       var g = data[offset+1] + dif;
+                                                       var b = data[offset+2] + dif;
+
+                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);
+                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);
+                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);
+                                               } else {
+                                                       var grey = greyLevel - dif;
+                                                       if (grey < 0) {
+                                                               grey = 0;
+                                                       } else if (grey > 255) {
+                                                               grey = 255;
+                                                       }
+
+                                                       data[offset] = data[offset+1] = data[offset+2] = grey;
+                                               }
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/fliph.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/fliph.js
new file mode 100644 (file)
index 0000000..5b7b0d2
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Pixastic Lib - Horizontal flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.fliph = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+                       var copyCanvas = document.createElement("canvas");
+                       copyCanvas.width = rect.width;
+                       copyCanvas.height = rect.height;
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.scale(-1,1);
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
+                       params.useData = false;
+
+                       return true;            
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " fliph";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/flipv.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/flipv.js
new file mode 100644 (file)
index 0000000..cfc60d3
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Pixastic Lib - Vertical flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.flipv = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+                       var copyCanvas = document.createElement("canvas");
+                       copyCanvas.width = rect.width;
+                       copyCanvas.height = rect.height;
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.scale(1,-1);
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
+                       params.useData = false;
+
+                       return true;            
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " flipv";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/glow.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/glow.js
new file mode 100644 (file)
index 0000000..bd93c81
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Pixastic Lib - Glow - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+
+Pixastic.Actions.glow = {
+       process : function(params) {
+
+               var amount = (parseFloat(params.options.amount)||0);
+               var blurAmount = parseFloat(params.options.radius)||0;
+
+               amount = Math.min(1,Math.max(0,amount));
+               blurAmount = Math.min(5,Math.max(0,blurAmount));
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+
+                       var blurCanvas = document.createElement("canvas");
+                       blurCanvas.width = params.width;
+                       blurCanvas.height = params.height;
+                       var blurCtx = blurCanvas.getContext("2d");
+                       blurCtx.drawImage(params.canvas,0,0);
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var clear = true;
+                       var steps = Math.round(blurAmount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+       
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+       
+                               copyCtx.drawImage(
+                                       blurCanvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               blurCtx.clearRect(0,0,params.width,params.height);
+       
+                               blurCtx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       var data = Pixastic.prepareData(params);
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var r = data[offset] + amount * blurData[offset];
+                                       var g = data[offset+1] + amount * blurData[offset+1];
+                                       var b = data[offset+2] + amount * blurData[offset+2];
+       
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/histogram.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/histogram.js
new file mode 100644 (file)
index 0000000..4b88404
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Pixastic Lib - Histogram - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.histogram = {
+       process : function(params) {
+
+               var average = !!(params.options.average);
+               var paint = !!(params.options.paint);
+               var color = params.options.color || "rgba(255,255,255,0.5)";
+               var values = [];
+               if (typeof params.options.returnValue != "object") {
+                       params.options.returnValue = {values:[]};
+               }
+               var returnValue = params.options.returnValue;
+               if (typeof returnValue.values != "array") {
+                       returnValue.values = [];
+               }
+               values = returnValue.values;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       params.useData = false;
+
+                       for (var i=0;i<256;i++) {
+                               values[i] = 0;
+                       }
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+                                       var brightness = average ? 
+                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)
+                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);
+                                       values[brightness]++;
+
+                               } while (--x);
+                       } while (--y);
+
+                       if (paint) {
+                               var maxValue = 0;
+                               for (var i=0;i<256;i++) {
+                                       if (values[i] > maxValue) {
+                                               maxValue = values[i];
+                                       }
+                               }
+                               var heightScale = params.height / maxValue;
+                               var widthScale = params.width / 256;
+                               var ctx = params.canvas.getContext("2d");
+                               ctx.fillStyle = color;
+                               for (var i=0;i<256;i++) {
+                                       ctx.fillRect(
+                                               i * widthScale, params.height - heightScale * values[i],
+                                               widthScale, values[i] * heightScale
+                                       );
+                               }
+                       }
+
+                       returnValue.values = values;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/hsl.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/hsl.js
new file mode 100644 (file)
index 0000000..510f71b
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Pixastic Lib - HSL Adjust  - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.hsl = {
+       process : function(params) {
+
+               var hue = parseInt(params.options.hue,10)||0;
+               var saturation = (parseInt(params.options.saturation,10)||0) / 100;
+               var lightness = (parseInt(params.options.lightness,10)||0) / 100;
+
+
+               // this seems to give the same result as Photoshop
+               if (saturation < 0) {
+                       var satMul = 1+saturation;
+               } else {
+                       var satMul = 1+saturation*2;
+               }
+
+               hue = (hue%360) / 360;
+               var hue6 = hue * 6;
+
+               var rgbDiv = 1 / 255;
+
+               var light255 = lightness * 255;
+               var lightp1 = 1 + lightness;
+               var lightm1 = 1 - lightness;
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       if (hue != 0 || saturation != 0) {
+                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. 
+                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.
+                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.
+                                               var vs = r;
+                                               if (g > vs) vs = g;
+                                               if (b > vs) vs = b;
+                                               var ms = r;
+                                               if (g < ms) ms = g;
+                                               if (b < ms) ms = b;
+                                               var vm = (vs-ms);
+                                               var l = (ms+vs)/255 * 0.5;
+                                               if (l > 0) {
+                                                       if (vm > 0) {
+                                                               if (l <= 0.5) {
+                                                                       var s = vm / (vs+ms) * satMul;
+                                                                       if (s > 1) s = 1;
+                                                                       var v = (l * (1+s));
+                                                               } else {
+                                                                       var s = vm / (510-vs-ms) * satMul;
+                                                                       if (s > 1) s = 1;
+                                                                       var v = (l+s - l*s);
+                                                               }
+                                                               if (r == vs) {
+                                                                       if (g == ms)
+                                                                               var h = 5 + ((vs-b)/vm) + hue6;
+                                                                       else
+                                                                               var h = 1 - ((vs-g)/vm) + hue6;
+                                                               } else if (g == vs) {
+                                                                       if (b == ms)
+                                                                               var h = 1 + ((vs-r)/vm) + hue6;
+                                                                       else
+                                                                               var h = 3 - ((vs-b)/vm) + hue6;
+                                                               } else {
+                                                                       if (r == ms)
+                                                                               var h = 3 + ((vs-g)/vm) + hue6;
+                                                                       else
+                                                                               var h = 5 - ((vs-r)/vm) + hue6;
+                                                               }
+                                                               if (h < 0) h+=6;
+                                                               if (h >= 6) h-=6;
+                                                               var m = (l+l-v);
+                                                               var sextant = h>>0;
+                                                               switch (sextant) {
+                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;
+                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;
+                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;
+                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;
+                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;
+                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       if (lightness < 0) {
+                                               r *= lightp1;
+                                               g *= lightp1;
+                                               b *= lightp1;
+                                       } else if (lightness > 0) {
+                                               r = r * lightm1 + light255;
+                                               g = g * lightm1 + light255;
+                                               b = b * lightm1 + light255;
+                                       }
+
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/invert.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/invert.js
new file mode 100644 (file)
index 0000000..0b5102b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Pixastic Lib - Invert filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.invert = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var invertAlpha = !!params.options.invertAlpha;
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       data[offset] = 255 - data[offset];
+                                       data[offset+1] = 255 - data[offset+1];
+                                       data[offset+2] = 255 - data[offset+2];
+                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " invert";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/laplace.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/laplace.js
new file mode 100644 (file)
index 0000000..6a6e146
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Pixastic Lib - Laplace filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.laplace = {
+       process : function(params) {
+
+               var strength = 1.0;
+               var invert = !!(params.options.invert);
+               var contrast = parseFloat(params.options.edgeStrength)||0;
+
+               var greyLevel = parseInt(params.options.greyLevel)||0;
+
+               contrast = -contrast;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var kernel = [
+                               [-1,    -1,     -1],
+                               [-1,    8,      -1],
+                               [-1,    -1,     -1]
+                       ];
+
+                       var weight = 1/8;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       var r = ((-dataCopy[offsetPrev-4]
+                                               - dataCopy[offsetPrev]
+                                               - dataCopy[offsetPrev+4]
+                                               - dataCopy[offset-4]
+                                               - dataCopy[offset+4]
+                                               - dataCopy[offsetNext-4]
+                                               - dataCopy[offsetNext]
+                                               - dataCopy[offsetNext+4])
+                                               + dataCopy[offset] * 8) 
+                                               * weight;
+       
+                                       var g = ((-dataCopy[offsetPrev-3]
+                                               - dataCopy[offsetPrev+1]
+                                               - dataCopy[offsetPrev+5]
+                                               - dataCopy[offset-3]
+                                               - dataCopy[offset+5]
+                                               - dataCopy[offsetNext-3]
+                                               - dataCopy[offsetNext+1]
+                                               - dataCopy[offsetNext+5])
+                                               + dataCopy[offset+1] * 8)
+                                               * weight;
+       
+                                       var b = ((-dataCopy[offsetPrev-2]
+                                               - dataCopy[offsetPrev+2]
+                                               - dataCopy[offsetPrev+6]
+                                               - dataCopy[offset-2]
+                                               - dataCopy[offset+6]
+                                               - dataCopy[offsetNext-2]
+                                               - dataCopy[offsetNext+2]
+                                               - dataCopy[offsetNext+6])
+                                               + dataCopy[offset+2] * 8)
+                                               * weight;
+
+                                       var brightness = ((r + g + b)/3) + greyLevel;
+
+                                       if (contrast != 0) {
+                                               if (brightness > 127) {
+                                                       brightness += ((brightness + 1) - 128) * contrast;
+                                               } else if (brightness < 127) {
+                                                       brightness -= (brightness + 1) * contrast;
+                                               }
+                                       }
+                                       if (invert) {
+                                               brightness = 255 - brightness;
+                                       }
+                                       if (brightness < 0 ) brightness = 0;
+                                       if (brightness > 255 ) brightness = 255;
+
+                                       data[offset] = data[offset+1] = data[offset+2] = brightness;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/lighten.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/lighten.js
new file mode 100644 (file)
index 0000000..90381aa
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Pixastic Lib - Lighten filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.lighten = {
+
+       process : function(params) {
+               var amount = parseFloat(params.options.amount) || 0;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       r += r*amount;
+                                       g += g*amount;
+                                       b += b*amount;
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       var img = params.image;
+                       if (amount < 0) {
+                               img.style.filter += " light()";
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100 * -amount
+                               );
+                       } else if (amount > 0) {
+                               img.style.filter += " light()";
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100
+                               );
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100 * amount
+                               );
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/mosaic.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/mosaic.js
new file mode 100644 (file)
index 0000000..ee462af
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Pixastic Lib - Mosaic filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.mosaic = {
+
+       process : function(params) {
+               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+
+                       var ctx = params.canvas.getContext("2d");
+
+                       var pixel = document.createElement("canvas");
+                       pixel.width = pixel.height = 1;
+                       var pixelCtx = pixel.getContext("2d");
+
+                       var copy = document.createElement("canvas");
+                       copy.width = w;
+                       copy.height = h;
+                       var copyCtx = copy.getContext("2d");
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
+
+                       for (var y=0;y<h;y+=blockSize) {
+                               for (var x=0;x<w;x+=blockSize) {
+                                       pixelCtx.drawImage(copy, x, y, blockSize, blockSize, 0, 0, 1, 1);
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
+                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);
+                               }
+                       }
+
+                       params.useData = false;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/noise.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/noise.js
new file mode 100644 (file)
index 0000000..97ba825
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Pixastic Lib - Noise filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.noise = {
+
+       process : function(params) {
+               var amount = 0;
+               var strength = 0;
+               var mono = false;
+
+               if (typeof params.options.amount != "undefined")
+                       amount = parseFloat(params.options.amount)||0;
+               if (typeof params.options.strength != "undefined")
+                       strength = parseFloat(params.options.strength)||0;
+               if (typeof params.options.mono != "undefined")
+                       mono = !!(params.options.mono);
+
+               amount = Math.max(0,Math.min(1,amount));
+               strength = Math.max(0,Math.min(1,strength));
+
+               var noise = 128 * strength;
+               var noise2 = noise / 2;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       var random = Math.random;
+
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       if (random() < amount) {
+                                               if (mono) {
+                                                       var pixelNoise = - noise2 + random() * noise;
+                                                       var r = data[offset] + pixelNoise;
+                                                       var g = data[offset+1] + pixelNoise;
+                                                       var b = data[offset+2] + pixelNoise;
+                                               } else {
+                                                       var r = data[offset] - noise2 + (random() * noise);
+                                                       var g = data[offset+1] - noise2 + (random() * noise);
+                                                       var b = data[offset+2] - noise2 + (random() * noise);
+                                               }
+
+                                               if (r < 0 ) r = 0;
+                                               if (g < 0 ) g = 0;
+                                               if (b < 0 ) b = 0;
+                                               if (r > 255 ) r = 255;
+                                               if (g > 255 ) g = 255;
+                                               if (b > 255 ) b = 255;
+
+                                               data[offset] = r;
+                                               data[offset+1] = g;
+                                               data[offset+2] = b;
+                                       }
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/pointillize.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/pointillize.js
new file mode 100644 (file)
index 0000000..59329c8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Pixastic Lib - Pointillize filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.pointillize = {
+
+       process : function(params) {
+               var radius = Math.max(1,parseInt(params.options.radius,10));
+               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));
+               var noise = Math.max(0,parseFloat(params.options.noise)||0);
+               var transparent = !!params.options.transparent;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+
+                       var ctx = params.canvas.getContext("2d");
+
+                       var pixel = document.createElement("canvas");
+                       pixel.width = pixel.height = 1;
+                       var pixelCtx = pixel.getContext("2d");
+
+                       var copy = document.createElement("canvas");
+                       copy.width = w;
+                       copy.height = h;
+                       var copyCtx = copy.getContext("2d");
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
+
+                       var diameter = radius * 2;
+
+                       if (transparent)
+                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+
+                       var noiseRadius = radius * noise;
+
+                       var dist = 1 / density;
+
+                       for (var y=0;y<h+radius;y+=diameter*dist) {
+                               for (var x=0;x<w+radius;x+=diameter*dist) {
+                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;
+                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;
+
+                                       var pixX = rndX - radius;
+                                       var pixY = rndY - radius;
+                                       if (pixX < 0) pixX = 0;
+                                       if (pixY < 0) pixY = 0;
+
+                                       pixelCtx.drawImage(copy, pixX, pixY, diameter, diameter, 0, 0, 1, 1);
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
+                                       ctx.beginPath();
+                                       ctx.arc(rect.left + rndX,rect.top + rndY, radius, 0, Math.PI*2, true);
+                                       ctx.closePath();
+                                       ctx.fill();
+                               }
+                       }
+
+                       params.useData = false;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/posterize.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/posterize.js
new file mode 100644 (file)
index 0000000..1bc629a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Pixastic Lib - Posterize effect - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.posterize = {
+
+       process : function(params) {
+
+               
+               var numLevels = 256;
+               if (typeof params.options.levels != "undefined")
+                       numLevels = parseInt(params.options.levels,10)||1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       numLevels = Math.max(2,Math.min(256,numLevels));
+       
+                       var numAreas = 256 / numLevels;
+                       var numValues = 256 / (numLevels-1);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = numValues * ((data[offset] / numAreas)>>0);
+                                       var g = numValues * ((data[offset+1] / numAreas)>>0);
+                                       var b = numValues * ((data[offset+2] / numAreas)>>0);
+
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/removenoise.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/removenoise.js
new file mode 100644 (file)
index 0000000..042033a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Pixastic Lib - Remove noise - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.removenoise = {
+       process : function(params) {
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+
+                                       var minR, maxR, minG, maxG, minB, maxB;
+
+                                       minR = maxR = data[offsetPrev];
+                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];
+                                       if (r1 < minR) minR = r1;
+                                       if (r2 < minR) minR = r2;
+                                       if (r3 < minR) minR = r3;
+                                       if (r1 > maxR) maxR = r1;
+                                       if (r2 > maxR) maxR = r2;
+                                       if (r3 > maxR) maxR = r3;
+
+                                       minG = maxG = data[offsetPrev+1];
+                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];
+                                       if (g1 < minG) minG = g1;
+                                       if (g2 < minG) minG = g2;
+                                       if (g3 < minG) minG = g3;
+                                       if (g1 > maxG) maxG = g1;
+                                       if (g2 > maxG) maxG = g2;
+                                       if (g3 > maxG) maxG = g3;
+
+                                       minB = maxB = data[offsetPrev+2];
+                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];
+                                       if (b1 < minB) minB = b1;
+                                       if (b2 < minB) minB = b2;
+                                       if (b3 < minB) minB = b3;
+                                       if (b1 > maxB) maxB = b1;
+                                       if (b2 > maxB) maxB = b2;
+                                       if (b3 > maxB) maxB = b3;
+
+                                       if (data[offset] > maxR) {
+                                               data[offset] = maxR;
+                                       } else if (data[offset] < minR) {
+                                               data[offset] = minR;
+                                       }
+                                       if (data[offset+1] > maxG) {
+                                               data[offset+1] = maxG;
+                                       } else if (data[offset+1] < minG) {
+                                               data[offset+1] = minG;
+                                       }
+                                       if (data[offset+2] > maxB) {
+                                               data[offset+2] = maxB;
+                                       } else if (data[offset+2] < minB) {
+                                               data[offset+2] = minB;
+                                       }
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/sepia.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/sepia.js
new file mode 100644 (file)
index 0000000..016bf20
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Pixastic Lib - Sepia filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.sepia = {
+
+       process : function(params) {
+               var mode = (parseInt(params.options.mode,10)||0);
+               if (mode < 0) mode = 0;
+               if (mode > 1) mode = 1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       if (mode) {
+                                               // a bit faster, but not as good
+                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;
+                                               var r = (d + 39);
+                                               var g = (d + 14);
+                                               var b = (d - 36);
+                                       } else {
+                                               // Microsoft
+                                               var or = data[offset];
+                                               var og = data[offset+1];
+                                               var ob = data[offset+2];
+       
+                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);
+                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);
+                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);
+                                       }
+
+                                       if (r < 0) r = 0; if (r > 255) r = 255;
+                                       if (g < 0) g = 0; if (g > 255) g = 255;
+                                       if (b < 0) b = 0; if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/sharpen.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/sharpen.js
new file mode 100644 (file)
index 0000000..d013832
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Pixastic Lib - Sharpen filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.sharpen = {
+       process : function(params) {
+
+               var strength = 0;
+               if (typeof params.options.amount != "undefined")
+                       strength = parseFloat(params.options.amount)||0;
+
+               if (strength < 0) strength = 0;
+               if (strength > 1) strength = 1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var mul = 15;
+                       var mulOther = 1 + 3*strength;
+
+                       var kernel = [
+                               [0,     -mulOther,      0],
+                               [-mulOther,     mul,    -mulOther],
+                               [0,     -mulOther,      0]
+                       ];
+
+                       var weight = 0;
+                       for (var i=0;i<3;i++) {
+                               for (var j=0;j<3;j++) {
+                                       weight += kernel[i][j];
+                               }
+                       }
+
+                       weight = 1 / weight;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       mul *= weight;
+                       mulOther *= weight;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w4;
+                               var offsetYNext = nextY*w4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+
+                                       var r = ((
+                                               - dataCopy[offsetPrev]
+                                               - dataCopy[offset-4]
+                                               - dataCopy[offset+4]
+                                               - dataCopy[offsetNext])         * mulOther
+                                               + dataCopy[offset]      * mul
+                                               );
+
+                                       var g = ((
+                                               - dataCopy[offsetPrev+1]
+                                               - dataCopy[offset-3]
+                                               - dataCopy[offset+5]
+                                               - dataCopy[offsetNext+1])       * mulOther
+                                               + dataCopy[offset+1]    * mul
+                                               );
+
+                                       var b = ((
+                                               - dataCopy[offsetPrev+2]
+                                               - dataCopy[offset-2]
+                                               - dataCopy[offset+6]
+                                               - dataCopy[offsetNext+2])       * mulOther
+                                               + dataCopy[offset+2]    * mul
+                                               );
+
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/solarize.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/solarize.js
new file mode 100644 (file)
index 0000000..33205ad
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Pixastic Lib - Solarize filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+Pixastic.Actions.solarize = {
+
+       process : function(params) {
+               var useAverage = !!params.options.average;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       if (r > 127) r = 255 - r;
+                                       if (g > 127) g = 255 - g;
+                                       if (b > 127) b = 255 - b;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/actions/unsharpmask.js b/js2/mwEmbed/libClipEdit/pixastic-lib/actions/unsharpmask.js
new file mode 100644 (file)
index 0000000..6c562e2
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Pixastic Lib - USM - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+
+Pixastic.Actions.unsharpmask = {
+       process : function(params) {
+
+               var amount = (parseFloat(params.options.amount)||0);
+               var blurAmount = parseFloat(params.options.radius)||0;
+               var threshold = parseFloat(params.options.threshold)||0;
+
+               amount = Math.min(500,Math.max(0,amount)) / 2;
+               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;
+               threshold = Math.min(255,Math.max(0,threshold));
+
+               threshold--;
+               var thresholdNeg = -threshold;
+
+               amount *= 0.016;
+               amount++;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+
+                       var blurCanvas = document.createElement("canvas");
+                       blurCanvas.width = params.width;
+                       blurCanvas.height = params.height;
+                       var blurCtx = blurCanvas.getContext("2d");
+                       blurCtx.drawImage(params.canvas,0,0);
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var steps = Math.round(blurAmount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+
+                               copyCtx.drawImage(
+                                       blurCanvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               blurCtx.clearRect(0,0,params.width,params.height);
+       
+                               blurCtx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       var data = Pixastic.prepareData(params);
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var difR = data[offset] - blurData[offset];
+                                       if (difR > threshold || difR < thresholdNeg) {
+                                               var blurR = blurData[offset];
+                                               blurR = amount * difR + blurR;
+                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);
+                                       }
+
+                                       var difG = data[offset+1] - blurData[offset+1];
+                                       if (difG > threshold || difG < thresholdNeg) {
+                                               var blurG = blurData[offset+1];
+                                               blurG = amount * difG + blurG;
+                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);
+                                       }
+
+                                       var difB = data[offset+2] - blurData[offset+2];
+                                       if (difB > threshold || difB < thresholdNeg) {
+                                               var blurB = blurData[offset+2];
+                                               blurB = amount * difB + blurB;
+                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);
+                                       }
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/editor.js b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/editor.js
new file mode 100644 (file)
index 0000000..6edba1a
--- /dev/null
@@ -0,0 +1,968 @@
+\r
+var PixasticEditor = (function () {\r
+\r
+       var $frame;     // iframe container element\r
+       var $editor;    // editor container element\r
+\r
+       // various UI structures\r
+       var accordionElements = {};\r
+       var tabElements = {};\r
+       var activeTabId;\r
+       var $activeTabContent;\r
+\r
+       var isRunning = false;\r
+\r
+       var $loadingScreen;\r
+\r
+       var $imageCanvas;       // the canvas holding the current state of the image\r
+       var $displayCanvas;     // the canvas element displayed on the screen, also the working canvas (where preview operations are performed)\r
+       var imageCtx;\r
+\r
+       var imageWidth = 0;     // dimensions of the current image state\r
+       var imageHeight = 0;\r
+\r
+       var undoImages = [];    // canvas elements holding previous image states\r
+       var undoLevels = 10;\r
+\r
+       var doc;\r
+\r
+       var $;\r
+\r
+       // test for valid file formats for toDataURL()\r
+       // we do that by calling it with each of the mime types in testFormats\r
+       // and then doing string checking on the resulting data: URI to see if it succeeded\r
+       var saveFormats = [];\r
+       var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]];\r
+       var testCanvas = document.createElement("canvas");\r
+       if (testCanvas.toDataURL) {\r
+               testCanvas.width = testCanvas.height = 1;\r
+               for (var i=0;i<testFormats.length;i++) {\r
+                       var data = testCanvas.toDataURL(testFormats[i][0]);\r
+                       if (data.substr(0, 5 + testFormats[i][0].length) == "data:" + testFormats[i][0])\r
+                               saveFormats.push({mime:testFormats[i][0], name:testFormats[i][1]});\r
+               }\r
+       }\r
+\r
+\r
+       // pops up an error dialog with the specified text (errTxt),\r
+       // if no context is provided, the name of the calling function is used.\r
+       // The final message is returned for easy throwing of actual errors\r
+       function errorDialog(errTxt, context) {\r
+               if (!($editor && $editor.get && $editor.get(0)))\r
+                       throw new Error("errorDialog(): $editor doesn't exist");\r
+\r
+               var caller = errorDialog.caller.toString().split(" ")[1];\r
+               caller = caller.substring(0, caller.indexOf("("));\r
+               context = context || caller;\r
+               errTxt = context + "(): " + errTxt;\r
+               var dialog = $j("<div></div>", doc)\r
+                       .addClass("error-dialog")\r
+                       .attr("title", "Oops!")\r
+                       .html(errTxt)\r
+                       .dialog();\r
+               // the dialog is added outside the Pixastic container, so get it back in.\r
+               var dialogParent = $j(dialog.get(0).parentNode);\r
+               dialogParent.appendTo($editor);\r
+\r
+               return errTxt;\r
+       }\r
+       \r
+       function enableTab(id, refresh) {\r
+               if (id == activeTabId && !refresh)\r
+                       return;\r
+\r
+               activeTabId = id;\r
+\r
+               var activeIndex = 0;\r
+\r
+               if ($activeTabContent) {\r
+                       if ($activeTabContent.get(0)) {\r
+                               var $parent = $j($activeTabContent.get(0).parentNode);\r
+                               activeIndex = $parent.data("accordionindex");\r
+                               if ($parent.data("ondeactivate")) {\r
+                                       $parent.data("ondeactivate")();\r
+                               }\r
+                               if ($parent.data("previewCheckbox"))\r
+                                       $parent.data("previewCheckbox").attr("checked", false);\r
+                               $parent.data("uidesc").previewEnabled = false;\r
+                               if ($parent.data("uidesc").forcePreview)\r
+                                       $parent.data("uidesc").previewEnabled = true;\r
+                       }\r
+               }\r
+\r
+\r
+               for (var a in accordionElements) {\r
+                       if (accordionElements.hasOwnProperty(a)) {\r
+                               accordionElements[a].accordion("option", "animated", false);\r
+                               accordionElements[a].accordion("activate", -1);\r
+                               accordionElements[a].hide();\r
+                               tabElements[a].removeClass("active");\r
+\r
+                       }\r
+               }\r
+\r
+               accordionElements[id].accordion("option", "animated", false);\r
+               accordionElements[id].accordion("activate", refresh ? activeIndex : 0);\r
+               tabElements[id].addClass("active");\r
+               accordionElements[id].show();\r
+               accordionElements[id].accordion("option", "animated", "slide");\r
+               resetDisplayCanvas();\r
+       }\r
+\r
+       // revert to a previous image state\r
+       function undo(idx) {\r
+               var undoImage = undoImages[idx];\r
+\r
+               if (!undoImage) \r
+                       throw new Error(errorDialog("Invalid undo state"));\r
+               if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
+                       throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
+\r
+               var canvas = $imageCanvas.get(0);\r
+               addUndo(canvas);\r
+               canvas.width = imageWidth = undoImage.width;\r
+               canvas.height = imageHeight = undoImage.height;\r
+               canvas.getContext("2d").drawImage(undoImage,0,0);\r
+\r
+               enableTab(activeTabId, true);\r
+               resetDisplayCanvas();\r
+       }\r
+\r
+       function addUndo(canvasElement) {\r
+               if (!canvasElement)\r
+                       throw new Error(errorDialog("No undo image state provided"));\r
+\r
+               if (undoImages.length == undoLevels) {\r
+                       undoImages.shift();\r
+               }\r
+               var undoCanvas = document.createElement("canvas");\r
+               undoCanvas.width = canvasElement.width;\r
+               undoCanvas.height = canvasElement.height;\r
+               undoCanvas.getContext("2d").drawImage(canvasElement,0,0);\r
+               $j(undoCanvas).addClass("undo-canvas");\r
+               undoImages.push(undoCanvas);\r
+               updateUndoList();\r
+       }\r
+\r
+       function updateUndoList() {\r
+               var $listCtr = $j("#undo-bar", doc)\r
+                       .html("");\r
+\r
+               var ctrHeight = $listCtr.height();\r
+\r
+               var $testCanvas = $j("<canvas></canvas>", doc)\r
+                       .addClass("undo-canvas-small")\r
+                       .addClass("far-far-away")\r
+                       .appendTo("body");\r
+\r
+               var canvasHeight = $testCanvas.height();\r
+               var canvasWidth = $testCanvas.width();\r
+               var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10);\r
+\r
+               $testCanvas.remove();\r
+\r
+               var undoRatio = canvasWidth / canvasHeight;\r
+\r
+               for (var i=undoImages.length-1;i>=0;i--) {\r
+                       (function(){\r
+                               var canvas = document.createElement("canvas");\r
+                               $j(canvas)\r
+                                       .addClass("undo-canvas-small")\r
+                                       .attr("width", canvasWidth)\r
+                                       .attr("height", canvasHeight);\r
+\r
+                               var image = undoImages[i];\r
+                               $j(image).show();\r
+                               \r
+                               var undoWidth, undoHeight;\r
+                               var imageRatio = image.width / image.height;\r
+\r
+                               if (imageRatio > undoRatio) {   // image too wide\r
+                                       undoWidth = canvasWidth;\r
+                                       undoHeight = canvasWidth / imageRatio;\r
+                               } else {\r
+                                       undoWidth = canvasHeight * imageRatio;\r
+                                       undoHeight = canvasHeight;\r
+                               }\r
+\r
+                               var restWidth = canvasWidth - undoWidth;\r
+                               var restHeight = canvasHeight - undoHeight;\r
+\r
+                               canvas.getContext("2d").drawImage(\r
+                                       image,\r
+                                       0,0,image.width,image.height,\r
+                                       restWidth*0.5, restHeight*0.5,\r
+                                       undoWidth, undoHeight\r
+                               );\r
+\r
+\r
+                               $link = $j("<a href='#'></a>", doc)\r
+                                       .addClass("undo-link")\r
+                                       .appendTo($listCtr)\r
+                                       .mouseover(function(){ $j(this).addClass("hover") })\r
+                                       .mouseout(function(){ $j(this).removeClass("hover") });\r
+                               $j(canvas).appendTo($link);\r
+\r
+                               var displayShowing;\r
+                               var undoIndex = i;\r
+                               $link.click(function() {\r
+                                       $j(image).hide();\r
+                                       $j(image).remove();\r
+                                       undo(undoIndex);\r
+                                       if (displayShowing)\r
+                                               $displayCanvas.show();\r
+                                       $j(".jcrop-holder", doc).show();\r
+                               });\r
+\r
+                               $link.mouseover(function() {\r
+                                       displayShowing = $displayCanvas.css("display") != "none";\r
+                                       var $imagectr = $j("#image-container", doc);\r
+\r
+                                       $j(".jcrop-holder", doc).hide();\r
+                                       $displayCanvas.hide();\r
+                                       $j(image).appendTo($imagectr);\r
+\r
+                                       var h1 = $j("#image-area", doc).height();\r
+                                       var h2 = image.height;\r
+                                       var m = Math.max(0, (h1 - h2) / 2);\r
+                                       $imagectr.css("marginTop", m);\r
+                       \r
+                                       $imagectr.height(image.height);\r
+                               });\r
+\r
+                               $link.mouseout(function() {\r
+                                       $j(image).remove();\r
+                                       if (displayShowing)\r
+                                               $displayCanvas.show();\r
+                                       $j(".jcrop-holder", doc).show();\r
+                                       updateDisplayCanvas();\r
+                               });\r
+\r
+\r
+                               $j(canvas).attr("title", "Click to revert to this previous image");\r
+\r
+                       })();\r
+               }\r
+       }\r
+\r
+\r
+       function applyAction(id, options, afteraction) {\r
+               if (!Pixastic.Actions[id])\r
+                       throw new Error("applyAction(): unknown action [" + id + "]");\r
+\r
+               $j("#action-bar-overlay", doc).show();\r
+\r
+               setTimeout(function() {\r
+                       options.leaveDOM = true;\r
+                       var canvasElement = $imageCanvas.get(0);\r
+                       addUndo(canvasElement)\r
+       \r
+                       var res = Pixastic.process(\r
+                               canvasElement, id, options,\r
+                               function(resCanvas) {\r
+                                       canvasElement.width = imageWidth = resCanvas.width;\r
+                                       canvasElement.height = imageHeight = resCanvas.height;\r
+       \r
+                                       var ctx = canvasElement.getContext("2d");\r
+                                       ctx.clearRect(0,0,imageWidth,imageHeight);\r
+                                       ctx.drawImage(resCanvas,0,0);\r
+                                       $imageCanvas = $j(canvasElement);\r
+                                       resetDisplayCanvas();\r
+       \r
+                                       $j("#action-bar-overlay", doc).hide();\r
+\r
+                                       if (afteraction)\r
+                                               afteraction();\r
+                               }\r
+                       );\r
+                       if (!res)\r
+                               throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]");\r
+               },1);\r
+       }\r
+\r
+\r
+       function previewAction(id, options, afteraction) {\r
+               if (!Pixastic.Actions[id])\r
+                       throw new Error("applyAction(): unknown action [" + id + "]");\r
+\r
+               $j("#action-bar-overlay", doc).show();\r
+\r
+               resetDisplayCanvas();\r
+\r
+               options.leaveDOM = true;\r
+               var canvasElement = $displayCanvas.get(0);\r
+\r
+               var res = Pixastic.process(\r
+                       canvasElement, id, options,\r
+                       function(resCanvas) {\r
+\r
+                               canvasElement.width = resCanvas.width;\r
+                               canvasElement.height = resCanvas.height;\r
+\r
+                               var ctx = canvasElement.getContext("2d");\r
+                               ctx.clearRect(0,0,canvasElement.width,canvasElement.height);\r
+                               ctx.drawImage(resCanvas,0,0);\r
+                               updateDisplayCanvas();\r
+                               updateOverlay();\r
+\r
+                               $j("#action-bar-overlay", doc).hide();\r
+\r
+                               if (afteraction)\r
+                                       afteraction();\r
+                       }\r
+               );\r
+       }\r
+\r
+       var onwindowresize = function() {\r
+               updateDisplayCanvas();\r
+               updateOverlay();\r
+       }\r
+\r
+       var baseUrl = ""\r
+\r
+       function buildEditor() {\r
+               var styles = [\r
+                       "jquery-ui-1.7.1.custom.css",\r
+                       "jquery.Jcrop.css",\r
+                       "pixastic.css"\r
+               ];\r
+\r
+               for (var i=0;i<styles.length;i++) {\r
+                       var s = doc.createElement("link");\r
+                       s.href = baseUrl + styles[i];\r
+                       s.type = "text/css";\r
+                       s.rel = "stylesheet";\r
+                       doc.getElementsByTagName("head")[0].appendChild( s );\r
+               }\r
+\r
+               undoImages = [];\r
+               accordionElements = {};\r
+               tabElements = {};\r
+               activeTabId = -1;\r
+               $activeTabContent = null;\r
+\r
+               // setup DOM UI skeleton\r
+               $editor = $j("<div />", doc)\r
+                       .attr("id", "pixastic-editor")\r
+                       .appendTo($j(doc.body));\r
+\r
+               $editor.append(\r
+                       $j("<div id='background' />", doc),\r
+                       $j("<div id='edit-ctr-1' />", doc).append(\r
+                               $j("<div id='edit-ctr-2' />", doc).append(\r
+                                       $j("<div id='controls-bar' />", doc).append(\r
+                                               $j("<div id='action-bar' />", doc).append(\r
+                                                       $j("<div id='action-bar-overlay' />", doc)\r
+                                               ),\r
+                                               $j("<div id='undo-bar' />", doc)\r
+                                       ),\r
+                                       $j("<div id='image-area' />", doc).append(\r
+                                               $j("<div id='image-area-sub' />", doc).append(\r
+                                                       $j("<div id='image-container' />", doc),\r
+                                                       $j("<div id='image-overlay-container' />", doc).append(\r
+                                                               $j("<div id='image-overlay' />", doc)\r
+                                                       )\r
+                                               )\r
+                                       )\r
+                               )\r
+                       ),\r
+                       $j("<div id='main-bar' />", doc),\r
+                       $j("<div id='powered-by-pixastic'><a href=\"http://www.pixastic.com/\" target=\"_blank\">Powered by Pixastic</a></div>", doc)\r
+               );\r
+\r
+               $j("#image-container", doc).append(\r
+                       $displayCanvas = $j("<canvas />", doc)\r
+                               .addClass("display-canvas")\r
+               );\r
+\r
+               // loop through all  defined UI action controls\r
+               var tabs = PixasticEditor.UI.data.tabs;\r
+\r
+               for (var i=0;i<tabs.length;i++) {\r
+                       (function() {\r
+       \r
+                       var tab = tabs[i];\r
+\r
+                       var $tabElement = $j("<a href=\"#\">" + tab.title + "</a>", doc)\r
+                               .attr("id", "main-tab-button-" + tab.id)\r
+                               .addClass("main-tab")\r
+                               .click(function() {\r
+                                       enableTab(tab.id);\r
+                               })\r
+                               .mouseover(function(){ $j(this).addClass("hover") })\r
+                               .mouseout(function(){ $j(this).removeClass("hover") });\r
+       \r
+                       $j("#main-bar", doc).append($tabElement);\r
+\r
+                       tabElements[tab.id] = $tabElement;\r
+\r
+                       var $menu = $j("<div/>", doc);\r
+                       accordionElements[tab.id] = $menu;\r
+\r
+                       for (var j=0;j<tab.actions.length;j++) {\r
+                               (function() {\r
+\r
+                               var action = tab.actions[j];\r
+\r
+                               var $actionElement = $j("<div><h3><a href=\"#\">" + action.title + "</a></h3></div>", doc)\r
+\r
+                               $menu.append($actionElement);\r
+\r
+                               var $content = $j("<div></div>", doc)\r
+                                       .attr("id", "pixastic-action-tab-content-" + action.id)\r
+                                       .appendTo($actionElement);\r
+\r
+                               var controlOptions = [];\r
+\r
+                               action.previewEnabled = false;\r
+                               if (action.forcePreview)\r
+                                       action.previewEnabled = true;\r
+\r
+                               function togglePreview(enable, doAction) {\r
+                                       if (enable && !action.previewEnabled && doAction)\r
+                                               doAction(true);\r
+                                       if (!enable && action.previewEnabled)\r
+                                               resetDisplayCanvas();\r
+                       \r
+                                       action.previewEnabled = enable;\r
+                               }\r
+\r
+                               var reset = function() {\r
+                                       for (var i in controlOptions) {\r
+                                               if (controlOptions.hasOwnProperty(i)) {\r
+                                                       controlOptions[i].reset();\r
+                                               }\r
+                                       }\r
+                                       if (action.previewEnabled)\r
+                                               doAction(true);\r
+                               }\r
+                               var doAction = function(isPreview) {\r
+                                       var options = {};\r
+                                       for (var i in controlOptions) {\r
+                                               if (controlOptions.hasOwnProperty(i)) {\r
+                                                       options[i] = controlOptions[i].valueField.val();\r
+                                               }\r
+                                       }\r
+\r
+                                       var afteraction = function() {\r
+                                               if (action.onafteraction)\r
+                                                       action.onafteraction(action, isPreview);\r
+                                               if (!isPreview)\r
+                                                       resetDisplayCanvas();\r
+       \r
+                                               if (!isPreview && !action.forcePreview) {\r
+                                                       $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false);\r
+                                                       togglePreview(false);\r
+                                                       reset();\r
+                                               }\r
+                                       }\r
+\r
+                                       if (isPreview) {\r
+                                               previewAction(action.id, options, afteraction);\r
+                                       } else {\r
+                                               applyAction(action.id, options, afteraction);\r
+                                       }\r
+\r
+                               }\r
+\r
+                               var hadInputs = false;\r
+\r
+                               if (action.controls) {\r
+                                       var onChange = function() {};\r
+                                       if (action.isAction && action.preview) {\r
+                                               onChange = function() {\r
+                                                       if (action.previewEnabled)\r
+                                                               doAction(true)\r
+                                               };\r
+                                       }\r
+\r
+                                       for (var k=0;k<action.controls.length;k++) {\r
+                                               var control = action.controls[k];\r
+                                               if (typeof control.defaultValue != "function") {\r
+                                                       (function(){\r
+                                                       var defVal = control.defaultValue;\r
+                                                       control.defaultValue = function() {\r
+                                                               return defVal;\r
+                                                       }\r
+                                                       })();\r
+                                               }\r
+                                               var controlId = action.id + "-" + control.option;\r
+\r
+                                               if (control.type != "output")\r
+                                                       hadInputs = true;\r
+\r
+                                               switch (control.type) {\r
+                                                       case "number" :\r
+                                                               switch (control.ui) {\r
+                                                                       case "slider" : \r
+                                                                               var slider = PixasticEditor.UI.makeSlider(\r
+                                                                                       control.label, controlId, \r
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
+                                                                               );\r
+               \r
+                                                                               slider.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = slider;\r
+                                                                               break;\r
+                                                                       case "text" : \r
+                                                                               var text = PixasticEditor.UI.makeNumericInput(\r
+                                                                                       control.label, control.labelRight, controlId, \r
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
+                                                                               );\r
+                                                                               text.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = text;\r
+                                                                               break;\r
+                                                               }\r
+                                                               break;\r
+                                                       case "boolean" :\r
+                                                               switch (control.ui) {\r
+                                                                       case "checkbox" : \r
+                                                                               var checkbox = PixasticEditor.UI.makeCheckbox(\r
+                                                                                       control.label, controlId, control.defaultValue, onChange\r
+                                                                               );\r
+               \r
+                                                                               checkbox.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = checkbox;\r
+                                                                               break;\r
+                                                               }\r
+                                                       case "string" :\r
+                                                               switch (control.ui) {\r
+                                                                       case "select" : \r
+                                                                               var select = PixasticEditor.UI.makeSelect(\r
+                                                                                       control.label, controlId, control.values, control.defaultValue, onChange\r
+                                                                               );\r
+               \r
+                                                                               select.container.appendTo($content);\r
+                                                                               controlOptions[control.option] = select;\r
+                                                                               break;\r
+                                                               }\r
+                                                               break;\r
+                                                       case "output" :\r
+                                                               var outputText = $j("<div></div>", doc)\r
+                                                                       .addClass("ui-action-output")\r
+                                                                       .html(control.content)\r
+                                                                       .appendTo($content);\r
+                                                               break;\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               if (action.isAction) {\r
+\r
+                                       var $applyButton = PixasticEditor.UI.makeButton("Apply")\r
+                                               .addClass("pixastic-option-button-apply")\r
+                                               .click(function() {doAction();});\r
+\r
+                                       $content.append($applyButton);\r
+\r
+                                       if (hadInputs) {\r
+                                               var $resetButton = PixasticEditor.UI.makeButton("Reset")\r
+                                                       .addClass("pixastic-option-button-reset")\r
+                                                       .click(reset);\r
+       \r
+                                               $content.append($resetButton)\r
+                                       }\r
+\r
+                                       if (action.preview && !action.forcePreview) {\r
+                                               var $checkctr = $j("<div></div>", doc)\r
+                                                       .addClass("ui-checkbox-container")\r
+                                                       .addClass("ui-preview-checkbox-container");\r
+\r
+                                               var $label = $j("<label></label>", doc)\r
+                                                       .addClass("ui-checkbox-label")\r
+                                                       .attr("for", "pixastic-input-preview-" + action.id)\r
+                                                       .html("Preview:")\r
+                                                       .appendTo($checkctr);\r
+\r
+                                               var $checkbox = $j("<input type=\"checkbox\"></input>", doc)\r
+                                                       .addClass("ui-checkbox")\r
+                                                       .attr("id", "pixastic-input-preview-" + action.id)\r
+                                                       .appendTo($checkctr)\r
+                                                       .change(function() {\r
+                                                               togglePreview(this.checked, doAction)\r
+                                                       });\r
+\r
+                                               $content.append($checkctr);\r
+\r
+                                               $content.data("previewCheckbox", $checkbox);\r
+                                       }\r
+\r
+                               }\r
+\r
+\r
+                               if (typeof action.content == "function") {\r
+                                       action.content($content);\r
+                               }\r
+\r
+                               // stupid hack to make it possible to get $content in change event (below)\r
+                               $j("<span></span>", doc).appendTo($content);\r
+\r
+                               $content.data("controlOptions", controlOptions);\r
+                               $content.data("onactivate", action.onactivate);\r
+                               $content.data("ondeactivate", action.ondeactivate);\r
+                               $content.data("onoverlayupdate", action.onoverlayupdate);\r
+                               $content.data("accordionindex", j);\r
+                               $content.data("uidesc", action);\r
+\r
+                               })();\r
+                       }\r
+       \r
+                       $j("#action-bar", doc).append($menu);\r
+\r
+                       $menu.hide().accordion({\r
+                               header: "h3",\r
+                               autoHeight : false,\r
+                               collapsible : true,\r
+                               active: -1\r
+                       })\r
+                       .bind("accordionchange", \r
+                               function(event, ui) {\r
+                                       resetDisplayCanvas();\r
+\r
+                                       // oldContent / newContent are arrays of whatever elements are present in the content area\r
+                                       // We need the parent element (the one holding the content) but if there is no content, how do we get it?\r
+                                       // fixed above by always appending a <span> but that's ugly and needs to be done in some other way\r
+                                       if (ui.oldContent.get(0)) {\r
+                                               var $parent = $j(ui.oldContent.get(0).parentNode);\r
+                                               if ($parent.data("ondeactivate")) {\r
+                                                       $parent.data("ondeactivate")();\r
+                                               }\r
+                                       }\r
+                                       $activeTabContent = ui.newContent;\r
+\r
+                                       if (ui.newContent.get(0)) {\r
+                                               var $parent = $j(ui.newContent.get(0).parentNode);\r
+                                               if ($parent.data("previewCheckbox"))\r
+                                                       $parent.data("previewCheckbox").attr("checked", false);\r
+                                               $parent.data("uidesc").previewEnabled = false;\r
+                                               if ($parent.data("uidesc").forcePreview)\r
+                                                       $parent.data("uidesc").previewEnabled = true;\r
+\r
+                                               var controlOptions = $parent.data("controlOptions");\r
+                                               for (var i in controlOptions) {\r
+                                                       if (controlOptions.hasOwnProperty(i)) {\r
+                                                               controlOptions[i].reset();\r
+                                                       }\r
+                                               }\r
+                                               if ($parent.data("onactivate")) {\r
+                                                       $parent.data("onactivate")();\r
+                                               }\r
+                                       }\r
+                                       updateDisplayCanvas();\r
+\r
+                               }\r
+                       );\r
+\r
+       \r
+                       })();\r
+               }\r
+\r
+               $j(window).bind("resize", onwindowresize);\r
+       }\r
+\r
+       function showLoadingScreen() {\r
+               if ($loadingScreen) {\r
+                       $loadingScreen.show();\r
+                       return;\r
+               }\r
+               $loadingScreen = $j("<div id=\"loading-screen\" />")\r
+               var $ctr = $j("<div id=\"loading-screen-cell\" />");\r
+               $j("<div />")\r
+                       .addClass("spinner")\r
+                       .appendTo($ctr);\r
+               $loadingScreen.append($ctr);\r
+               $loadingScreen.appendTo("body");\r
+       }\r
+\r
+       function hideLoadingScreen() {\r
+               setTimeout(function() {\r
+                       $loadingScreen.hide();\r
+               }, 1);\r
+       }\r
+\r
+       var oldScrollLeft;\r
+       var oldScrollTop;\r
+       var oldOverflow;\r
+\r
+       // fire it up\r
+       function init(callback) {\r
+               isRunning = true;\r
+\r
+               showLoadingScreen();\r
+\r
+               oldScrollLeft = document.body.scrollLeft;\r
+               oldScrollTop = document.body.scrollTop;\r
+               oldOverflow = document.body.style.overflow;\r
+\r
+               document.body.scrollLeft = 0;\r
+               document.body.scrollTop = 0;\r
+               document.body.style.overflow = "hidden";\r
+\r
+               $frame = $j("<iframe />");\r
+               $frame.hide();\r
+               $frame.css({\r
+                       position : "absolute",\r
+                       left : document.body.scrollLeft + "px",\r
+                       top : document.body.scrollTop + "px",\r
+                       width : "100%",\r
+                       height : "100%",\r
+                       zIndex : "11"\r
+               });\r
+               $frame.load(function(){\r
+                       doc = $frame.get(0).contentDocument;\r
+\r
+                       buildEditor();\r
+                       callback();\r
+                       $frame.show();\r
+                       hideLoadingScreen();\r
+                       setTimeout(function(){\r
+                               updateDisplayCanvas();\r
+                       },10);\r
+               });\r
+               $frame.appendTo("body");\r
+       }\r
+\r
+       // unload the editor, remove all elements added to the page and restore whatever properties we messed with\r
+       function unload() {\r
+               $j(window).unbind("resize", onwindowresize);\r
+               $frame.hide();\r
+               $editor.hide();\r
+               $editor.remove();\r
+               $frame.remove();\r
+\r
+               document.body.scrollLeft = oldScrollLeft;\r
+               document.body.scrollTop = oldScrollTop;\r
+               document.body.style.overflow = oldOverflow;\r
+\r
+               isRunning = false;\r
+       }\r
+\r
+\r
+       // resets the display canvas (clears the canvas and repaints the current state)\r
+       // then updates display and overlay\r
+       function resetDisplayCanvas() {\r
+               if (!($displayCanvas && $displayCanvas.get))    throw new Error(errorDialog("$displayCanvas doesn't exist"));\r
+               if (!($imageCanvas && $imageCanvas.get))        throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
+\r
+               var display = $displayCanvas.get(0);\r
+               var image = $imageCanvas.get(0);\r
+\r
+               if (!display)   throw new Error(errorDialog("resetDisplayCanvas(): No elements in $displayCanvas"));\r
+               if (!image)     throw new Error(errorDialog("resetDisplayCanvas(): No elements in $imageCanvas"));\r
+\r
+               display.width = imageWidth;\r
+               display.height = imageHeight;\r
+               display.getContext("2d").drawImage( image, 0, 0 );\r
+\r
+               updateDisplayCanvas();\r
+               updateOverlay();\r
+       }\r
+\r
+       // updates the display by resetting the height and margin of the image container\r
+       // this is mainly to keep vertical centering\r
+       function updateDisplayCanvas() {\r
+               var $imageCtr = $j("#image-container", doc);\r
+               var $editArea = $j("#image-area", doc);\r
+\r
+               if (!$imageCtr.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $imageCtr doesn't exist"));\r
+               if (!$displayCanvas.get(0))     throw new Error(errorDialog("updateDisplayCanvas(): $displayCanvas doesn't exist"));\r
+               if (!$editArea.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $editArea doesn't exist"));\r
+\r
+               var h2 = $displayCanvas.get(0).height;\r
+               var h1 = $j("#image-area", doc).height();\r
+               var m = Math.max(0, (h1 - h2) / 2);\r
+               $imageCtr.height(h2);\r
+               $imageCtr.css("marginTop", m);\r
+       }\r
+\r
+       // basically the same as updateDisplayCanvas but for the image overlay\r
+       function updateOverlay() {\r
+               var $overlay = $j("#image-overlay-container", doc);\r
+               var $imagectr = $j("#image-container", doc);\r
+               $overlay.height($imagectr.height());\r
+               $overlay.css("marginTop", $imagectr.css("marginTop"));\r
+\r
+               if ($activeTabContent && $activeTabContent.get(0)) {\r
+                       var $tabContent = $j($activeTabContent.get(0).parentNode);\r
+                       if (typeof $tabContent.data("onoverlayupdate") == "function")\r
+                               $tabContent.data("onoverlayupdate")();\r
+               }\r
+       }\r
+\r
+       var imageIsLoading = false;\r
+       var originalImageElement;\r
+       var $tmpImg;\r
+\r
+       function loadImage(imgEl) {\r
+               if (imageIsLoading) \r
+                       return;\r
+\r
+               imageIsLoading = true;\r
+\r
+               originalImageElement = imgEl;\r
+\r
+               $imageCanvas = $j("<canvas />", doc);\r
+               imageCtx = $imageCanvas.get(0).getContext("2d");\r
+\r
+               imageWidth = 0;\r
+               imageHeight = 0;\r
+               $imageCanvas.attr("width", 0);\r
+               $imageCanvas.attr("height", 0);\r
+\r
+               if (imgEl.tagName.toLowerCase() == "img" && !imgEl._pixasticCanvas) {\r
+                       var onload = function(el) {\r
+                               imageWidth = el.offsetWidth;\r
+                               imageHeight = el.offsetHeight;\r
+                               $imageCanvas.attr("width", imageWidth);\r
+                               $imageCanvas.attr("height", imageHeight);\r
+                               imageCtx.drawImage(el,0,0);\r
+                               $tmpImg.remove();\r
+                               imageIsLoading = false;\r
+                               enableTab("reshape");\r
+                               setTimeout(function() {\r
+                                       resetDisplayCanvas();\r
+                               }, 10);\r
+                       }\r
+                       $tmpImg = $j("<img />", doc)\r
+                               .css("position", "absolute")\r
+                               .css("left", "-9999px")\r
+                               .css("top", "-9999px")\r
+                               .appendTo("body")\r
+                               .load(function(){onload(this);})\r
+                               .error(function(){\r
+                                       throw new Error("Could not load temporary copy image. Is provided image valid?");\r
+                                       unload();\r
+                               })\r
+                               .attr("src", imgEl.src);\r
+                               if ($tmpImg.attr("complete")) {\r
+                                       onload($tmpImg.get(0));\r
+                               }\r
+               } else {\r
+                       var $canvas = imgEl._pixasticCanvas || imgEl;\r
+                       imageWidth = $canvas.attr("width");\r
+                       imageHeight = $canvas.attr("height");\r
+                       $imageCanvas.attr("width", imageWidth);\r
+                       $imageCanvas.attr("height", imageHeight);\r
+                       imageCtx.drawImage($canvas.get(0), 0, 0);\r
+                       imageIsLoading = false;\r
+                       enableTab("reshape");\r
+                       resetDisplayCanvas();\r
+               }\r
+       }\r
+\r
+       // return public interface\r
+       return {\r
+               /*\r
+               // don't call. For now we must load the image immediately via load()\r
+               loadImage : function(imgEl) {\r
+                       if (!isRunning) return false;\r
+                       loadImage(imgEl);\r
+               },\r
+               */\r
+               saveToPage : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::saveToPage(): Editor is not running");\r
+\r
+                       var $canvas = PixasticEditor.getImageCanvas();\r
+                       var img = PixasticEditor.getOriginalImage();\r
+                       if (img.tagName.toLowerCase() == "canvas") {\r
+                               img.width = $canvas.attr("width");\r
+                               img.height = $canvas.attr("height");\r
+                               img.getContext("2d").drawImage($canvas.get(0), 0, 0);\r
+                       } else {\r
+                               img.src = PixasticEditor.getDataURI();\r
+                       }\r
+                       img._pixasticCanvas = PixasticEditor.getImageCanvas();\r
+               },\r
+               load : function(img, customBaseUrl) {\r
+                       if (isRunning) return false;\r
+\r
+                       if (!img)\r
+                               throw new Error("Must be called with an image or canvas as its first argument", "PixasticEditor::load")\r
+\r
+                       $ = PixasticEditor.jQuery;\r
+\r
+                       baseUrl = customBaseUrl || "http://www.pixastic.com/editor-test/";\r
+\r
+                       init(function() {\r
+                               if (img && img.tagName.toLowerCase() == "img" || img.tagName.toLowerCase() == "canvas") {\r
+                                       loadImage(img);\r
+                               }\r
+                       });\r
+               },\r
+\r
+               unload : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::unload(): Editor is not running");\r
+                       unload();\r
+               },\r
+\r
+               getDocument : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDocument(): Editor is not running");\r
+\r
+                       return doc;\r
+               },\r
+\r
+               validSaveFormats : function() {\r
+                       return saveFormats;\r
+               },\r
+\r
+               getOriginalImage : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getOriginalImage(): Editor is not running");\r
+                       return originalImageElement;\r
+               },\r
+\r
+               getDataURI : function(mime) {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDataURI(): Editor is not running");\r
+\r
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
+\r
+                       return $imageCanvas.get(0).toDataURL(mime||"image/png");\r
+               },\r
+\r
+               getImageCanvas : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getImageCanvas(): Editor is not running");\r
+\r
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
+\r
+                       return $imageCanvas;\r
+               },\r
+               getOverlay : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getOverlay(): Editor is not running");\r
+\r
+                       return $j("#image-overlay", doc);\r
+               },\r
+               getDisplayCanvas : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayCanvas(): Editor is not running");\r
+\r
+                       if (!($displayCanvas && $displayCanvas.get && $displayCanvas.get(0)))\r
+                               throw new Error(errorDialog("$displayCanvas doesn't exist", "getDisplayCanvas"));\r
+                       return $displayCanvas;\r
+               },\r
+               getDisplayWidth : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayWidth(): Editor is not running");\r
+\r
+                       return displayWidth;\r
+               },\r
+               getDisplayHeight : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayHeight(): Editor is not running");\r
+\r
+                       return displayHeight;\r
+               },\r
+               getImageWidth : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getImageWidth(): Editor is not running");\r
+\r
+                       return imageWidth;\r
+               },\r
+               getImageHeight : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::getImageHeight(): Editor is not running");\r
+\r
+                       return imageHeight;\r
+               },\r
+               errorDialog : function() {\r
+                       if (!isRunning) throw new Error("PixasticEditor::errorDialog(): Editor is not running");\r
+\r
+                       return errorDialog.apply(null, arguments);\r
+               }\r
+       }\r
+\r
+})();
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.all.js b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.all.js
new file mode 100644 (file)
index 0000000..fa38d04
--- /dev/null
@@ -0,0 +1,3169 @@
+/*\r
+ * Pixastic Lib - Core Functions - v0.1.3\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+var Pixastic = (function() {\r
+\r
+\r
+       function addEvent(el, event, handler) {\r
+               if (el.addEventListener)\r
+                       el.addEventListener(event, handler, false); \r
+               else if (el.attachEvent)\r
+                       el.attachEvent("on" + event, handler); \r
+       }\r
+\r
+       function onready(handler) {\r
+               var handlerDone = false;\r
+               var execHandler = function() {\r
+                       if (!handlerDone) {\r
+                               handlerDone = true;\r
+                               handler();\r
+                       }\r
+               }\r
+               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");\r
+               var script = document.getElementById("__onload_ie_sumbox__");\r
+               script.onreadystatechange = function() {\r
+                       if (script.readyState == "complete") {\r
+                               script.parentNode.removeChild(script);\r
+                               execHandler();\r
+                       }\r
+               }\r
+               if (document.addEventListener)\r
+                       document.addEventListener("DOMContentLoaded", execHandler, false); \r
+               addEvent(window, "load", execHandler);\r
+       }\r
+\r
+       function init() {\r
+               if (!Pixastic.parseOnLoad) return;\r
+               var imgEls = getElementsByClass("pixastic", null, "img");\r
+               var canvasEls = getElementsByClass("pixastic", null, "canvas");\r
+               var elements = imgEls.concat(canvasEls);\r
+               for (var i=0;i<elements.length;i++) {\r
+                       (function() {\r
+\r
+                       var el = elements[i];\r
+                       var actions = [];\r
+                       var classes = el.className.split(" ");\r
+                       for (var c=0;c<classes.length;c++) {\r
+                               var cls = classes[c];\r
+                               if (cls.substring(0,9) == "pixastic-") {\r
+                                       var actionName = cls.substring(9);\r
+                                       if (actionName != "")\r
+                                               actions.push(actionName);\r
+                               }\r
+                       }\r
+                       if (actions.length) {\r
+                               if (el.tagName.toLowerCase() == "img") {\r
+                                       var dataImg = new Image();\r
+                                       dataImg.src = el.src;\r
+                                       if (dataImg.complete) {\r
+                                               for (var a=0;a<actions.length;a++) {\r
+                                                       var res = Pixastic.applyAction(el, el, actions[a], null);\r
+                                                       if (res) \r
+                                                               el = res;\r
+                                               }\r
+                                       } else {\r
+                                               dataImg.onload = function() {\r
+                                                       for (var a=0;a<actions.length;a++) {\r
+                                                               var res = Pixastic.applyAction(el, el, actions[a], null)\r
+                                                               if (res) \r
+                                                                       el = res;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } else {\r
+                                       setTimeout(function() {\r
+                                               for (var a=0;a<actions.length;a++) {\r
+                                                       var res = Pixastic.applyAction(\r
+                                                               el, el, actions[a], null\r
+                                                       );\r
+                                                       if (res) \r
+                                                               el = res;\r
+                                               }\r
+                                       },1);\r
+                               }\r
+                       }\r
+\r
+                       })();\r
+               }\r
+       }\r
+\r
+//     if (typeof pixastic_no_onready == "undefined") // yuck.\r
+//             onready(init);\r
+\r
+       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/\r
+       function getElementsByClass(searchClass,node,tag) {\r
+               var classElements = new Array();\r
+               if ( node == null )\r
+                       node = document;\r
+               if ( tag == null )\r
+                       tag = '*';\r
+\r
+               var els = node.getElementsByTagName(tag);\r
+               var elsLen = els.length;\r
+               var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");\r
+               for (i = 0, j = 0; i < elsLen; i++) {\r
+                       if ( pattern.test(els[i].className) ) {\r
+                               classElements[j] = els[i];\r
+                               j++;\r
+                       }\r
+               }\r
+               return classElements;\r
+       }\r
+\r
+       var debugElement;\r
+\r
+       function writeDebug(text, level) {\r
+               if (!Pixastic.debug) return;\r
+               try {\r
+                       switch (level) {\r
+                               case "warn" : \r
+                                       console.warn("Pixastic:", text);\r
+                                       break;\r
+                               case "error" :\r
+                                       console.error("Pixastic:", text);\r
+                                       break;\r
+                               default:\r
+                                       console.log("Pixastic:", text);\r
+                       }\r
+               } catch(e) {\r
+               }\r
+               if (!debugElement) {\r
+                       \r
+               }\r
+       }\r
+\r
+\r
+       return {\r
+\r
+               parseOnLoad : false,\r
+\r
+               debug : false,\r
+               \r
+               applyAction : function(img, dataImg, actionName, options) {\r
+\r
+                       options = options || {};\r
+\r
+                       var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");\r
+                       if (imageIsCanvas && Pixastic.Client.isIE()) {\r
+                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");\r
+                               return false;\r
+                       }\r
+\r
+                       var canvas, ctx;\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               canvas = document.createElement("canvas");\r
+                               ctx = canvas.getContext("2d");\r
+                       }\r
+\r
+                       var w = parseInt(img.offsetWidth);\r
+                       var h = parseInt(img.offsetHeight);\r
+\r
+                       if (imageIsCanvas) {\r
+                               w = img.width;\r
+                               h = img.height;\r
+                       }\r
+\r
+                       if (actionName.indexOf("(") > -1) {\r
+                               var tmp = actionName;\r
+                               actionName = tmp.substr(0, tmp.indexOf("("));\r
+                               var arg = tmp.match(/\((.*?)\)/);\r
+                               if (arg[1]) {\r
+                                       arg = arg[1].split(";");\r
+                                       for (var a=0;a<arg.length;a++) {\r
+                                               thisArg = arg[a].split("=");\r
+                                               if (thisArg.length == 2) {\r
+                                                       if (thisArg[0] == "rect") {\r
+                                                               var rectVal = thisArg[1].split(",");\r
+                                                               options[thisArg[0]] = {\r
+                                                                       left : parseInt(rectVal[0],10)||0,\r
+                                                                       top : parseInt(rectVal[1],10)||0,\r
+                                                                       width : parseInt(rectVal[2],10)||0,\r
+                                                                       height : parseInt(rectVal[3],10)||0\r
+                                                               }\r
+                                                       } else {\r
+                                                               options[thisArg[0]] = thisArg[1];\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if (!options.rect) {\r
+                               options.rect = {\r
+                                       left : 0, top : 0, width : w, height : h\r
+                               };\r
+                       }\r
+                       var validAction = false;\r
+                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {\r
+                               validAction = true;\r
+                       }\r
+                       if (!validAction) {\r
+                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");\r
+                               return false;\r
+                       }\r
+                       if (!Pixastic.Actions[actionName].checkSupport()) {\r
+                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");\r
+                               return false;\r
+                       }\r
+\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               canvas.width = w;\r
+                               canvas.height = h;\r
+                               canvas.style.width = w+"px";\r
+                               canvas.style.height = h+"px";\r
+                               ctx.drawImage(dataImg,0,0,w,h);\r
+\r
+                               if (!img.__pixastic_org_image) {\r
+                                       canvas.__pixastic_org_image = img;\r
+                                       canvas.__pixastic_org_width = w;\r
+                                       canvas.__pixastic_org_height = h;\r
+                               } else {\r
+                                       canvas.__pixastic_org_image = img.__pixastic_org_image;\r
+                                       canvas.__pixastic_org_width = img.__pixastic_org_width;\r
+                                       canvas.__pixastic_org_height = img.__pixastic_org_height;\r
+                               }\r
+\r
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {\r
+                               img.__pixastic_org_style = img.style.cssText;\r
+                       }\r
+\r
+                       var params = {\r
+                               image : img,\r
+                               canvas : canvas,\r
+                               width : w,\r
+                               height : h,\r
+                               useData : true,\r
+                               options : options\r
+                       }\r
+\r
+                       // Ok, let's do it!\r
+\r
+                       var res = Pixastic.Actions[actionName].process(params);\r
+\r
+                       if (!res) {\r
+                               return false;\r
+                       }\r
+\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               if (params.useData) {\r
+                                       if (Pixastic.Client.hasCanvasImageData()) {\r
+                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);\r
+\r
+                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.\r
+                                               canvas.getContext("2d").fillRect(0,0,0,0);\r
+                                       }\r
+                               }\r
+\r
+                               if (!options.leaveDOM) {\r
+                                       // copy properties and stuff from the source image\r
+                                       canvas.title = img.title;\r
+                                       canvas.imgsrc = img.imgsrc;\r
+                                       if (!imageIsCanvas) canvas.alt  = img.alt;\r
+                                       if (!imageIsCanvas) canvas.imgsrc = img.src;\r
+                                       canvas.className = img.className;\r
+                                       canvas.style.cssText = img.style.cssText;\r
+                                       canvas.name = img.name;\r
+                                       canvas.tabIndex = img.tabIndex;\r
+                                       canvas.id = img.id;\r
+                                       if (img.parentNode && img.parentNode.replaceChild) {\r
+                                               img.parentNode.replaceChild(canvas, img);\r
+                                       }\r
+                               }\r
+\r
+                               options.resultCanvas = canvas;\r
+\r
+                               return canvas;\r
+                       }\r
+\r
+                       return img;\r
+               },\r
+\r
+               prepareData : function(params, getCopy) {\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       var rect = params.options.rect;\r
+                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);\r
+                       var data = dataDesc.data;\r
+                       if (!getCopy) params.canvasData = dataDesc;\r
+                       return data;\r
+               },\r
+\r
+               // load the image file\r
+               process : function(img, actionName, options, callback)\r
+               {\r
+                       if (img.tagName.toLowerCase() == "img") {\r
+                               var dataImg = new Image();\r
+                               dataImg.src = img.src;\r
+                               if (dataImg.complete) {\r
+                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);\r
+                                       if (callback) callback(res);\r
+                                       return res;\r
+                               } else {\r
+                                       dataImg.onload = function() {\r
+                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)\r
+                                               if (callback) callback(res);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (img.tagName.toLowerCase() == "canvas") {\r
+                               var res = Pixastic.applyAction(img, img, actionName, options);\r
+                               if (callback) callback(res);\r
+                               return res;\r
+                       }\r
+               },\r
+\r
+               revert : function(img) {\r
+                       if (Pixastic.Client.hasCanvas()) {\r
+                               if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {\r
+                                       img.width = img.__pixastic_org_width;\r
+                                       img.height = img.__pixastic_org_height;\r
+                                       img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);\r
+\r
+                                       if (img.parentNode && img.parentNode.replaceChild) {\r
+                                               img.parentNode.replaceChild(img.__pixastic_org_image, img);\r
+                                       }\r
+\r
+                                       return img;\r
+                               }\r
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {\r
+                               img.style.cssText = img.__pixastic_org_style;\r
+                       }\r
+               },\r
+\r
+               Client : {\r
+                       hasCanvas : (function() {\r
+                               var c = document.createElement("canvas");\r
+                               var val = false;\r
+                               try {\r
+                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));\r
+                               } catch(e) {}\r
+                               return function() {\r
+                                       return val;\r
+                               }\r
+                       })(),\r
+\r
+                       hasCanvasImageData : (function() {\r
+                               var c = document.createElement("canvas");\r
+                               var val = false;\r
+                               var ctx;\r
+                               try {\r
+                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {\r
+                                               val = (typeof ctx.getImageData == "function");\r
+                                       }\r
+                               } catch(e) {}\r
+                               return function() {\r
+                                       return val;\r
+                               }\r
+                       })(),\r
+\r
+                       isIE : function() {\r
+                               return !!document.all && !!window.attachEvent && !window.opera;\r
+                       }\r
+               },\r
+\r
+               Actions : {}\r
+       }\r
+\r
+\r
+})();\r
+/*\r
+ * Pixastic Lib - jQuery plugin\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {\r
+       jQuery.fn.pixastic = function(action, options) {\r
+               var newElements = [];\r
+               this.each(\r
+                       function () {\r
+                               if (this.tagName.toLowerCase() == "img" && !this.complete) {\r
+                                       return;\r
+                               }\r
+                               var res = Pixastic.process(this, action, options);\r
+                               if (res) {\r
+                                       newElements.push(res);\r
+                               }\r
+                       }\r
+               );\r
+               if (newElements.length > 0)\r
+                       return jQuery(newElements);\r
+               else\r
+                       return this;\r
+       };\r
+\r
+};\r
+/*\r
+ * Pixastic Lib - Blend - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.blend = {\r
+\r
+       process : function(params) {\r
+               var amount = parseFloat(params.options.amount);\r
+               var mode = (params.options.mode || "normal").toLowerCase();\r
+               var image = params.options.image;\r
+\r
+               amount = Math.max(0,Math.min(1,amount));\r
+\r
+               if (!image) return false;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+                       var data = Pixastic.prepareData(params);\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       params.useData = false;\r
+\r
+                       var otherCanvas = document.createElement("canvas");\r
+                       otherCanvas.width = params.canvas.width;\r
+                       otherCanvas.height = params.canvas.height;\r
+                       var otherCtx = otherCanvas.getContext("2d");\r
+                       otherCtx.drawImage(image,0,0);\r
+\r
+                       var params2 = {canvas:otherCanvas,options:params.options};\r
+                       var data2 = Pixastic.prepareData(params2);\r
+                       var dataDesc2 = params2.canvasData;\r
+\r
+                       var p = w*h;\r
+                       var pix = p*4;\r
+                       var pix1, pix2;\r
+                       var r1, g1, b1;\r
+                       var r2, g2, b2;\r
+                       var r3, g3, b3;\r
+                       var r4, g4, b4;\r
+\r
+                       var dataChanged = false;\r
+\r
+                       switch (mode) {\r
+                               case "normal" : \r
+                                       //while (p--) {\r
+                                       //      data2[pix-=4] = data2[pix];\r
+                                       //      data2[pix1=pix+1] = data2[pix1];\r
+                                       //      data2[pix2=pix+2] = data2[pix2];\r
+                                       //}\r
+                                       break;\r
+\r
+                               case "multiply" : \r
+                                       while (p--) {\r
+                                               data2[pix-=4] = data[pix] * data2[pix] / 255;\r
+                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;\r
+                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "lighten" : \r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) > data2[pix])\r
+                                                       data2[pix] = r1;\r
+                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])\r
+                                                       data2[pix1] = g1;\r
+                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])\r
+                                                       data2[pix2] = b1;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "darken" : \r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) < data2[pix])\r
+                                                       data2[pix] = r1;\r
+                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])\r
+                                                       data2[pix1] = g1;\r
+                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])\r
+                                                       data2[pix2] = b1;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "darkercolor" : \r
+                                       while (p--) {\r
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
+                                                       data2[pix] = r1;\r
+                                                       data2[pix1] = g1;\r
+                                                       data2[pix2] = b1;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "lightercolor" : \r
+                                       while (p--) {\r
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
+                                                       data2[pix] = r1;\r
+                                                       data2[pix1] = g1;\r
+                                                       data2[pix2] = b1;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "lineardodge" : \r
+                                       otherCtx.globalCompositeOperation = "source-over";\r
+                                       otherCtx.drawImage(params.canvas, 0, 0);\r
+                                       otherCtx.globalCompositeOperation = "lighter";\r
+                                       otherCtx.drawImage(image, 0, 0);\r
+\r
+                                       /*\r
+                                       while (p--) {\r
+                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)\r
+                                                       data2[pix] = 255;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)\r
+                                                       data2[pix1] = 255;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)\r
+                                                       data2[pix2] = 255;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       */\r
+\r
+                                       break;\r
+\r
+                               case "linearburn" : \r
+                                       while (p--) {\r
+                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)\r
+                                                       data2[pix] = 0;\r
+                                               else\r
+                                                       data2[pix] = (r3 - 255);\r
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)\r
+                                                       data2[pix1] = 0;\r
+                                               else\r
+                                                       data2[pix1] = (g3 - 255);\r
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)\r
+                                                       data2[pix2] = 0;\r
+                                               else\r
+                                                       data2[pix2] = (b3 - 255);\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "difference" : \r
+                                       while (p--) {\r
+                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)\r
+                                                       data2[pix] = -r3;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)\r
+                                                       data2[pix1] = -g3;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)\r
+                                                       data2[pix2] = -b3;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "screen" : \r
+                                       while (p--) {\r
+                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));\r
+                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));\r
+                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "exclusion" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];\r
+                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];\r
+                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "overlay" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) < 128)\r
+                                                       data2[pix] = data2[pix]*r1*div_2_255;\r
+                                               else\r
+                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;\r
+\r
+                                               if ((g1 = data[pix1=pix+1]) < 128)\r
+                                                       data2[pix1] = data2[pix1]*g1*div_2_255;\r
+                                               else\r
+                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;\r
+\r
+                                               if ((b1 = data[pix2=pix+2]) < 128)\r
+                                                       data2[pix2] = data2[pix2]*b1*div_2_255;\r
+                                               else\r
+                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "softlight" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               if ((r1 = data[pix-=4]) < 128)\r
+                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;\r
+                                               else\r
+                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;\r
+\r
+                                               if ((g1 = data[pix1=pix+1]) < 128)\r
+                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;\r
+                                               else\r
+                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;\r
+\r
+                                               if ((b1 = data[pix2=pix+2]) < 128)\r
+                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;\r
+                                               else\r
+                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "hardlight" : \r
+                                       var div_2_255 = 2 / 255;\r
+                                       while (p--) {\r
+                                               if ((r2 = data2[pix-=4]) < 128)\r
+                                                       data2[pix] = data[pix] * r2 * div_2_255;\r
+                                               else\r
+                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;\r
+\r
+                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
+                                                       data2[pix1] = data[pix1] * g2 * div_2_255;\r
+                                               else\r
+                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;\r
+\r
+                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
+                                                       data2[pix2] = data[pix2] * b2 * div_2_255;\r
+                                               else\r
+                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;\r
+\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "colordodge" : \r
+                                       while (p--) {\r
+                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)\r
+                                                       data2[pix] = 255;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+\r
+                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)\r
+                                                       data2[pix1] = 255;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+\r
+                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)\r
+                                                       data2[pix2] = 255;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "colorburn" : \r
+                                       while (p--) {\r
+                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)\r
+                                                       data2[pix] = 0;\r
+                                               else\r
+                                                       data2[pix] = r3;\r
+\r
+                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)\r
+                                                       data2[pix1] = 0;\r
+                                               else\r
+                                                       data2[pix1] = g3;\r
+\r
+                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)\r
+                                                       data2[pix2] = 0;\r
+                                               else\r
+                                                       data2[pix2] = b3;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "linearlight" : \r
+                                       while (p--) {\r
+                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {\r
+                                                       data2[pix] = 0\r
+                                               } else {\r
+                                                       if (r3 > 255)\r
+                                                               data2[pix] = 255;\r
+                                                       else\r
+                                                               data2[pix] = r3;\r
+                                               }\r
+                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {\r
+                                                       data2[pix1] = 0\r
+                                               } else {\r
+                                                       if (g3 > 255)\r
+                                                               data2[pix1] = 255;\r
+                                                       else\r
+                                                               data2[pix1] = g3;\r
+                                               }\r
+                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {\r
+                                                       data2[pix2] = 0\r
+                                               } else {\r
+                                                       if (b3 > 255)\r
+                                                               data2[pix2] = 255;\r
+                                                       else\r
+                                                               data2[pix2] = b3;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "vividlight" : \r
+                                       while (p--) {\r
+                                               if ((r2=data2[pix-=4]) < 128) {\r
+                                                       if (r2) {\r
+                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) \r
+                                                                       data2[pix] = 0;\r
+                                                               else\r
+                                                                       data2[pix] = r3\r
+                                                       } else {\r
+                                                               data2[pix] = 0;\r
+                                                       }\r
+                                               } else if ((r3 = (r4=2*r2-256)) < 255) {\r
+                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) \r
+                                                               data2[pix] = 255;\r
+                                                       else\r
+                                                               data2[pix] = r3;\r
+                                               } else {\r
+                                                       if (r3 < 0) \r
+                                                               data2[pix] = 0;\r
+                                                       else\r
+                                                               data2[pix] = r3\r
+                                               }\r
+\r
+                                               if ((g2=data2[pix1=pix+1]) < 128) {\r
+                                                       if (g2) {\r
+                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) \r
+                                                                       data2[pix1] = 0;\r
+                                                               else\r
+                                                                       data2[pix1] = g3;\r
+                                                       } else {\r
+                                                               data2[pix1] = 0;\r
+                                                       }\r
+                                               } else if ((g3 = (g4=2*g2-256)) < 255) {\r
+                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)\r
+                                                               data2[pix1] = 255;\r
+                                                       else\r
+                                                               data2[pix1] = g3;\r
+                                               } else {\r
+                                                       if (g3 < 0) \r
+                                                               data2[pix1] = 0;\r
+                                                       else\r
+                                                               data2[pix1] = g3;\r
+                                               }\r
+\r
+                                               if ((b2=data2[pix2=pix+2]) < 128) {\r
+                                                       if (b2) {\r
+                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) \r
+                                                                       data2[pix2] = 0;\r
+                                                               else\r
+                                                                       data2[pix2] = b3;\r
+                                                       } else {\r
+                                                               data2[pix2] = 0;\r
+                                                       }\r
+                                               } else if ((b3 = (b4=2*b2-256)) < 255) {\r
+                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) \r
+                                                               data2[pix2] = 255;\r
+                                                       else\r
+                                                               data2[pix2] = b3;\r
+                                               } else {\r
+                                                       if (b3 < 0) \r
+                                                               data2[pix2] = 0;\r
+                                                       else\r
+                                                               data2[pix2] = b3;\r
+                                               }\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "pinlight" : \r
+                                       while (p--) {\r
+                                               if ((r2=data2[pix-=4]) < 128)\r
+                                                       if ((r1=data[pix]) < (r4=2*r2))\r
+                                                               data2[pix] = r1;\r
+                                                       else\r
+                                                               data2[pix] = r4;\r
+                                               else\r
+                                                       if ((r1=data[pix]) > (r4=2*r2-256))\r
+                                                               data2[pix] = r1;\r
+                                                       else\r
+                                                               data2[pix] = r4;\r
+\r
+                                               if ((g2=data2[pix1=pix+1]) < 128)\r
+                                                       if ((g1=data[pix1]) < (g4=2*g2))\r
+                                                               data2[pix1] = g1;\r
+                                                       else\r
+                                                               data2[pix1] = g4;\r
+                                               else\r
+                                                       if ((g1=data[pix1]) > (g4=2*g2-256))\r
+                                                               data2[pix1] = g1;\r
+                                                       else\r
+                                                               data2[pix1] = g4;\r
+\r
+                                               if ((r2=data2[pix2=pix+2]) < 128)\r
+                                                       if ((r1=data[pix2]) < (r4=2*r2))\r
+                                                               data2[pix2] = r1;\r
+                                                       else\r
+                                                               data2[pix2] = r4;\r
+                                               else\r
+                                                       if ((r1=data[pix2]) > (r4=2*r2-256))\r
+                                                               data2[pix2] = r1;\r
+                                                       else\r
+                                                               data2[pix2] = r4;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+\r
+                               case "hardmix" : \r
+                                       while (p--) {\r
+                                               if ((r2 = data2[pix-=4]) < 128)\r
+                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)\r
+                                                               data2[pix] = 0;\r
+                                                       else\r
+                                                               data2[pix] = 255;\r
+                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)\r
+                                                       data2[pix] = 0;\r
+                                               else\r
+                                                       data2[pix] = 255;\r
+\r
+                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
+                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)\r
+                                                               data2[pix1] = 0;\r
+                                                       else\r
+                                                               data2[pix1] = 255;\r
+                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)\r
+                                                       data2[pix1] = 0;\r
+                                               else\r
+                                                       data2[pix1] = 255;\r
+\r
+                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
+                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)\r
+                                                               data2[pix2] = 0;\r
+                                                       else\r
+                                                               data2[pix2] = 255;\r
+                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)\r
+                                                       data2[pix2] = 0;\r
+                                               else\r
+                                                       data2[pix2] = 255;\r
+                                       }\r
+                                       dataChanged = true;\r
+                                       break;\r
+                       }\r
+\r
+                       if (dataChanged) \r
+                               otherCtx.putImageData(dataDesc2,0,0);\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.save();\r
+                       ctx.globalAlpha = amount;\r
+                       ctx.drawImage(\r
+                               otherCanvas,\r
+                               0,0,rect.width,rect.height,\r
+                               rect.left,rect.top,rect.width,rect.height\r
+                       );\r
+                       ctx.globalAlpha = 1;\r
+                       ctx.restore();\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Blur filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.blur = {\r
+       process : function(params) {\r
+\r
+               if (typeof params.options.fixMargin == "undefined")\r
+                       params.options.fixMargin = true;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       /*\r
+                       var kernel = [\r
+                               [0.5,   1,      0.5],\r
+                               [1,     2,      1],\r
+                               [0.5,   1,      0.5]\r
+                       ];\r
+                       */\r
+\r
+                       var kernel = [\r
+                               [0,     1,      0],\r
+                               [1,     2,      1],\r
+                               [0,     1,      0]\r
+                       ];\r
+\r
+                       var weight = 0;\r
+                       for (var i=0;i<3;i++) {\r
+                               for (var j=0;j<3;j++) {\r
+                                       weight += kernel[i][j];\r
+                               }\r
+                       }\r
+\r
+                       weight = 1 / (weight*2);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+       \r
+                                       data[offset] = (\r
+                                               /*\r
+                                               dataCopy[offsetPrev - 4]\r
+                                               + dataCopy[offsetPrev+4] \r
+                                               + dataCopy[offsetNext - 4]\r
+                                               + dataCopy[offsetNext+4]\r
+                                               + \r
+                                               */\r
+                                               (dataCopy[offsetPrev]\r
+                                               + dataCopy[offset-4]\r
+                                               + dataCopy[offset+4]\r
+                                               + dataCopy[offsetNext])         * 2\r
+                                               + dataCopy[offset]              * 4\r
+                                               ) * weight;\r
+\r
+                                       data[offset+1] = (\r
+                                               /*\r
+                                               dataCopy[offsetPrev - 3]\r
+                                               + dataCopy[offsetPrev+5] \r
+                                               + dataCopy[offsetNext - 3] \r
+                                               + dataCopy[offsetNext+5]\r
+                                               + \r
+                                               */\r
+                                               (dataCopy[offsetPrev+1]\r
+                                               + dataCopy[offset-3]\r
+                                               + dataCopy[offset+5]\r
+                                               + dataCopy[offsetNext+1])       * 2\r
+                                               + dataCopy[offset+1]            * 4\r
+                                               ) * weight;\r
+\r
+                                       data[offset+2] = (\r
+                                               /*\r
+                                               dataCopy[offsetPrev - 2] \r
+                                               + dataCopy[offsetPrev+6] \r
+                                               + dataCopy[offsetNext - 2] \r
+                                               + dataCopy[offsetNext+6]\r
+                                               + \r
+                                               */\r
+                                               (dataCopy[offsetPrev+2]\r
+                                               + dataCopy[offset-2]\r
+                                               + dataCopy[offset+6]\r
+                                               + dataCopy[offsetNext+2])       * 2\r
+                                               + dataCopy[offset+2]            * 4\r
+                                               ) * weight;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";\r
+\r
+                       if (params.options.fixMargin) {\r
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";\r
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";\r
+                       }\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Blur Fast - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.blurfast = {\r
+       process : function(params) {\r
+\r
+               var amount = parseFloat(params.options.amount)||0;\r
+               var clear = !!(params.options.clear && params.options.clear != "false");\r
+\r
+               amount = Math.max(0,Math.min(5,amount));\r
+\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.save();\r
+                       ctx.beginPath();\r
+                       ctx.rect(rect.left, rect.top, rect.width, rect.height);\r
+                       ctx.clip();\r
+\r
+                       var scale = 2;\r
+                       var smallWidth = Math.round(params.width / scale);\r
+                       var smallHeight = Math.round(params.height / scale);\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = smallWidth;\r
+                       copy.height = smallHeight;\r
+\r
+                       var clear = false;\r
+                       var steps = Math.round(amount * 20);\r
+\r
+                       var copyCtx = copy.getContext("2d");\r
+                       for (var i=0;i<steps;i++) {\r
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
+       \r
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
+       \r
+                               copyCtx.drawImage(\r
+                                       params.canvas,\r
+                                       0,0,params.width,params.height,\r
+                                       0,0,scaledWidth,scaledHeight\r
+                               );\r
+       \r
+                               if (clear)\r
+                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);\r
+       \r
+                               ctx.drawImage(\r
+                                       copy,\r
+                                       0,0,scaledWidth,scaledHeight,\r
+                                       0,0,params.width,params.height\r
+                               );\r
+                       }\r
+\r
+                       ctx.restore();\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       var radius = 10 * amount;\r
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";\r
+\r
+                       if (params.options.fixMargin || 1) {\r
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";\r
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";\r
+                       }\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Brightness/Contrast filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.brightness = {\r
+\r
+       process : function(params) {\r
+\r
+               var brightness = parseInt(params.options.brightness,10) || 0;\r
+               var contrast = parseFloat(params.options.contrast)||0;\r
+               var legacy = !!(params.options.legacy && params.options.legacy != "false");\r
+\r
+               if (legacy) {\r
+                       brightness = Math.min(150,Math.max(-150,brightness));\r
+               } else {\r
+                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;\r
+               }\r
+               contrast = Math.max(0,contrast+1);\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var p = w*h;\r
+                       var pix = p*4, pix1, pix2;\r
+\r
+                       var mul, add;\r
+                       if (contrast != 1) {\r
+                               if (legacy) {\r
+                                       mul = contrast;\r
+                                       add = (brightness - 128) * contrast + 128;\r
+                               } else {\r
+                                       mul = brightMul * contrast;\r
+                                       add = - contrast * 128 + 128;\r
+                               }\r
+                       } else {  // this if-then is not necessary anymore, is it?\r
+                               if (legacy) {\r
+                                       mul = 1;\r
+                                       add = brightness;\r
+                               } else {\r
+                                       mul = brightMul;\r
+                                       add = 0;\r
+                               }\r
+                       }\r
+                       var r, g, b;\r
+                       while (p--) {\r
+                               if ((r = data[pix-=4] * mul + add) > 255 )\r
+                                       data[pix] = 255;\r
+                               else if (r < 0)\r
+                                       data[pix] = 0;\r
+                               else\r
+                                       data[pix] = r;\r
+\r
+                               if ((g = data[pix1=pix+1] * mul + add) > 255 ) \r
+                                       data[pix1] = 255;\r
+                               else if (g < 0)\r
+                                       data[pix1] = 0;\r
+                               else\r
+                                       data[pix1] = g;\r
+\r
+                               if ((b = data[pix2=pix+2] * mul + add) > 255 ) \r
+                                       data[pix2] = 255;\r
+                               else if (b < 0)\r
+                                       data[pix2] = 0;\r
+                               else\r
+                                       data[pix2] = b;\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Color adjust filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.coloradjust = {\r
+\r
+       process : function(params) {\r
+               var red = parseFloat(params.options.red) || 0;\r
+               var green = parseFloat(params.options.green) || 0;\r
+               var blue = parseFloat(params.options.blue) || 0;\r
+\r
+               red = Math.round(red*255);\r
+               green = Math.round(green*255);\r
+               blue = Math.round(blue*255);\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+\r
+                       var p = rect.width*rect.height;\r
+                       var pix = p*4, pix1, pix2;\r
+\r
+                       var r, g, b;\r
+                       while (p--) {\r
+                               pix -= 4;\r
+\r
+                               if (red) {\r
+                                       if ((r = data[pix] + red) < 0 ) \r
+                                               data[pix] = 0;\r
+                                       else if (r > 255 ) \r
+                                               data[pix] = 255;\r
+                                       else\r
+                                               data[pix] = r;\r
+                               }\r
+\r
+                               if (green) {\r
+                                       if ((g = data[pix1=pix+1] + green) < 0 ) \r
+                                               data[pix1] = 0;\r
+                                       else if (g > 255 ) \r
+                                               data[pix1] = 255;\r
+                                       else\r
+                                               data[pix1] = g;\r
+                               }\r
+\r
+                               if (blue) {\r
+                                       if ((b = data[pix2=pix+2] + blue) < 0 ) \r
+                                               data[pix2] = 0;\r
+                                       else if (b > 255 ) \r
+                                               data[pix2] = 255;\r
+                                       else\r
+                                               data[pix2] = b;\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Histogram - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+\r
+Pixastic.Actions.colorhistogram = {\r
+\r
+       array256 : function(default_value) {\r
+               arr = [];\r
+               for (var i=0; i<256; i++) { arr[i] = default_value; }\r
+               return arr\r
+       },\r
\r
+       process : function(params) {\r
+               var values = [];\r
+               if (typeof params.options.returnValue != "object") {\r
+                       params.options.returnValue = {rvals:[], gvals:[], bvals:[]};\r
+               }\r
+               var paint = !!(params.options.paint);\r
+\r
+               var returnValue = params.options.returnValue;\r
+               if (typeof returnValue.values != "array") {\r
+                       returnValue.rvals = [];\r
+                       returnValue.gvals = [];\r
+                       returnValue.bvals = [];\r
+               }\r
\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       params.useData = false;\r
\r
+                       var rvals = this.array256(0);\r
+                       var gvals = this.array256(0);\r
+                       var bvals = this.array256(0);\r
\r
+                       var rect = params.options.rect;\r
+\r
+                       var p = rect.width*rect.height;\r
+                       var pix = p*4;\r
+                       while (p--) {\r
+                               rvals[data[pix-=4]]++;\r
+                               gvals[data[pix+1]]++;\r
+                               bvals[data[pix+2]]++;\r
+                       }\r
\r
+                       returnValue.rvals = rvals;\r
+                       returnValue.gvals = gvals;\r
+                       returnValue.bvals = bvals;\r
+\r
+                       if (paint) {\r
+                               var ctx = params.canvas.getContext("2d");\r
+                               var vals = [rvals, gvals, bvals];\r
+                               for (var v=0;v<3;v++) {\r
+                                       var yoff = (v+1) * params.height / 3;\r
+                                       var maxValue = 0;\r
+                                       for (var i=0;i<256;i++) {\r
+                                               if (vals[v][i] > maxValue)\r
+                                                       maxValue = vals[v][i];\r
+                                       }\r
+                                       var heightScale = params.height / 3 / maxValue;\r
+                                       var widthScale = params.width / 256;\r
+                                       if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";\r
+                                       else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";\r
+                                       else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";\r
+                                       for (var i=0;i<256;i++) {\r
+                                               ctx.fillRect(\r
+                                                       i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,\r
+                                                       widthScale, vals[v][i] * heightScale\r
+                                               );\r
+                                       }\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Crop - v0.1.1\r
+ * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.crop = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var width = rect.width;\r
+                       var height = rect.height;\r
+                       var top = rect.top;\r
+                       var left = rect.left;\r
+\r
+                       if (typeof params.options.left != "undefined")\r
+                               left = parseInt(params.options.left,10);\r
+                       if (typeof params.options.top != "undefined")\r
+                               top = parseInt(params.options.top,10);\r
+                       if (typeof params.options.height != "undefined")\r
+                               width = parseInt(params.options.width,10);\r
+                       if (typeof params.options.height != "undefined")\r
+                               height = parseInt(params.options.height,10);\r
+\r
+                       if (left < 0) left = 0;\r
+                       if (left > params.width-1) left = params.width-1;\r
+\r
+                       if (top < 0) top = 0;\r
+                       if (top > params.height-1) top = params.height-1;\r
+\r
+                       if (width < 1) width = 1;\r
+                       if (left + width > params.width)\r
+                               width = params.width - left;\r
+\r
+                       if (height < 1) height = 1;\r
+                       if (top + height > params.height)\r
+                               height = params.height - top;\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = params.width;\r
+                       copy.height = params.height;\r
+                       copy.getContext("2d").drawImage(params.canvas,0,0);\r
+\r
+                       params.canvas.width = width;\r
+                       params.canvas.height = height;\r
+                       params.canvas.getContext("2d").clearRect(0,0,width,height);\r
+\r
+                       params.canvas.getContext("2d").drawImage(copy,\r
+                               left,top,width,height,\r
+                               0,0,width,height\r
+                       );\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Desaturation filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.desaturate = {\r
+\r
+       process : function(params) {\r
+               var useAverage = !!(params.options.average && params.options.average != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var p = w*h;\r
+                       var pix = p*4, pix1, pix2;\r
+\r
+                       if (useAverage) {\r
+                               while (p--) \r
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3\r
+                       } else {\r
+                               while (p--)\r
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);\r
+                       }\r
+                       return true;\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " gray";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Edge detection filter - v0.1.1\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.edges = {\r
+       process : function(params) {\r
+\r
+               var mono = !!(params.options.mono && params.options.mono != "false");\r
+               var invert = !!(params.options.invert && params.options.invert != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var c = -1/8;\r
+                       var kernel = [\r
+                               [c,     c,      c],\r
+                               [c,     1,      c],\r
+                               [c,     c,      c]\r
+                       ];\r
+\r
+                       weight = 1/c;\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+       \r
+                                       var r = ((dataCopy[offsetPrev-4]\r
+                                               + dataCopy[offsetPrev]\r
+                                               + dataCopy[offsetPrev+4]\r
+                                               + dataCopy[offset-4]\r
+                                               + dataCopy[offset+4]\r
+                                               + dataCopy[offsetNext-4]\r
+                                               + dataCopy[offsetNext]\r
+                                               + dataCopy[offsetNext+4]) * c\r
+                                               + dataCopy[offset]\r
+                                               ) \r
+                                               * weight;\r
+       \r
+                                       var g = ((dataCopy[offsetPrev-3]\r
+                                               + dataCopy[offsetPrev+1]\r
+                                               + dataCopy[offsetPrev+5]\r
+                                               + dataCopy[offset-3]\r
+                                               + dataCopy[offset+5]\r
+                                               + dataCopy[offsetNext-3]\r
+                                               + dataCopy[offsetNext+1]\r
+                                               + dataCopy[offsetNext+5]) * c\r
+                                               + dataCopy[offset+1])\r
+                                               * weight;\r
+       \r
+                                       var b = ((dataCopy[offsetPrev-2]\r
+                                               + dataCopy[offsetPrev+2]\r
+                                               + dataCopy[offsetPrev+6]\r
+                                               + dataCopy[offset-2]\r
+                                               + dataCopy[offset+6]\r
+                                               + dataCopy[offsetNext-2]\r
+                                               + dataCopy[offsetNext+2]\r
+                                               + dataCopy[offsetNext+6]) * c\r
+                                               + dataCopy[offset+2])\r
+                                               * weight;\r
+\r
+                                       if (mono) {\r
+                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;\r
+                                               if (invert) brightness = 255 - brightness;\r
+                                               if (brightness < 0 ) brightness = 0;\r
+                                               if (brightness > 255 ) brightness = 255;\r
+                                               r = g = b = brightness;\r
+                                       } else {\r
+                                               if (invert) {\r
+                                                       r = 255 - r;\r
+                                                       g = 255 - g;\r
+                                                       b = 255 - b;\r
+                                               }\r
+                                               if (r < 0 ) r = 0;\r
+                                               if (g < 0 ) g = 0;\r
+                                               if (b < 0 ) b = 0;\r
+                                               if (r > 255 ) r = 255;\r
+                                               if (g > 255 ) g = 255;\r
+                                               if (b > 255 ) b = 255;\r
+                                       }\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Edge detection 2 - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ * \r
+ * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!\r
+ *\r
+ */\r
+\r
+Pixastic.Actions.edges2 = {\r
+       process : function(params) {\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w * 4;\r
+                       var pixel = w4 + 4; // Start at (1,1)\r
+                       var hm1 = h - 1;\r
+                       var wm1 = w - 1;\r
+                       for (var y = 1; y < hm1; ++y) {\r
+                               // Prepare initial cached values for current row\r
+                               var centerRow = pixel - 4;\r
+                               var priorRow = centerRow - w4;\r
+                               var nextRow = centerRow + w4;\r
+                               \r
+                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];\r
+                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
+                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
+                               \r
+                               var rp = dataCopy[priorRow += 2];\r
+                               var gp = dataCopy[++priorRow];\r
+                               var bp = dataCopy[++priorRow];\r
+                               \r
+                               var rc = dataCopy[centerRow += 2];\r
+                               var gc = dataCopy[++centerRow];\r
+                               var bc = dataCopy[++centerRow];\r
+                               \r
+                               var rn = dataCopy[nextRow += 2];\r
+                               var gn = dataCopy[++nextRow];\r
+                               var bn = dataCopy[++nextRow];\r
+                               \r
+                               var r2 = - rp - rc - rn;\r
+                               var g2 = - gp - gc - gn;\r
+                               var b2 = - bp - bc - bn;\r
+                               \r
+                               // Main convolution loop\r
+                               for (var x = 1; x < wm1; ++x) {\r
+                                       centerRow = pixel + 4;\r
+                                       priorRow = centerRow - w4;\r
+                                       nextRow = centerRow + w4;\r
+                                       \r
+                                       var r = 127 + r1 - rp - (rc * -8) - rn;\r
+                                       var g = 127 + g1 - gp - (gc * -8) - gn;\r
+                                       var b = 127 + b1 - bp - (bc * -8) - bn;\r
+                                       \r
+                                       r1 = r2;\r
+                                       g1 = g2;\r
+                                       b1 = b2;\r
+                                       \r
+                                       rp = dataCopy[  priorRow];\r
+                                       gp = dataCopy[++priorRow];\r
+                                       bp = dataCopy[++priorRow];\r
+                                       \r
+                                       rc = dataCopy[  centerRow];\r
+                                       gc = dataCopy[++centerRow];\r
+                                       bc = dataCopy[++centerRow];\r
+                                       \r
+                                       rn = dataCopy[  nextRow];\r
+                                       gn = dataCopy[++nextRow];\r
+                                       bn = dataCopy[++nextRow];\r
+                                       \r
+                                       r += (r2 = - rp - rc - rn);\r
+                                       g += (g2 = - gp - gc - gn);\r
+                                       b += (b2 = - bp - bc - bn);\r
+\r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+                                       if (r < 0) r = 0;\r
+                                       if (g < 0) g = 0;\r
+                                       if (b < 0) b = 0;\r
+\r
+                                       data[pixel] = r;\r
+                                       data[++pixel] = g;\r
+                                       data[++pixel] = b;\r
+                                       //data[++pixel] = 255; // alpha\r
+\r
+                                       pixel+=2;\r
+                               }\r
+                               pixel += 8;\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Emboss filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.emboss = {\r
+       process : function(params) {\r
+\r
+               var strength = parseFloat(params.options.strength)||1;\r
+               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;\r
+               var direction = params.options.direction||"topleft";\r
+               var blend = !!(params.options.blend && params.options.blend != "false");\r
+\r
+               var dirY = 0;\r
+               var dirX = 0;\r
+\r
+               switch (direction) {\r
+                       case "topleft":                 // top left\r
+                               dirY = -1;\r
+                               dirX = -1;\r
+                               break;\r
+                       case "top":                     // top\r
+                               dirY = -1;\r
+                               dirX = 0;\r
+                               break;\r
+                       case "topright":                        // top right\r
+                               dirY = -1;\r
+                               dirX = 1;\r
+                               break;\r
+                       case "right":                   // right\r
+                               dirY = 0;\r
+                               dirX = 1;\r
+                               break;\r
+                       case "bottomright":                     // bottom right\r
+                               dirY = 1;\r
+                               dirX = 1;\r
+                               break;\r
+                       case "bottom":                  // bottom\r
+                               dirY = 1;\r
+                               dirX = 0;\r
+                               break;\r
+                       case "bottomleft":                      // bottom left\r
+                               dirY = 1;\r
+                               dirX = -1;\r
+                               break;\r
+                       case "left":                    // left\r
+                               dirY = 0;\r
+                               dirX = -1;\r
+                               break;\r
+               }\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var invertAlpha = !!params.options.invertAlpha;\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var otherY = dirY;\r
+                               if (y + otherY < 1) otherY = 0;\r
+                               if (y + otherY > h) otherY = 0;\r
+\r
+                               var offsetYOther = (y-1+otherY)*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                               var offset = offsetY + (x-1)*4;\r
+\r
+                                               var otherX = dirX;\r
+                                               if (x + otherX < 1) otherX = 0;\r
+                                               if (x + otherX > w) otherX = 0;\r
+\r
+                                               var offsetOther = offsetYOther + (x-1+otherX)*4;\r
+\r
+                                               var dR = dataCopy[offset] - dataCopy[offsetOther];\r
+                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];\r
+                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];\r
+\r
+                                               var dif = dR;\r
+                                               var absDif = dif > 0 ? dif : -dif;\r
+\r
+                                               var absG = dG > 0 ? dG : -dG;\r
+                                               var absB = dB > 0 ? dB : -dB;\r
+\r
+                                               if (absG > absDif) {\r
+                                                       dif = dG;\r
+                                               }\r
+                                               if (absB > absDif) {\r
+                                                       dif = dB;\r
+                                               }\r
+\r
+                                               dif *= strength;\r
+\r
+                                               if (blend) {\r
+                                                       var r = data[offset] + dif;\r
+                                                       var g = data[offset+1] + dif;\r
+                                                       var b = data[offset+2] + dif;\r
+\r
+                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);\r
+                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);\r
+                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);\r
+                                               } else {\r
+                                                       var grey = greyLevel - dif;\r
+                                                       if (grey < 0) {\r
+                                                               grey = 0;\r
+                                                       } else if (grey > 255) {\r
+                                                               grey = 255;\r
+                                                       }\r
+\r
+                                                       data[offset] = data[offset+1] = data[offset+2] = grey;\r
+                                               }\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+\r
+}\r
+/*\r
+ * Pixastic Lib - Flip - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.flip = {\r
+       process : function(params) {\r
+               var rect = params.options.rect;\r
+               var copyCanvas = document.createElement("canvas");\r
+               copyCanvas.width = rect.width;\r
+               copyCanvas.height = rect.height;\r
+               copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
+\r
+               var ctx = params.canvas.getContext("2d");\r
+               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+\r
+               if (params.options.axis == "horizontal") {\r
+                       ctx.scale(-1,1);\r
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
+               } else {\r
+                       ctx.scale(1,-1);\r
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
+               }\r
+\r
+               params.useData = false;\r
+\r
+               return true;            \r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Horizontal flip - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.fliph = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+                       var copyCanvas = document.createElement("canvas");\r
+                       copyCanvas.width = rect.width;\r
+                       copyCanvas.height = rect.height;\r
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+                       ctx.scale(-1,1);\r
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
+                       params.useData = false;\r
+\r
+                       return true;            \r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " fliph";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Vertical flip - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.flipv = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var rect = params.options.rect;\r
+                       var copyCanvas = document.createElement("canvas");\r
+                       copyCanvas.width = rect.width;\r
+                       copyCanvas.height = rect.height;\r
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+                       ctx.scale(1,-1);\r
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
+                       params.useData = false;\r
+\r
+                       return true;            \r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " flipv";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Glow - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+\r
+Pixastic.Actions.glow = {\r
+       process : function(params) {\r
+\r
+               var amount = (parseFloat(params.options.amount)||0);\r
+               var blurAmount = parseFloat(params.options.radius)||0;\r
+\r
+               amount = Math.min(1,Math.max(0,amount));\r
+               blurAmount = Math.min(5,Math.max(0,blurAmount));\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var blurCanvas = document.createElement("canvas");\r
+                       blurCanvas.width = params.width;\r
+                       blurCanvas.height = params.height;\r
+                       var blurCtx = blurCanvas.getContext("2d");\r
+                       blurCtx.drawImage(params.canvas,0,0);\r
+\r
+                       var scale = 2;\r
+                       var smallWidth = Math.round(params.width / scale);\r
+                       var smallHeight = Math.round(params.height / scale);\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = smallWidth;\r
+                       copy.height = smallHeight;\r
+\r
+                       var clear = true;\r
+                       var steps = Math.round(blurAmount * 20);\r
+\r
+                       var copyCtx = copy.getContext("2d");\r
+                       for (var i=0;i<steps;i++) {\r
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
+       \r
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
+       \r
+                               copyCtx.drawImage(\r
+                                       blurCanvas,\r
+                                       0,0,params.width,params.height,\r
+                                       0,0,scaledWidth,scaledHeight\r
+                               );\r
+       \r
+                               blurCtx.clearRect(0,0,params.width,params.height);\r
+       \r
+                               blurCtx.drawImage(\r
+                                       copy,\r
+                                       0,0,scaledWidth,scaledHeight,\r
+                                       0,0,params.width,params.height\r
+                               );\r
+                       }\r
+\r
+                       var data = Pixastic.prepareData(params);\r
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var r = data[offset] + amount * blurData[offset];\r
+                                       var g = data[offset+1] + amount * blurData[offset+1];\r
+                                       var b = data[offset+2] + amount * blurData[offset+2];\r
+       \r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+                                       if (r < 0) r = 0;\r
+                                       if (g < 0) g = 0;\r
+                                       if (b < 0) b = 0;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Histogram - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.histogram = {\r
+       process : function(params) {\r
+\r
+               var average = !!(params.options.average && params.options.average != "false");\r
+               var paint = !!(params.options.paint && params.options.paint != "false");\r
+               var color = params.options.color || "rgba(255,255,255,0.5)";\r
+               var values = [];\r
+               if (typeof params.options.returnValue != "object") {\r
+                       params.options.returnValue = {values:[]};\r
+               }\r
+               var returnValue = params.options.returnValue;\r
+               if (typeof returnValue.values != "array") {\r
+                       returnValue.values = [];\r
+               }\r
+               values = returnValue.values;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       params.useData = false;\r
+\r
+                       for (var i=0;i<256;i++) {\r
+                               values[i] = 0;\r
+                       }\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+                                       var brightness = average ? \r
+                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)\r
+                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);\r
+                                       values[brightness]++;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       if (paint) {\r
+                               var maxValue = 0;\r
+                               for (var i=0;i<256;i++) {\r
+                                       if (values[i] > maxValue) {\r
+                                               maxValue = values[i];\r
+                                       }\r
+                               }\r
+                               var heightScale = params.height / maxValue;\r
+                               var widthScale = params.width / 256;\r
+                               var ctx = params.canvas.getContext("2d");\r
+                               ctx.fillStyle = color;\r
+                               for (var i=0;i<256;i++) {\r
+                                       ctx.fillRect(\r
+                                               i * widthScale, params.height - heightScale * values[i],\r
+                                               widthScale, values[i] * heightScale\r
+                                       );\r
+                               }\r
+                       }\r
+\r
+                       returnValue.values = values;\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - HSL Adjust  - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.hsl = {\r
+       process : function(params) {\r
+\r
+               var hue = parseInt(params.options.hue,10)||0;\r
+               var saturation = (parseInt(params.options.saturation,10)||0) / 100;\r
+               var lightness = (parseInt(params.options.lightness,10)||0) / 100;\r
+\r
+\r
+               // this seems to give the same result as Photoshop\r
+               if (saturation < 0) {\r
+                       var satMul = 1+saturation;\r
+               } else {\r
+                       var satMul = 1+saturation*2;\r
+               }\r
+\r
+               hue = (hue%360) / 360;\r
+               var hue6 = hue * 6;\r
+\r
+               var rgbDiv = 1 / 255;\r
+\r
+               var light255 = lightness * 255;\r
+               var lightp1 = 1 + lightness;\r
+               var lightm1 = 1 - lightness;\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var r = data[offset];\r
+                                       var g = data[offset+1];\r
+                                       var b = data[offset+2];\r
+\r
+                                       if (hue != 0 || saturation != 0) {\r
+                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. \r
+                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.\r
+                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.\r
+                                               var vs = r;\r
+                                               if (g > vs) vs = g;\r
+                                               if (b > vs) vs = b;\r
+                                               var ms = r;\r
+                                               if (g < ms) ms = g;\r
+                                               if (b < ms) ms = b;\r
+                                               var vm = (vs-ms);\r
+                                               var l = (ms+vs)/255 * 0.5;\r
+                                               if (l > 0) {\r
+                                                       if (vm > 0) {\r
+                                                               if (l <= 0.5) {\r
+                                                                       var s = vm / (vs+ms) * satMul;\r
+                                                                       if (s > 1) s = 1;\r
+                                                                       var v = (l * (1+s));\r
+                                                               } else {\r
+                                                                       var s = vm / (510-vs-ms) * satMul;\r
+                                                                       if (s > 1) s = 1;\r
+                                                                       var v = (l+s - l*s);\r
+                                                               }\r
+                                                               if (r == vs) {\r
+                                                                       if (g == ms)\r
+                                                                               var h = 5 + ((vs-b)/vm) + hue6;\r
+                                                                       else\r
+                                                                               var h = 1 - ((vs-g)/vm) + hue6;\r
+                                                               } else if (g == vs) {\r
+                                                                       if (b == ms)\r
+                                                                               var h = 1 + ((vs-r)/vm) + hue6;\r
+                                                                       else\r
+                                                                               var h = 3 - ((vs-b)/vm) + hue6;\r
+                                                               } else {\r
+                                                                       if (r == ms)\r
+                                                                               var h = 3 + ((vs-g)/vm) + hue6;\r
+                                                                       else\r
+                                                                               var h = 5 - ((vs-r)/vm) + hue6;\r
+                                                               }\r
+                                                               if (h < 0) h+=6;\r
+                                                               if (h >= 6) h-=6;\r
+                                                               var m = (l+l-v);\r
+                                                               var sextant = h>>0;\r
+                                                               switch (sextant) {\r
+                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;\r
+                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;\r
+                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;\r
+                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;\r
+                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;\r
+                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                                       if (lightness < 0) {\r
+                                               r *= lightp1;\r
+                                               g *= lightp1;\r
+                                               b *= lightp1;\r
+                                       } else if (lightness > 0) {\r
+                                               r = r * lightm1 + light255;\r
+                                               g = g * lightm1 + light255;\r
+                                               b = b * lightm1 + light255;\r
+                                       }\r
+\r
+                                       if (r < 0) r = 0;\r
+                                       if (g < 0) g = 0;\r
+                                       if (b < 0) b = 0;\r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+\r
+}\r
+/*\r
+ * Pixastic Lib - Invert filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.invert = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       var invertAlpha = !!params.options.invertAlpha;\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+                                       data[offset] = 255 - data[offset];\r
+                                       data[offset+1] = 255 - data[offset+1];\r
+                                       data[offset+2] = 255 - data[offset+2];\r
+                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       params.image.style.filter += " invert";\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Laplace filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.laplace = {\r
+       process : function(params) {\r
+\r
+               var strength = 1.0;\r
+               var invert = !!(params.options.invert && params.options.invert != "false");\r
+               var contrast = parseFloat(params.options.edgeStrength)||0;\r
+\r
+               var greyLevel = parseInt(params.options.greyLevel)||0;\r
+\r
+               contrast = -contrast;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var kernel = [\r
+                               [-1,    -1,     -1],\r
+                               [-1,    8,      -1],\r
+                               [-1,    -1,     -1]\r
+                       ];\r
+\r
+                       var weight = 1/8;\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+       \r
+                                       var r = ((-dataCopy[offsetPrev-4]\r
+                                               - dataCopy[offsetPrev]\r
+                                               - dataCopy[offsetPrev+4]\r
+                                               - dataCopy[offset-4]\r
+                                               - dataCopy[offset+4]\r
+                                               - dataCopy[offsetNext-4]\r
+                                               - dataCopy[offsetNext]\r
+                                               - dataCopy[offsetNext+4])\r
+                                               + dataCopy[offset] * 8) \r
+                                               * weight;\r
+       \r
+                                       var g = ((-dataCopy[offsetPrev-3]\r
+                                               - dataCopy[offsetPrev+1]\r
+                                               - dataCopy[offsetPrev+5]\r
+                                               - dataCopy[offset-3]\r
+                                               - dataCopy[offset+5]\r
+                                               - dataCopy[offsetNext-3]\r
+                                               - dataCopy[offsetNext+1]\r
+                                               - dataCopy[offsetNext+5])\r
+                                               + dataCopy[offset+1] * 8)\r
+                                               * weight;\r
+       \r
+                                       var b = ((-dataCopy[offsetPrev-2]\r
+                                               - dataCopy[offsetPrev+2]\r
+                                               - dataCopy[offsetPrev+6]\r
+                                               - dataCopy[offset-2]\r
+                                               - dataCopy[offset+6]\r
+                                               - dataCopy[offsetNext-2]\r
+                                               - dataCopy[offsetNext+2]\r
+                                               - dataCopy[offsetNext+6])\r
+                                               + dataCopy[offset+2] * 8)\r
+                                               * weight;\r
+\r
+                                       var brightness = ((r + g + b)/3) + greyLevel;\r
+\r
+                                       if (contrast != 0) {\r
+                                               if (brightness > 127) {\r
+                                                       brightness += ((brightness + 1) - 128) * contrast;\r
+                                               } else if (brightness < 127) {\r
+                                                       brightness -= (brightness + 1) * contrast;\r
+                                               }\r
+                                       }\r
+                                       if (invert) {\r
+                                               brightness = 255 - brightness;\r
+                                       }\r
+                                       if (brightness < 0 ) brightness = 0;\r
+                                       if (brightness > 255 ) brightness = 255;\r
+\r
+                                       data[offset] = data[offset+1] = data[offset+2] = brightness;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Lighten filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.lighten = {\r
+\r
+       process : function(params) {\r
+               var amount = parseFloat(params.options.amount) || 0;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       var r = data[offset];\r
+                                       var g = data[offset+1];\r
+                                       var b = data[offset+2];\r
+\r
+                                       r += r*amount;\r
+                                       g += g*amount;\r
+                                       b += b*amount;\r
+\r
+                                       if (r < 0 ) r = 0;\r
+                                       if (g < 0 ) g = 0;\r
+                                       if (b < 0 ) b = 0;\r
+                                       if (r > 255 ) r = 255;\r
+                                       if (g > 255 ) g = 255;\r
+                                       if (b > 255 ) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+\r
+               } else if (Pixastic.Client.isIE()) {\r
+                       var img = params.image;\r
+                       if (amount < 0) {\r
+                               img.style.filter += " light()";\r
+                               img.filters[img.filters.length-1].addAmbient(\r
+                                       255,255,255,\r
+                                       100 * -amount\r
+                               );\r
+                       } else if (amount > 0) {\r
+                               img.style.filter += " light()";\r
+                               img.filters[img.filters.length-1].addAmbient(\r
+                                       255,255,255,\r
+                                       100\r
+                               );\r
+                               img.filters[img.filters.length-1].addAmbient(\r
+                                       255,255,255,\r
+                                       100 * amount\r
+                               );\r
+                       }\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Mosaic filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.mosaic = {\r
+\r
+       process : function(params) {\r
+               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+\r
+                       var pixel = document.createElement("canvas");\r
+                       pixel.width = pixel.height = 1;\r
+                       var pixelCtx = pixel.getContext("2d");\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = w;\r
+                       copy.height = h;\r
+                       var copyCtx = copy.getContext("2d");\r
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
+\r
+                       for (var y=0;y<h;y+=blockSize) {\r
+                               for (var x=0;x<w;x+=blockSize) {\r
+                                       var blockSizeX = blockSize;\r
+                                       var blockSizeY = blockSize;\r
+               \r
+                                       if (blockSizeX + x > w)\r
+                                               blockSizeX = w - x;\r
+                                       if (blockSizeY + y > h)\r
+                                               blockSizeY = h - y;\r
+\r
+                                       pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);\r
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
+                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);\r
+                               }\r
+                       }\r
+                       params.useData = false;\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Noise filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.noise = {\r
+\r
+       process : function(params) {\r
+               var amount = 0;\r
+               var strength = 0;\r
+               var mono = false;\r
+\r
+               if (typeof params.options.amount != "undefined")\r
+                       amount = parseFloat(params.options.amount)||0;\r
+               if (typeof params.options.strength != "undefined")\r
+                       strength = parseFloat(params.options.strength)||0;\r
+               if (typeof params.options.mono != "undefined")\r
+                       mono = !!(params.options.mono && params.options.mono != "false");\r
+\r
+               amount = Math.max(0,Math.min(1,amount));\r
+               strength = Math.max(0,Math.min(1,strength));\r
+\r
+               var noise = 128 * strength;\r
+               var noise2 = noise / 2;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       var random = Math.random;\r
+\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+                                       if (random() < amount) {\r
+                                               if (mono) {\r
+                                                       var pixelNoise = - noise2 + random() * noise;\r
+                                                       var r = data[offset] + pixelNoise;\r
+                                                       var g = data[offset+1] + pixelNoise;\r
+                                                       var b = data[offset+2] + pixelNoise;\r
+                                               } else {\r
+                                                       var r = data[offset] - noise2 + (random() * noise);\r
+                                                       var g = data[offset+1] - noise2 + (random() * noise);\r
+                                                       var b = data[offset+2] - noise2 + (random() * noise);\r
+                                               }\r
+\r
+                                               if (r < 0 ) r = 0;\r
+                                               if (g < 0 ) g = 0;\r
+                                               if (b < 0 ) b = 0;\r
+                                               if (r > 255 ) r = 255;\r
+                                               if (g > 255 ) g = 255;\r
+                                               if (b > 255 ) b = 255;\r
+\r
+                                               data[offset] = r;\r
+                                               data[offset+1] = g;\r
+                                               data[offset+2] = b;\r
+                                       }\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+/*\r
+ * Pixastic Lib - Posterize effect - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.posterize = {\r
+\r
+       process : function(params) {\r
+\r
+               \r
+               var numLevels = 256;\r
+               if (typeof params.options.levels != "undefined")\r
+                       numLevels = parseInt(params.options.levels,10)||1;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       numLevels = Math.max(2,Math.min(256,numLevels));\r
+       \r
+                       var numAreas = 256 / numLevels;\r
+                       var numValues = 256 / (numLevels-1);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       var r = numValues * ((data[offset] / numAreas)>>0);\r
+                                       var g = numValues * ((data[offset+1] / numAreas)>>0);\r
+                                       var b = numValues * ((data[offset+2] / numAreas)>>0);\r
+\r
+                                       if (r > 255) r = 255;\r
+                                       if (g > 255) g = 255;\r
+                                       if (b > 255) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Pointillize filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.pointillize = {\r
+\r
+       process : function(params) {\r
+               var radius = Math.max(1,parseInt(params.options.radius,10));\r
+               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));\r
+               var noise = Math.max(0,parseFloat(params.options.noise)||0);\r
+               var transparent = !!(params.options.transparent && params.options.transparent != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+\r
+                       var ctx = params.canvas.getContext("2d");\r
+                       var canvasWidth = params.canvas.width;\r
+                       var canvasHeight = params.canvas.height;\r
+\r
+                       var pixel = document.createElement("canvas");\r
+                       pixel.width = pixel.height = 1;\r
+                       var pixelCtx = pixel.getContext("2d");\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = w;\r
+                       copy.height = h;\r
+                       var copyCtx = copy.getContext("2d");\r
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
+\r
+                       var diameter = radius * 2;\r
+\r
+                       if (transparent)\r
+                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
+\r
+                       var noiseRadius = radius * noise;\r
+\r
+                       var dist = 1 / density;\r
+\r
+                       for (var y=0;y<h+radius;y+=diameter*dist) {\r
+                               for (var x=0;x<w+radius;x+=diameter*dist) {\r
+                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;\r
+                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;\r
+\r
+                                       var pixX = rndX - radius;\r
+                                       var pixY = rndY - radius;\r
+                                       if (pixX < 0) pixX = 0;\r
+                                       if (pixY < 0) pixY = 0;\r
+\r
+                                       var cx = rndX + rect.left;\r
+                                       var cy = rndY + rect.top;\r
+                                       if (cx < 0) cx = 0;\r
+                                       if (cx > canvasWidth) cx = canvasWidth;\r
+                                       if (cy < 0) cy = 0;\r
+                                       if (cy > canvasHeight) cy = canvasHeight;\r
+\r
+                                       var diameterX = diameter;\r
+                                       var diameterY = diameter;\r
+\r
+                                       if (diameterX + pixX > w)\r
+                                               diameterX = w - pixX;\r
+                                       if (diameterY + pixY > h)\r
+                                               diameterY = h - pixY;\r
+                                       if (diameterX < 1) diameterX = 1;\r
+                                       if (diameterY < 1) diameterY = 1;\r
+\r
+                                       pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);\r
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
+\r
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
+                                       ctx.beginPath();\r
+                                       ctx.arc(cx, cy, radius, 0, Math.PI*2, true);\r
+                                       ctx.closePath();\r
+                                       ctx.fill();\r
+                               }\r
+                       }\r
+\r
+                       params.useData = false;\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}/*\r
+ * Pixastic Lib - Resize - v0.1.0\r
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.resize = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var width = parseInt(params.options.width,10);\r
+                       var height = parseInt(params.options.height,10);\r
+                       var canvas = params.canvas;\r
+\r
+                       if (width < 1) width = 1;\r
+                       if (width < 2) width = 2;\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = width;\r
+                       copy.height = height;\r
+\r
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
+                       canvas.width = width;\r
+                       canvas.height = height;\r
+\r
+                       canvas.getContext("2d").drawImage(copy,0,0);\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Remove noise - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.removenoise = {\r
+       process : function(params) {\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w*4;\r
+                               var offsetYNext = nextY*w*4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+\r
+                                       var minR, maxR, minG, maxG, minB, maxB;\r
+\r
+                                       minR = maxR = data[offsetPrev];\r
+                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];\r
+                                       if (r1 < minR) minR = r1;\r
+                                       if (r2 < minR) minR = r2;\r
+                                       if (r3 < minR) minR = r3;\r
+                                       if (r1 > maxR) maxR = r1;\r
+                                       if (r2 > maxR) maxR = r2;\r
+                                       if (r3 > maxR) maxR = r3;\r
+\r
+                                       minG = maxG = data[offsetPrev+1];\r
+                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];\r
+                                       if (g1 < minG) minG = g1;\r
+                                       if (g2 < minG) minG = g2;\r
+                                       if (g3 < minG) minG = g3;\r
+                                       if (g1 > maxG) maxG = g1;\r
+                                       if (g2 > maxG) maxG = g2;\r
+                                       if (g3 > maxG) maxG = g3;\r
+\r
+                                       minB = maxB = data[offsetPrev+2];\r
+                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];\r
+                                       if (b1 < minB) minB = b1;\r
+                                       if (b2 < minB) minB = b2;\r
+                                       if (b3 < minB) minB = b3;\r
+                                       if (b1 > maxB) maxB = b1;\r
+                                       if (b2 > maxB) maxB = b2;\r
+                                       if (b3 > maxB) maxB = b3;\r
+\r
+                                       if (data[offset] > maxR) {\r
+                                               data[offset] = maxR;\r
+                                       } else if (data[offset] < minR) {\r
+                                               data[offset] = minR;\r
+                                       }\r
+                                       if (data[offset+1] > maxG) {\r
+                                               data[offset+1] = maxG;\r
+                                       } else if (data[offset+1] < minG) {\r
+                                               data[offset+1] = minG;\r
+                                       }\r
+                                       if (data[offset+2] > maxB) {\r
+                                               data[offset+2] = maxB;\r
+                                       } else if (data[offset+2] < minB) {\r
+                                               data[offset+2] = minB;\r
+                                       }\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Rotate - v0.1.0\r
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.rotate = {\r
+       process : function(params) {\r
+               if (Pixastic.Client.hasCanvas()) {\r
+                       var canvas = params.canvas;\r
+\r
+                       var width = params.width;\r
+                       var height = params.height;\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = width;\r
+                       copy.height = height;\r
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
+\r
+                       var angle = -parseFloat(params.options.angle) * Math.PI / 180;\r
+\r
+                       var dimAngle = angle;\r
+                       if (dimAngle > Math.PI*0.5)\r
+                               dimAngle = Math.PI - dimAngle;\r
+                       if (dimAngle < -Math.PI*0.5)\r
+                               dimAngle = -Math.PI - dimAngle;\r
+\r
+                       var diag = Math.sqrt(width*width + height*height);\r
+\r
+                       var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));\r
+                       var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));\r
+\r
+                       var newWidth = Math.abs(Math.cos(diagAngle1) * diag);\r
+                       var newHeight = Math.abs(Math.sin(diagAngle2) * diag);\r
+\r
+                       canvas.width = newWidth;\r
+                       canvas.height = newHeight;\r
+\r
+                       var ctx = canvas.getContext("2d");\r
+                       ctx.translate(newWidth/2, newHeight/2);\r
+                       ctx.rotate(angle);\r
+                       ctx.drawImage(copy,-width/2,-height/2);\r
+\r
+                       params.useData = false;\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvas();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Pixastic Lib - Sepia filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.sepia = {\r
+\r
+       process : function(params) {\r
+               var mode = (parseInt(params.options.mode,10)||0);\r
+               if (mode < 0) mode = 0;\r
+               if (mode > 1) mode = 1;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       if (mode) {\r
+                                               // a bit faster, but not as good\r
+                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;\r
+                                               var r = (d + 39);\r
+                                               var g = (d + 14);\r
+                                               var b = (d - 36);\r
+                                       } else {\r
+                                               // Microsoft\r
+                                               var or = data[offset];\r
+                                               var og = data[offset+1];\r
+                                               var ob = data[offset+2];\r
+       \r
+                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);\r
+                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);\r
+                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);\r
+                                       }\r
+\r
+                                       if (r < 0) r = 0; if (r > 255) r = 255;\r
+                                       if (g < 0) g = 0; if (g > 255) g = 255;\r
+                                       if (b < 0) b = 0; if (b > 255) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}/*\r
+ * Pixastic Lib - Sharpen filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.sharpen = {\r
+       process : function(params) {\r
+\r
+               var strength = 0;\r
+               if (typeof params.options.amount != "undefined")\r
+                       strength = parseFloat(params.options.amount)||0;\r
+\r
+               if (strength < 0) strength = 0;\r
+               if (strength > 1) strength = 1;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var dataCopy = Pixastic.prepareData(params, true)\r
+\r
+                       var mul = 15;\r
+                       var mulOther = 1 + 3*strength;\r
+\r
+                       var kernel = [\r
+                               [0,     -mulOther,      0],\r
+                               [-mulOther,     mul,    -mulOther],\r
+                               [0,     -mulOther,      0]\r
+                       ];\r
+\r
+                       var weight = 0;\r
+                       for (var i=0;i<3;i++) {\r
+                               for (var j=0;j<3;j++) {\r
+                                       weight += kernel[i][j];\r
+                               }\r
+                       }\r
+\r
+                       weight = 1 / weight;\r
+\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+\r
+                       mul *= weight;\r
+                       mulOther *= weight;\r
+\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+\r
+                               var nextY = (y == h) ? y - 1 : y;\r
+                               var prevY = (y == 1) ? 0 : y-2;\r
+\r
+                               var offsetYPrev = prevY*w4;\r
+                               var offsetYNext = nextY*w4;\r
+\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
+\r
+                                       var r = ((\r
+                                               - dataCopy[offsetPrev]\r
+                                               - dataCopy[offset-4]\r
+                                               - dataCopy[offset+4]\r
+                                               - dataCopy[offsetNext])         * mulOther\r
+                                               + dataCopy[offset]      * mul\r
+                                               );\r
+\r
+                                       var g = ((\r
+                                               - dataCopy[offsetPrev+1]\r
+                                               - dataCopy[offset-3]\r
+                                               - dataCopy[offset+5]\r
+                                               - dataCopy[offsetNext+1])       * mulOther\r
+                                               + dataCopy[offset+1]    * mul\r
+                                               );\r
+\r
+                                       var b = ((\r
+                                               - dataCopy[offsetPrev+2]\r
+                                               - dataCopy[offset-2]\r
+                                               - dataCopy[offset+6]\r
+                                               - dataCopy[offsetNext+2])       * mulOther\r
+                                               + dataCopy[offset+2]    * mul\r
+                                               );\r
+\r
+\r
+                                       if (r < 0 ) r = 0;\r
+                                       if (g < 0 ) g = 0;\r
+                                       if (b < 0 ) b = 0;\r
+                                       if (r > 255 ) r = 255;\r
+                                       if (g > 255 ) g = 255;\r
+                                       if (b > 255 ) b = 255;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+/*\r
+ * Pixastic Lib - Solarize filter - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+Pixastic.Actions.solarize = {\r
+\r
+       process : function(params) {\r
+               var useAverage = !!(params.options.average && params.options.average != "false");\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var data = Pixastic.prepareData(params);\r
+                       var rect = params.options.rect;\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x-1)*4;\r
+\r
+                                       var r = data[offset];\r
+                                       var g = data[offset+1];\r
+                                       var b = data[offset+2];\r
+\r
+                                       if (r > 127) r = 255 - r;\r
+                                       if (g > 127) g = 255 - g;\r
+                                       if (b > 127) b = 255 - b;\r
+\r
+                                       data[offset] = r;\r
+                                       data[offset+1] = g;\r
+                                       data[offset+2] = b;\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return (Pixastic.Client.hasCanvasImageData());\r
+       }\r
+}/*\r
+ * Pixastic Lib - USM - v0.1.0\r
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
+ * License: [http://www.pixastic.com/lib/license.txt]\r
+ */\r
+\r
+\r
+Pixastic.Actions.unsharpmask = {\r
+       process : function(params) {\r
+\r
+               var amount = (parseFloat(params.options.amount)||0);\r
+               var blurAmount = parseFloat(params.options.radius)||0;\r
+               var threshold = parseFloat(params.options.threshold)||0;\r
+\r
+               amount = Math.min(500,Math.max(0,amount)) / 2;\r
+               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;\r
+               threshold = Math.min(255,Math.max(0,threshold));\r
+\r
+               threshold--;\r
+               var thresholdNeg = -threshold;\r
+\r
+               amount *= 0.016;\r
+               amount++;\r
+\r
+               if (Pixastic.Client.hasCanvasImageData()) {\r
+                       var rect = params.options.rect;\r
+\r
+                       var blurCanvas = document.createElement("canvas");\r
+                       blurCanvas.width = params.width;\r
+                       blurCanvas.height = params.height;\r
+                       var blurCtx = blurCanvas.getContext("2d");\r
+                       blurCtx.drawImage(params.canvas,0,0);\r
+\r
+                       var scale = 2;\r
+                       var smallWidth = Math.round(params.width / scale);\r
+                       var smallHeight = Math.round(params.height / scale);\r
+\r
+                       var copy = document.createElement("canvas");\r
+                       copy.width = smallWidth;\r
+                       copy.height = smallHeight;\r
+\r
+                       var steps = Math.round(blurAmount * 20);\r
+\r
+                       var copyCtx = copy.getContext("2d");\r
+                       for (var i=0;i<steps;i++) {\r
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
+\r
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
+\r
+                               copyCtx.drawImage(\r
+                                       blurCanvas,\r
+                                       0,0,params.width,params.height,\r
+                                       0,0,scaledWidth,scaledHeight\r
+                               );\r
+       \r
+                               blurCtx.clearRect(0,0,params.width,params.height);\r
+       \r
+                               blurCtx.drawImage(\r
+                                       copy,\r
+                                       0,0,scaledWidth,scaledHeight,\r
+                                       0,0,params.width,params.height\r
+                               );\r
+                       }\r
+\r
+                       var data = Pixastic.prepareData(params);\r
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
+                       var w = rect.width;\r
+                       var h = rect.height;\r
+                       var w4 = w*4;\r
+                       var y = h;\r
+                       do {\r
+                               var offsetY = (y-1)*w4;\r
+                               var x = w;\r
+                               do {\r
+                                       var offset = offsetY + (x*4-4);\r
+\r
+                                       var difR = data[offset] - blurData[offset];\r
+                                       if (difR > threshold || difR < thresholdNeg) {\r
+                                               var blurR = blurData[offset];\r
+                                               blurR = amount * difR + blurR;\r
+                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);\r
+                                       }\r
+\r
+                                       var difG = data[offset+1] - blurData[offset+1];\r
+                                       if (difG > threshold || difG < thresholdNeg) {\r
+                                               var blurG = blurData[offset+1];\r
+                                               blurG = amount * difG + blurG;\r
+                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);\r
+                                       }\r
+\r
+                                       var difB = data[offset+2] - blurData[offset+2];\r
+                                       if (difB > threshold || difB < thresholdNeg) {\r
+                                               var blurB = blurData[offset+2];\r
+                                               blurB = amount * difB + blurB;\r
+                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);\r
+                                       }\r
+\r
+                               } while (--x);\r
+                       } while (--y);\r
+\r
+                       return true;\r
+               }\r
+       },\r
+       checkSupport : function() {\r
+               return Pixastic.Client.hasCanvasImageData();\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.css b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.css
new file mode 100644 (file)
index 0000000..a487ba2
--- /dev/null
@@ -0,0 +1,423 @@
+/* http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */\r
+\r
+html, body, div, span, applet, object, iframe,\r
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,\r
+a, abbr, acronym, address, big, cite, code,\r
+del, dfn, em, font, img, ins, kbd, q, s, samp,\r
+small, strike, strong, sub, sup, tt, var,\r
+dl, dt, dd, ol, ul, li,\r
+fieldset, form, label, legend,\r
+table, caption, tbody, tfoot, thead, tr, th, td {\r
+       margin: 0;\r
+       padding: 0;\r
+       border: 0;\r
+       outline: 0;\r
+       font-weight: inherit;\r
+       font-style: inherit;\r
+       font-size: 100%;\r
+       font-family: inherit;\r
+       vertical-align: baseline;\r
+}\r
+/* remember to define focus styles! */\r
+:focus {\r
+       outline: 0;\r
+}\r
+body {\r
+       line-height: 1;\r
+       color: black;\r
+       background: white;\r
+}\r
+ol, ul {\r
+       list-style: none;\r
+}\r
+/* tables still need 'cellspacing="0"' in the markup */\r
+table {\r
+       border-collapse: separate;\r
+       border-spacing: 0;\r
+}\r
+caption, th, td {\r
+       text-align: left;\r
+       font-weight: normal;\r
+}\r
+blockquote:before, blockquote:after,\r
+q:before, q:after {\r
+       content: "";\r
+}\r
+blockquote, q {\r
+       quotes: "" "";\r
+}\r
+/* end reset */\r
+\r
+/* -----------------------\r
+ *   Base\r
+ * -----------------------\r
+ */\r
+\r
+/* main container element for editor app */\r
+#pixastic-editor {\r
+       margin : 0;\r
+       position : absolute;\r
+       left : 0;\r
+       top : 0;\r
+       padding: 0px;\r
+       width: 100%;\r
+       height: 100%;\r
+       font-family : Helvetica,Arial,sans-serif;\r
+       overflow : hidden;\r
+       z-index : 10000000;\r
+} \r
+\r
+\r
+/* -----------------------\r
+ *   Loading screen\r
+ * -----------------------\r
+ */\r
+\r
+/* container for loading screen */\r
+#loading-screen {\r
+       margin : 0;\r
+       position : absolute;\r
+       left : 0;\r
+       top : 0;\r
+       padding: 0px;\r
+       width: 100%;\r
+       height: 100%;\r
+       font-family : Helvetica,Arial,sans-serif;\r
+       overflow : hidden;\r
+       z-index : 10000000;\r
+       background-color : #111;\r
+       opacity : 0.9;\r
+       display : table;\r
+       text-align : center;\r
+} \r
+\r
+/* container for spinner in loading screen */\r
+#loading-screen-cell {\r
+       display : table-cell;\r
+       vertical-align : middle;\r
+       text-align : center;\r
+}\r
+\r
+\r
+/* -----------------------\r
+ *   Misc\r
+ * -----------------------\r
+ */\r
+\r
+\r
+// UI error dialog\r
+.ui-dialog .error-dialog {\r
+       background-color : #544;\r
+}\r
+\r
+/* loading spinner */\r
+.spinner {\r
+       width : 31px;\r
+       height : 31px;\r
+       display : inline-block;\r
+       background: url(spinner.gif);\r
+       overflow : hidden;\r
+}\r
+\r
+canvas.display-canvas,\r
+canvas.undo-canvas {\r
+       /*\r
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1JREFUeNpiPHPmDAM2YGxsjFWciYFEMKqBGMD4//9/rBJnz54dDSX6aQAIMABCtQiAsDRF+wAAAABJRU5ErkJggg==');\r
+       */\r
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC5JREFUeNpiPHPmTAMDHmBsbIxPmoGJgUIwasBgMICFUDyfPXt2NBCHvwEAAQYAICIGn294LYEAAAAASUVORK5CYII=');\r
+\r
+}\r
+\r
+.far-far-away {\r
+       position : absolute;\r
+       left : -9999px;\r
+       top : -9999px;\r
+}\r
+\r
+#powered-by-pixastic {\r
+       position : absolute;\r
+       bottom : 0px;\r
+       margin-bottom : 23px;\r
+       margin-left : 42px;\r
+}\r
+#powered-by-pixastic a {\r
+       font-size : 12px;\r
+       font-family : Helvetica,Arial,sans-serif;\r
+       letter-spacing : 0.1em;\r
+       color : rgb(100,100,100);\r
+       color : rgba(255,255,255,0.2);\r
+       text-decoration : none;\r
+}\r
+\r
+#powered-by-pixastic a:hover {\r
+       color : rgb(200,200,200);\r
+       color : rgba(255,255,255,0.7);\r
+       text-decoration : underline;\r
+}\r
+\r
+\r
+/* -----------------------\r
+ *   Skeleton structure\r
+ * -----------------------\r
+ */\r
+\r
+/* editor background underlay */\r
+#background {\r
+       background-color : #111;\r
+       opacity : 0.9;\r
+       width : 100%;\r
+       height : 100%;\r
+       position : absolute;\r
+       z-index : -1;\r
+}\r
+\r
+#image-area {\r
+       position : relative;\r
+       background-color : #222;\r
+       border : 1px solid #444;\r
+       width : 100%;\r
+       height : 100%;\r
+       -moz-box-sizing:border-box;\r
+       overflow : auto;\r
+       text-align : center;\r
+}\r
+\r
+#image-area-sub {\r
+}\r
+\r
+#image-container {\r
+}\r
+\r
+#image-overlay-container {\r
+       -moz-box-sizing:border-box;\r
+       width:100%;\r
+       height:100%;\r
+       position:absolute;\r
+       top:0;\r
+       left:0;\r
+}\r
+\r
+#image-overlay {\r
+}\r
+\r
+\r
+/* structure elements */\r
+#edit-ctr-1 {\r
+       position : absolute;\r
+       top : 0;\r
+       left : 0;\r
+       width : 100%;\r
+       height : 100%;\r
+}\r
+\r
+#edit-ctr-2 {\r
+       -moz-box-sizing : border-box;\r
+       box-sizing : border-box;\r
+       padding-left:40px;\r
+       padding-right:420px;\r
+       padding-top:70px;\r
+       padding-bottom : 40px;\r
+       height : 100%;\r
+       width : 100%;\r
+}\r
+\r
+\r
+/* main menu bar */\r
+#main-bar {\r
+       position : absolute;\r
+       width : 100%;\r
+       text-align : right;\r
+       margin-top : 20px;\r
+       margin-right : 30px;\r
+}\r
+\r
+/* area on the right with accordion widgets and undo bar */\r
+#controls-bar {\r
+       margin-right : -385px;\r
+       width : 372px;\r
+       float : right;\r
+       height : 100%;\r
+}\r
+\r
+/* accordion area */\r
+#action-bar {\r
+       padding : 10px;\r
+       width : 290px;\r
+       background-color : #222;\r
+       border : 1px solid #444;\r
+       -moz-box-sizing : border-box;\r
+       box-sizing : border-box;\r
+       height : 100%;\r
+       overflow-x : hidden;\r
+       overflow-y : auto;\r
+       float: right; \r
+       position : relative;\r
+}\r
+\r
+#action-bar-overlay {\r
+       position : absolute;\r
+       z-index : 1000000;\r
+       width : 100%;\r
+       height : 100%;\r
+       left : 0;\r
+       top : 0;\r
+       background-color : #444;\r
+       opacity : 0.2;\r
+       display : none;\r
+}\r
+\r
+\r
+/* vertical bar with undo image states */\r
+#undo-bar {\r
+       -moz-box-sizing : border-box;\r
+       box-sizing : border-box;\r
+       background-color : #222;\r
+       border : 1px solid #444;\r
+       width: 70px; \r
+       height: 100%;\r
+       overflow: hidden;\r
+       padding-top : 3px;\r
+}\r
+\r
+\r
+\r
+/* -----------------------\r
+ *   Main menu styles\r
+ * -----------------------\r
+ */\r
+\r
+.main-tab {\r
+       color : #999;\r
+       display : inline-block;\r
+       width : 150px;\r
+       text-transform : lowercase;\r
+       font-size : 22px;\r
+       cursor : pointer;\r
+       text-align : center;\r
+       text-decoration : none;\r
+       padding-top : 4px;\r
+       padding-bottom : 5px;\r
+       outline : 0;\r
+}\r
+\r
+.main-tab.hover {\r
+       color : white !important;\r
+}\r
+\r
+.main-tab.active {\r
+       color : white;\r
+}\r
+\r
+\r
+\r
+/* -----------------------\r
+ *   Undo list\r
+ * -----------------------\r
+ */\r
+\r
+\r
+.undo-canvas-small {\r
+       width : 60px;\r
+       height : 40px;\r
+       cursor : pointer;\r
+}\r
+\r
+.undo-link {\r
+       width : 60px;\r
+       height : 40px;\r
+       display : block;\r
+       margin : 4px;\r
+       cursor : pointer;\r
+       opacity : 0.8;\r
+}\r
+\r
+.undo-link.hover {\r
+       opacity : 1;\r
+}\r
+\r
+\r
+\r
+/* -----------------------\r
+ *   Action UI controls\r
+ * -----------------------\r
+ */\r
+\r
+\r
+.ui-slider-label, \r
+.ui-checkbox-label, \r
+.ui-textinput-label, \r
+.ui-select-label {\r
+       width : 70px;\r
+       text-align : right;\r
+       margin-right : 5px;\r
+       display : inline-block;\r
+}\r
+\r
+.ui-textinput-label-right {\r
+       margin-left : 5px;\r
+}\r
+\r
+.ui-textinput {\r
+}\r
+\r
+.ui-numericinput {\r
+       width : 35px;\r
+}\r
+\r
+.ui-slider {\r
+       width : 125px;\r
+       display : inline-block;\r
+       margin-left : 3px;\r
+       background-color : #222;\r
+}\r
+\r
+.ui-slider-value {\r
+       font-size : 11px;\r
+       width : 25px;\r
+       display : inline-block;\r
+       margin-left : 10px;\r
+}\r
+\r
+.ui-action-output {\r
+       margin-bottom : 10px;\r
+}\r
+\r
+.ui-accordion .ui-accordion-content-active {\r
+       font-size : 11px;\r
+       overflow : hidden;\r
+}\r
+\r
+.ui-slider-horizontal {\r
+}\r
+\r
+.ui-slider-container, \r
+.ui-checkbox-container, \r
+.ui-textinput-container, \r
+.ui-select-container {\r
+       margin-top : 0px;\r
+       margin-bottom : 10px;\r
+       white-space : nowrap;\r
+}\r
+\r
+.ui-preview-checkbox-container {\r
+       display : inline-block;\r
+}\r
+\r
+.ui-checkbox {\r
+       margin-bottom:3px;\r
+       margin-left:5px;\r
+       margin-right:5px;\r
+       margin-top:0px;\r
+       vertical-align:middle;\r
+}\r
+\r
+input::-moz-focus-inner { border: 0; }\r
+\r
+.action-output-text {\r
+       margin-bottom : 5px;\r
+}\r
+\r
+button {\r
+       margin-right : 5px;\r
+}\r
+\r
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/ui.js b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/ui.js
new file mode 100644 (file)
index 0000000..a0a20ba
--- /dev/null
@@ -0,0 +1,237 @@
+(function($) {\r
+\r
+       var PE = PixasticEditor;\r
+\r
+       function makeSlider(label, id, min, max, step, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-slider-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-slider-label")\r
+                       .attr("for", "input-slider-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $value = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-slider-value")\r
+                       .html(defaultVal());\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               var $slider = $j("<div class='ui-slider'><div class='ui-slider-handle'></div><div class='ui-slider-range'></div></div>", PE.getDocument())\r
+                       .appendTo($ctr)\r
+                       .attr("id", "input-slider-" + id)\r
+                       .slider({\r
+                               slide: function() {\r
+                                       $value.html($j(this).slider("value"));\r
+                                       $valueField.val($j(this).slider("value"));\r
+                               },\r
+                               change : function() {\r
+                                       $value.html($j(this).slider("value"));\r
+                                       $valueField.val($j(this).slider("value"));\r
+                                       if (onChange && performOnChange)\r
+                                               onChange();\r
+                               },\r
+                               min : min,\r
+                               max : max,\r
+                               step : step,\r
+                               value : defaultVal()\r
+                       });\r
+\r
+               $value.appendTo($ctr);\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       slider : $slider,\r
+                       valueText : $value,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               $value.html(defaultVal());\r
+                               $valueField.val(defaultVal());\r
+                               $slider.slider("value", defaultVal());\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeCheckbox(label, id, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-checkbox-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-checkbox-label")\r
+                       .attr("for", "input-checkbox-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               var $checkbox = $j("<input type=\"checkbox\"></input>", PE.getDocument())\r
+                       .addClass("ui-checkbox")\r
+                       .attr("id", "input-checkbox-" + id)\r
+                       .attr("checked", defaultVal())\r
+                       .appendTo($ctr)\r
+                       .change(function() {\r
+                               $valueField.val(this.checked);\r
+                               if (onChange && performOnChange)\r
+                                       onChange();\r
+                       });\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       checkbox : $checkbox,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               $checkbox.attr("checked", defaultVal());\r
+                               $valueField.val(defaultVal());\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeSelect(label, id, values, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-select-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-checkbox-label")\r
+                       .attr("for", "input-checkbox-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var selectHtml = "<select>";\r
+               for (var i=0;i<values.length;i++) {\r
+                       selectHtml += "<option value='" + values[i].value + "' " \r
+                               + (defaultVal() == values[i].value ? "selected" : "") \r
+                               + ">" + values[i].name + "</option>";\r
+               }\r
+               selectHtml += "</select>";\r
+\r
+               var $select = $j(selectHtml).appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               $select.change(\r
+                       function() {\r
+                               $valueField.val(this.options[this.selectedIndex].value);\r
+                               if (onChange && performOnChange)\r
+                                       onChange();\r
+                       }\r
+               );\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       select : $select,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               var defVal = defaultVal();\r
+                               $select.val(defVal);\r
+                               $valueField.val(defVal);\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeNumericInput(label, labelRight, id, min, max, step, defaultVal, onChange) {\r
+               var $ctr = $j("<div></div>", PE.getDocument())\r
+                       .addClass("ui-textinput-container");\r
+\r
+               var $label = $j("<label></label>", PE.getDocument())\r
+                       .addClass("ui-textinput-label")\r
+                       .attr("for", "input-numeric-" + id)\r
+                       .html(label + ":")\r
+                       .appendTo($ctr);\r
+\r
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
+                       .attr("id", "input-hidden-" + id)\r
+                       .val(defaultVal())\r
+                       .appendTo($ctr);\r
+\r
+               var performOnChange = true;\r
+\r
+               function setVal(val) {\r
+                       val = Math.min(max, val);\r
+                       val = Math.max(min, val);\r
+                       $textInput.val(val);\r
+                       $valueField.val(val);\r
+               }\r
+\r
+               var $textInput = $j("<input type=\"text\"></input>", PE.getDocument())\r
+                       .addClass("ui-textinput")\r
+                       .addClass("ui-numericinput")\r
+                       .appendTo($ctr)\r
+                       .val(defaultVal())\r
+                       .attr("id", "input-numeric-" + id)\r
+                       .change(function() {\r
+                               var val = parseFloat(this.value);\r
+                               setVal(val);\r
+                               if (onChange && performOnChange)\r
+                                       onChange();\r
+                       })\r
+                       .keydown(function(e) {\r
+                               var val = parseFloat($j(this).val());\r
+                               if (e.keyCode == 38) { // up\r
+                                       setVal(val + step);\r
+                               }\r
+                               if (e.keyCode == 40) { // down\r
+                                       setVal(val - step);\r
+                               }\r
+                       });\r
+\r
+               if (labelRight) {\r
+                       var $labelRight = $j("<label></label>", PE.getDocument())\r
+                               .addClass("ui-textinput-label-right")\r
+                               .html(labelRight)\r
+                               .appendTo($ctr);\r
+               }\r
+\r
+               return {\r
+                       container : $ctr,\r
+                       label : $label,\r
+                       textinput : $textInput,\r
+                       valueField : $valueField,\r
+                       reset : function() {\r
+                               performOnChange = false;\r
+                               setVal(defaultVal());\r
+                               performOnChange = true;\r
+                       }\r
+               };\r
+       }\r
+\r
+       function makeButton(text) {\r
+               var $button = $j("<button></button>", PE.getDocument()).html(text);\r
+               return $button;\r
+       }\r
+\r
+\r
+       PE.UI = {\r
+               makeSlider : makeSlider,\r
+               makeCheckbox : makeCheckbox,\r
+               makeNumericInput : makeNumericInput,\r
+               makeSelect : makeSelect,\r
+               makeButton : makeButton\r
+       }\r
+\r
+})(PixasticEditor.jQuery);\r
+\r
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/uidata.js b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/uidata.js
new file mode 100644 (file)
index 0000000..03f50b7
--- /dev/null
@@ -0,0 +1,966 @@
+(function($) {\r
+\r
+var PE = PixasticEditor;\r
+\r
+PE.UI.data = {\r
+       tabs : [\r
+               {\r
+                       title : "Reshape",\r
+                       id : "reshape",\r
+                       actions : [\r
+                               {\r
+                                       title : "Resize",\r
+                                       id : "resize",\r
+                                       isAction : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Enter new dimensions below."\r
+                                               },\r
+                                               {\r
+                                                       label : "Width",\r
+                                                       labelRight : "px",\r
+                                                       option : "width",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageWidth(); },\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Height",\r
+                                                       labelRight : "px",\r
+                                                       option : "height",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageHeight(); },\r
+                                                       ui : "text"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Crop",\r
+                                       id : "crop",\r
+                                       isAction : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Enter new crop values below or use mouse to select crop area."\r
+                                               },\r
+                                               {\r
+                                                       label : "X",\r
+                                                       labelRight : "px",\r
+                                                       option : "left",\r
+                                                       type : "number", \r
+                                                       range : [0,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : 0,\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Y",\r
+                                                       labelRight : "px",\r
+                                                       option : "top",\r
+                                                       type : "number", \r
+                                                       range : [0,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : 0,\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Width",\r
+                                                       labelRight : "px",\r
+                                                       option : "width",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageWidth(); },\r
+                                                       ui : "text"\r
+                                               },\r
+                                               {\r
+                                                       label : "Height",\r
+                                                       labelRight : "px",\r
+                                                       option : "height",\r
+                                                       type : "number", \r
+                                                       range : [1,10000], \r
+                                                       step : 1,\r
+                                                       defaultValue : function() { return PE.getImageHeight(); },\r
+                                                       ui : "text"\r
+                                               }\r
+                                       ],\r
+                                       onactivate : function() {\r
+                                               var $canvas = PE.getDisplayCanvas();\r
+                                               var onchange = function(c) {\r
+                                                       var doc = PE.getDocument();\r
+                                                       $j("#input-numeric-crop-left", doc).val(c.x).change();\r
+                                                       $j("#input-numeric-crop-top", doc).val(c.y).change();\r
+                                                       $j("#input-numeric-crop-width", doc).val(c.w).change();\r
+                                                       $j("#input-numeric-crop-height", doc).val(c.h).change();\r
+                                                       $j("#input-hidden-crop-left", doc).val(c.x).change();\r
+                                                       $j("#input-hidden-crop-top", doc).val(c.y).change();\r
+                                                       $j("#input-hidden-crop-width", doc).val(c.w).change();\r
+                                                       $j("#input-hidden-crop-height", doc).val(c.h).change();\r
+                                               }\r
+                                               $canvas.data("Jcrop-onchange", onchange);\r
+                                               $canvas.Jcrop({onChange:onchange}, PE.getDocument());\r
+                                       },\r
+                                       ondeactivate : function() {\r
+                                               var $canvas = PE.getDisplayCanvas();\r
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
+                                                       $canvas.data("Jcrop").destroy();\r
+                                       },\r
+                                       onafteraction : function(action, isPreview) {\r
+                                               action.ondeactivate();\r
+                                               action.onactivate();\r
+                                               /*\r
+                                               var $canvas = PE.getDisplayCanvas();\r
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
+                                                       $canvas.data("Jcrop").destroy();\r
+                                               var onchange = $canvas.data("Jcrop-onchange");\r
+                                               $canvas.Jcrop({onChange:onchange});\r
+                                               */\r
+                                       }\r
+                               },\r
+                               {\r
+                                       title : "Rotate",\r
+                                       id : "rotate",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       forcePreview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Enter the angle (-180&deg; to 180&deg;) you want to rotate the picture. Use negative values for clockwise rotation, positive for counterclockwise."\r
+                                               },\r
+                                               {\r
+                                                       label : "Angle",\r
+                                                       labelRight : "&deg;",\r
+                                                       option : "angle",\r
+                                                       type : "number", \r
+                                                       range : [-180,180], \r
+                                                       step : 1,\r
+                                                       defaultValue : 0,\r
+                                                       ui : "text"\r
+                                               }\r
+                                       ],\r
+                                       onactivate : function() {\r
+                                               var doc = PE.getDocument();\r
+                                               var $displayCanvas = PE.getDisplayCanvas();\r
+                                               var dim = Math.min($displayCanvas.attr("height"), 200);\r
+                                               var $canvas = $j("<canvas></canvas>", doc);\r
+                                               PE.getOverlay().append($canvas);\r
+\r
+                                               $canvas.attr("width", dim);\r
+                                               $canvas.attr("height", dim);\r
+                                               $canvas.width(dim);\r
+                                               $canvas.height(dim);\r
+\r
+                                               $canvas.css("marginTop", (($displayCanvas.attr("height") - dim) * 0.5) + "px");\r
+\r
+                                               var lineWidth = 20;\r
+                                               var radius = dim/2 - lineWidth;\r
+                                               if (radius < 1) radius = 1;\r
+\r
+                                               var ctx = $canvas.get(0).getContext("2d");\r
+                                               ctx.beginPath()\r
+                                               ctx.arc(dim/2, dim/2, radius, 0, Math.PI*2, true);\r
+                                               ctx.closePath();\r
+                                               ctx.fillStyle = "rgba(200,200,200,0.2)";\r
+                                               ctx.fill();\r
+                                               ctx.strokeStyle = "rgba(200,200,200,0.5)";\r
+                                               ctx.lineWidth = 20;\r
+                                               ctx.stroke();\r
+\r
+                                               $j("#image-area", doc).css("cursor", "move");\r
+\r
+                                               $overlay = PE.getOverlay();\r
+\r
+                                               $canvas.get(0).ondragstart = function() {return false;}\r
+                                               $canvas.get(0).onselectstart = function() {return false;}\r
+\r
+                                               var mx = 0, my = 0;\r
+                                               var startMouseAngle = 0;\r
+                                               var startAngle = 0;\r
+                                               var deltaAngle = 0;\r
+                                               var angle = 0;\r
+\r
+                                               var mouseIsDown = false;\r
+                                               var onmousedown = function(e) {\r
+                                                       mouseIsDown = true;\r
+                                                       var offset = $displayCanvas.offset();\r
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
+                                                       startMouseAngle = Math.atan2(my, mx);\r
+                                                       startAngle = parseInt($j("#input-numeric-rotate-angle", doc).val(), 10) * Math.PI / 180;\r
+                                               }\r
+                                               var onmousemove = function(e) {\r
+                                                       if (!mouseIsDown) return;\r
+\r
+                                                       var offset = $displayCanvas.offset();\r
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
+                                                       deltaAngle = Math.atan2(my, mx) - startMouseAngle;\r
+                                                       angle = startAngle - deltaAngle;\r
+                                                       if (angle < -Math.PI) angle += 2*Math.PI;\r
+                                                       if (angle > Math.PI) angle -= 2*Math.PI;\r
+                                                       $j("#input-numeric-rotate-angle", doc).val(Math.round(angle * 180 / Math.PI));\r
+                                                       $j("#input-numeric-rotate-angle", doc).change();\r
+                                               }\r
+                                               var onmouseup = function() {\r
+                                                       mouseIsDown = false;\r
+                                               }\r
+\r
+                                               $j("#image-area", doc).bind("mousedown", onmousedown);\r
+                                               $j("#image-area", doc).bind("mousemove", onmousemove);\r
+                                               $j("#image-area", doc).bind("mouseup", onmouseup);\r
+                                               $canvas.data("onmousedown", onmousedown);\r
+                                               $canvas.data("onmousemove", onmousemove);\r
+                                               $canvas.data("onmouseup", onmouseup);\r
+                                               $displayCanvas.data("rotateCanvas", $canvas);\r
+                                       },\r
+                                       ondeactivate : function() {\r
+                                               var doc = PE.getDocument();\r
+                                               var $displayCanvas = PE.getDisplayCanvas();\r
+                                               $overlay = PE.getOverlay();\r
+                                               $j("#image-area", doc).css("cursor", "default");\r
+\r
+                                               var $canvas = $displayCanvas.data("rotateCanvas");\r
+\r
+                                               $j("#image-area", doc).unbind("mousedown", $canvas.data("onmousedown"));\r
+                                               $j("#image-area", doc).unbind("mousemove", $canvas.data("onmousemove"));\r
+                                               $j("#image-area", doc).unbind("mouseup", $canvas.data("onmouseup"));\r
+                                               $displayCanvas.removeData("rotateCanvas");\r
+                                               $canvas.remove();\r
+                                       },\r
+                                       onafteraction : function(action, isPreview) {\r
+                                               if (!isPreview) { // rebuild the rotate widget\r
+                                                       action.ondeactivate();\r
+                                                       action.onactivate();\r
+                                               }\r
+                                       },\r
+                                       onoverlayupdate : function() {\r
+                                               var $canvas = PE.getDisplayCanvas().data("rotateCanvas");\r
+                                               if ($canvas) {\r
+                                                       $canvas.css("marginTop", ((PE.getDisplayCanvas().get(0).height - $canvas.get(0).height) * 0.5) + "px");\r
+                                               }\r
+                                       }\r
+                               },\r
+                               {\r
+                                       title : "Flip",\r
+                                       id : "flip",\r
+                                       isAction : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       label : "Axis",\r
+                                                       option : "axis",\r
+                                                       type : "string", \r
+                                                       values : [\r
+                                                               {name:"Horizontal", value:"horizontal"},\r
+                                                               {name:"Vertical", value:"vertical"}\r
+                                                       ],\r
+                                                       defaultValue : "vertical",\r
+                                                       ui : "select"\r
+                                               }\r
+                                       ]\r
+                               }\r
+                       ]\r
+               },\r
+               {\r
+                       title : "Develop",\r
+                       id : "develop",\r
+                       actions : [\r
+                               {\r
+                                       title : "Brightness & Contrast",\r
+                                       id : "brightness",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to adjust the brightness and/or contrast of the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Brightness",\r
+                                                       option : "brightness",\r
+                                                       type : "number", \r
+                                                       range : [-100,100], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Contrast",\r
+                                                       option : "contrast",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Legacy mode",\r
+                                                       option : "legacy",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Hue/Saturation/Lightness",\r
+                                       id : "hsl",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to adjust the hue, saturation and/or lightness of the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Hue",\r
+                                                       option : "hue",\r
+                                                       type : "number", \r
+                                                       range : [-180,180], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Saturation",\r
+                                                       option : "saturation",\r
+                                                       type : "number", \r
+                                                       range : [-100,100], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Lightness",\r
+                                                       option : "lightness",\r
+                                                       type : "number", \r
+                                                       range : [-100,100], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Adjust colors",\r
+                                       id : "coloradjust",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to shift the R, G and B channels of the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Red",\r
+                                                       option : "red",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Green",\r
+                                                       option : "green",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Blue",\r
+                                                       option : "blue",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Desaturate",\r
+                                       id : "desaturate",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "This will desaturate the image. Select \"Use average\" to use the average value of the R, G and B channels rather than the default mix of 30% red, 59% green and 11% blue."\r
+                                               },\r
+                                               {\r
+                                                       label : "Use average",\r
+                                                       option : "average",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Sepia toning",\r
+                                       id : "sepia",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Applies a sepia toning effect to the image."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Invert",\r
+                                       id : "invert",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "This will invert the colors of the image."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Lighten",\r
+                                       id : "lighten",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the slider below to lighten or darken the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [-1,1], \r
+                                                       defaultValue : 0,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Unsharp mask",\r
+                                       id : "unsharpmask",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the sliders below to adjust the unsharp mask parameters."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,500], \r
+                                                       defaultValue : 200,\r
+                                                       ui : "slider",\r
+                                                       step : 2\r
+                                               },\r
+                                               {\r
+                                                       label : "Radius",\r
+                                                       option : "radius",\r
+                                                       type : "number", \r
+                                                       range : [0,5], \r
+                                                       defaultValue : 2,\r
+                                                       ui : "slider",\r
+                                                       step : 0.1\r
+                                               },\r
+                                               {\r
+                                                       label : "Threshold",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,255], \r
+                                                       defaultValue : 25,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               }\r
+\r
+                       ]\r
+               },\r
+               {\r
+                       title : "Effects",\r
+                       id : "effects",\r
+                       actions : [\r
+                               {\r
+                                       title : "Blur",\r
+                                       id : "blurfast",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Use the slider to set the blur amount."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+\r
+                               },\r
+                               {\r
+                                       title : "Edge detection",\r
+                                       id : "edges",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Performs edge detection on the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Greyscale",\r
+                                                       option : "mono",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               },\r
+                                               {\r
+                                                       label : "Invert",\r
+                                                       option : "invert",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Emboss",\r
+                                       id : "emboss",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Adds an emboss-like effect to the image. Use the controls below to control the appearance of the effect. Choose \"Blend\" to blend the effect with the original image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Strength",\r
+                                                       option : "strength",\r
+                                                       type : "number", \r
+                                                       range : [0,10], \r
+                                                       defaultValue : 1,\r
+                                                       ui : "slider",\r
+                                                       step : 0.1\r
+                                               },\r
+                                               {\r
+                                                       label : "Grey level",\r
+                                                       option : "greyLevel",\r
+                                                       type : "number", \r
+                                                       range : [0,255], \r
+                                                       defaultValue : 180,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Direction",\r
+                                                       option : "direction",\r
+                                                       type : "string", \r
+                                                       values : [\r
+                                                               {name:"Top left", value:"topleft"},\r
+                                                               {name:"Top", value:"top"},\r
+                                                               {name:"Top right", value:"topright"},\r
+                                                               {name:"Right", value:"right"},\r
+                                                               {name:"Bottom right", value:"bottomright"},\r
+                                                               {name:"Bottom", value:"bottom"},\r
+                                                               {name:"Bottom left", value:"bottomleft"},\r
+                                                               {name:"Left", value:"left"}\r
+                                                       ],\r
+                                                       defaultValue : "topleft",\r
+                                                       ui : "select"\r
+                                               },\r
+                                               {\r
+                                                       label : "Blend",\r
+                                                       option : "blend",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+\r
+                               },\r
+                               {\r
+                                       title : "Glow",\r
+                                       id : "glow",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Creates a glowing effect on the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Radius",\r
+                                                       option : "radius",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Add noise",\r
+                                       id : "noise",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Add random noise to the image."\r
+                                               },\r
+                                               {\r
+                                                       label : "Amount",\r
+                                                       option : "amount",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Strength",\r
+                                                       option : "strength",\r
+                                                       type : "number", \r
+                                                       range : [0,1], \r
+                                                       defaultValue : 0.5,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Greyscale",\r
+                                                       option : "mono",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Remove noise",\r
+                                       id : "removenoise",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Attempts to remove noise from the image. Works best for getting rid of single pixels that stand out."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Pointillize",\r
+                                       id : "pointillize",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Paints the picture with circular points."\r
+                                               },\r
+                                               {\r
+                                                       label : "Point radius",\r
+                                                       option : "radius",\r
+                                                       type : "number", \r
+                                                       range : [1,50], \r
+                                                       defaultValue : 5,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               },\r
+                                               {\r
+                                                       label : "Density",\r
+                                                       option : "density",\r
+                                                       type : "number", \r
+                                                       range : [0,5], \r
+                                                       defaultValue : 1,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Noise",\r
+                                                       option : "noise",\r
+                                                       type : "number", \r
+                                                       range : [0,2], \r
+                                                       defaultValue : 1,\r
+                                                       ui : "slider",\r
+                                                       step : 0.01\r
+                                               },\r
+                                               {\r
+                                                       label : "Transparent",\r
+                                                       option : "transparent",\r
+                                                       type : "boolean", \r
+                                                       defaultValue : false,\r
+                                                       ui : "checkbox"\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Posterize",\r
+                                       id : "posterize",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Reduces the number of colours to a specified number of levels."\r
+                                               },\r
+                                               {\r
+                                                       label : "Levels",\r
+                                                       option : "levels",\r
+                                                       type : "number", \r
+                                                       range : [1,32], \r
+                                                       defaultValue : 5,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Solarize",\r
+                                       id : "solarize",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Applies a solarize effect to the image."\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       title : "Mosaic",\r
+                                       id : "mosaic",\r
+                                       isAction : true,\r
+                                       preview : true,\r
+                                       controls : [\r
+                                               {\r
+                                                       type : "output",\r
+                                                       content : "Creates a pixelated look."\r
+                                               },\r
+                                               {\r
+                                                       label : "Block size",\r
+                                                       option : "blockSize",\r
+                                                       type : "number", \r
+                                                       range : [1,100], \r
+                                                       defaultValue : 5,\r
+                                                       ui : "slider",\r
+                                                       step : 1\r
+                                               }\r
+                                       ]\r
+                               }\r
+\r
+\r
+                       ]\r
+               },\r
+               {\r
+                       title : "Done",\r
+                       id : "done",\r
+                       actions : [\r
+                               {\r
+                                       title : "Save to page",\r
+                                       id : "savepage",\r
+                                       content : function($ctr) {\r
+                                               var doc = PE.getDocument();\r
+                                               $j("<div></div>", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .html("This will save the image to the page.")\r
+                                                       .appendTo($ctr);\r
+\r
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($ctr);\r
+                                               var $saveButton = $j("<button></button>", doc)\r
+                                                       .html("Save image")\r
+                                                       .appendTo($buttonCtr)\r
+                                                       .click(function() {\r
+                                                               PE.saveToPage();\r
+                                                       });\r
+\r
+                                       }\r
+                               },\r
+                               {\r
+                                       title : "Save to file",\r
+                                       id : "savefile",\r
+                                       content : function(ctr) {\r
+                                               var doc = PE.getDocument();\r
+                                               $j("<div></div>", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .html("This will save the image to your local computer.")\r
+                                                       .appendTo(ctr);\r
+\r
+                                               var formats = PE.validSaveFormats();\r
+\r
+                                               var selectHtml = "<select>";\r
+                                               for (var i=0;i<formats.length;i++) {\r
+                                                       selectHtml += "<option value='" + formats[i].mime + "'>" + formats[i].name + "</option>";\r
+                                               }\r
+                                               selectHtml += "</select>";\r
+\r
+                                               var selectCtr = $j("<div></div>", doc)\r
+                                                       .addClass("ui-select-container");\r
+\r
+\r
+                                               var label = $j("<div></div>", doc)\r
+                                                       .addClass("ui-select-label")\r
+                                                       .html("Format:")\r
+                                                       .appendTo(selectCtr);\r
+\r
+                                               var formatSelect = $j(selectHtml, doc).appendTo(selectCtr);\r
+\r
+\r
+                                               selectCtr.appendTo(ctr);\r
+\r
+                                               var buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
+                                               var saveButton = $j("<button></button>", doc)\r
+                                                       .html("Save file")\r
+                                                       .appendTo(buttonCtr)\r
+\r
+                                               saveButton.click(function() {\r
+                                                       var selectElement = formatSelect.get(0);\r
+                                                       var formatMime = selectElement.options[selectElement.selectedIndex].value;\r
+                                                       var dataString = PE.getDataURI(formatMime);\r
+\r
+                                                       var dialog = $j("<div></div>", doc)\r
+                                                               .attr("id", "save-dialog")\r
+                                                               .attr("title", "Download file")\r
+                                                               .html(\r
+                                                                       "Right click the link below and select \"Save as...\" to save your file.<br/>"\r
+                                                                       + "<br/>"\r
+                                                                       + "<a href=\"" + dataString + "\">Image Link</a>"\r
+                                                               )\r
+                                                               .dialog();\r
+\r
+                                                       // the dialog is added outside the Pixastic container, so get it back in.\r
+                                                       var dialogParent = $j(dialog.get(0).parentNode);\r
+                                                       $j("#pixastic-editor", doc).append(dialogParent);\r
+                                               });\r
+                                       }\r
+                               },\r
+                               /*\r
+                               {\r
+                                       title : "Upload to Flickr",\r
+                                       id : "flickrupload",\r
+                                       content : function($ctr) {\r
+                                               var doc = PE.getDocument();\r
+\r
+                                               function flickrAuthed() {\r
+                                                       var $text = $j("<div />", doc)\r
+                                                               .addClass("action-output-text")\r
+                                                               .html("Authorized as: " + PE.Flickr.getAuthName());\r
+\r
+                                                       var $buttonCtr = $j("<div></div>", doc);\r
+                                                       var $uploadButton = $j("<button></button>", doc)\r
+                                                               .html("Upload image")\r
+                                                               .appendTo($buttonCtr)\r
+\r
+                                                       $uploadButton.click(function() {\r
+                                                               PE.Flickr.uploadImage(PE.getDataURI());\r
+                                                       });\r
+\r
+                                                       $ctr.append($text, $buttonCtr);\r
+                                               }\r
+\r
+                                               var $authCtr = $j("<div />", doc).appendTo($ctr);\r
+\r
+                                               $j("<div />", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .html("If you have a Flickr account you can now upload your image to Flickr. You will need to give access to your account first. Click the button below to open an authorization window.")\r
+                                                       .appendTo($authCtr);\r
+\r
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($authCtr);\r
+                                               var $authButton = $j("<button></button>", doc)\r
+                                                       .html("Authenticate")\r
+                                                       .appendTo($buttonCtr)\r
+\r
+                                               var checkButtonAdded = false;\r
+                                               $authButton.click(function() {\r
+                                                       PE.Flickr.auth();\r
+                                                       if (!checkButtonAdded) {\r
+                                                               checkButtonAdded = true;\r
+\r
+                                                               var $text = $j("<div />", doc)\r
+                                                                       .addClass("action-output-text")\r
+                                                                       .html("Now click the button below when you have authorized access to your Flickr account.");\r
+       \r
+                                                               var $buttonCtr = $j("<div></div>", doc);\r
+       \r
+                                                               $authCtr.append($text, $buttonCtr);\r
+       \r
+                                                               var $checkButton = $j("<button></button>", doc)\r
+                                                                       .html("I have authenticated!")\r
+                                                                       .appendTo($buttonCtr);\r
+       \r
+                                                               $checkButton.click(function() {\r
+                                                                       PE.Flickr.checkAuth(function(res) {\r
+                                                                               if (res.stat == "ok") {\r
+                                                                                       $authCtr.remove();\r
+                                                                                       flickrAuthed();\r
+                                                                               }\r
+                                                                       });\r
+                                                               });\r
+                                                       }\r
+\r
+                                               });\r
+                                       }\r
+                               },\r
+                               */\r
+                               {\r
+                                       title : "Quit",\r
+                                       id : "quit", \r
+                                       content : function(ctr) {\r
+                                               var doc = PE.getDocument();\r
+\r
+                                               $j("<div>Are you sure you want to quit?</div>", doc)\r
+                                                       .addClass("action-output-text")\r
+                                                       .appendTo(ctr);\r
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
+\r
+                                               var $quitButton = PE.UI.makeButton("Yes, quit now!")\r
+                                                       .appendTo($buttonCtr)\r
+\r
+                                               $quitButton.click(function() {\r
+                                                       PE.unload();\r
+                                               });\r
+\r
+                                               var $saveButton = PE.UI.makeButton("Save to page and quit")\r
+                                                       .appendTo($buttonCtr)\r
+                                                       .click(function() {\r
+                                                               PE.saveToPage();\r
+                                                               PE.unload();\r
+                                                       });\r
+                                       }\r
+                               }\r
+                       ]\r
+               }\r
+       ]\r
+};\r
+\r
+\r
+})(PixasticEditor.jQuery);
\ No newline at end of file
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic.core.js b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic.core.js
new file mode 100644 (file)
index 0000000..5988428
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Pixastic Lib - Core Functions - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+var Pixastic = (function() {
+
+
+
+       function addEvent(el, event, handler) {
+               if (el.addEventListener)
+                       el.addEventListener(event, handler, false); 
+               else if (el.attachEvent)
+                       el.attachEvent("on" + event, handler); 
+       }
+
+       function onready(handler) {
+               var handlerDone = false;
+               var execHandler = function() {
+                       if (!handlerDone) {
+                               handlerDone = true;
+                               handler();
+                       }
+               }
+               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");
+               var script = document.getElementById("__onload_ie_sumbox__");
+               script.onreadystatechange = function() {
+                       if (script.readyState == "complete") {
+                               script.parentNode.removeChild(script);
+                               execHandler();
+                       }
+               }
+               if (document.addEventListener)
+                       document.addEventListener("DOMContentLoaded", execHandler, false); 
+               addEvent(window, "load", execHandler);
+       }
+
+
+       function init() {
+               if (!Pixastic.parseOnLoad) return;
+               var imgEls = getElementsByClass("pixastic", null, "img");
+               var canvasEls = getElementsByClass("pixastic", null, "canvas");
+               var elements = imgEls.concat(canvasEls);
+               for (var i=0;i<elements.length;i++) {
+                       (function() {
+
+                       var el = elements[i];
+                       var actions = [];
+                       var classes = el.className.split(" ");
+                       for (var c=0;c<classes.length;c++) {
+                               var cls = classes[c];
+                               if (cls.substring(0,9) == "pixastic-") {
+                                       var actionName = cls.substring(9);
+                                       if (actionName != "")
+                                               actions.push(actionName);
+                               }
+                       }
+                       if (actions.length) {
+                               if (el.tagName == "IMG") {
+                                       var dataImg = new Image();
+                                       dataImg.src = el.src;
+                                       if (dataImg.complete) {
+                                               for (var a=0;a<actions.length;a++) {
+                                                       var res = Pixastic.applyAction(el, el, actions[a], null);
+                                                       if (res) 
+                                                               el = res;
+                                               }
+                                       } else {
+                                               dataImg.onload = function() {
+                                                       for (var a=0;a<actions.length;a++) {
+                                                               var res = Pixastic.applyAction(el, el, actions[a], null)
+                                                               if (res) 
+                                                                       el = res;
+                                                       }
+                                               }
+                                       }
+                               } else {
+                                       setTimeout(function() {
+                                               for (var a=0;a<actions.length;a++) {
+                                                       var res = Pixastic.applyAction(
+                                                               el, el, actions[a], null
+                                                       );
+                                                       if (res) 
+                                                               el = res;
+                                               }
+                                       },1);
+                               }
+                       }
+
+                       })();
+               }
+       }
+
+       onready(init);
+
+
+       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/
+       function getElementsByClass(searchClass,node,tag) {
+                       var classElements = new Array();
+                       if ( node == null )
+                                       node = document;
+                       if ( tag == null )
+                                       tag = '*';
+
+                       var els = node.getElementsByTagName(tag);
+                       var elsLen = els.length;
+                       var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
+                       for (i = 0, j = 0; i < elsLen; i++) {
+                                       if ( pattern.test(els[i].className) ) {
+                                                       classElements[j] = els[i];
+                                                       j++;
+                                       }
+                       }
+                       return classElements;
+       }
+
+       var debugElement;
+
+       function writeDebug(text, level) {
+               if (!Pixastic.debug) return;
+
+               try {
+                       switch (level) {
+                               case "warn" : 
+                                       console.warn("Pixastic:", text);
+                                       break;
+                               case "error" :
+                                       console.error("Pixastic:", text);
+                                       break;
+                               default:
+                                       console.log("Pixastic:", text);
+                       }
+               } catch(e) {
+               }
+               if (!debugElement) {
+                       
+               }
+       }
+
+
+       return {
+
+               parseOnLoad : false,
+
+               debug : false,
+               
+               applyAction : function(img, dataImg, actionName, options) {
+
+                       options = options || {};
+
+                       var imageIsCanvas = (img.tagName == "CANVAS");
+                       if (imageIsCanvas && Pixastic.Client.isIE()) {
+                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");
+                               return false;
+                       }
+
+                       var canvas, ctx;
+                       if (Pixastic.Client.hasCanvas()) {
+                               canvas = document.createElement("canvas");
+                               ctx = canvas.getContext("2d");
+                       }
+
+                       var w = parseInt(img.offsetWidth);
+                       var h = parseInt(img.offsetHeight);
+
+                       if (actionName.indexOf("(") > -1) {
+                               var tmp = actionName;
+                               actionName = tmp.substr(0, tmp.indexOf("("));
+                               var arg = tmp.match(/\((.*?)\)/);
+                               if (arg[1]) {
+                                       arg = arg[1].split(";");
+                                       for (var a=0;a<arg.length;a++) {
+                                               thisArg = arg[a].split("=");
+                                               if (thisArg.length == 2) {
+                                                       if (thisArg[0] == "rect") {
+                                                               var rectVal = thisArg[1].split(",");
+                                                               options[thisArg[0]] = {
+                                                                       left : parseInt(rectVal[0],10)||0,
+                                                                       top : parseInt(rectVal[1],10)||0,
+                                                                       width : parseInt(rectVal[2],10)||0,
+                                                                       height : parseInt(rectVal[3],10)||0
+                                                               }
+                                                       } else {
+                                                               options[thisArg[0]] = thisArg[1];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (!options.rect) {
+                               options.rect = {
+                                       left : 0, top : 0, width : w, height : h
+                               };
+                       }
+                       var validAction = false;
+                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {
+                               validAction = true;
+                       }
+                       if (!validAction) {
+                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");
+                               return false;
+                       }
+                       if (!Pixastic.Actions[actionName].checkSupport()) {
+                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");
+                               return false;
+                       }
+
+                       if (Pixastic.Client.hasCanvas()) {
+                               canvas.width = w;
+                               canvas.height = h;
+                               canvas.style.width = w+"px";
+                               canvas.style.height = h+"px";
+                               ctx.drawImage(dataImg,0,0,w,h);
+                       }
+
+                       var params = {
+                               image : img,
+                               canvas : canvas,
+                               width : w,
+                               height : h,
+                               useData : true,
+                               options : options
+                       }
+       
+                       var res = Pixastic.Actions[actionName].process(params);
+
+                       if (!res) {
+                               return false;
+                       }
+
+                       if (Pixastic.Client.hasCanvas()) {
+                               if (params.useData) {
+                                       if (Pixastic.Client.hasCanvasImageData()) {
+                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);
+                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.
+                                               canvas.getContext("2d").fillRect(0,0,0,0);
+                                       }
+                               }
+                               // copy properties and stuff from the source image
+                               canvas.title = img.title;
+                               canvas.imgsrc = img.imgsrc;
+                               if (!imageIsCanvas) canvas.alt  = img.alt;
+                               if (!imageIsCanvas) canvas.imgsrc = img.src;
+                               canvas.className = img.className;
+                               if (img.getAttribute("style"))
+                                       canvas.setAttribute("style", img.getAttribute("style"));
+                               canvas.cssText = img.cssText;
+                               canvas.name = img.name;
+                               canvas.tabIndex = img.tabIndex;
+                               canvas.id = img.id;
+
+                               if (img.parentNode && img.parentNode.replaceChild) {
+                                       img.parentNode.replaceChild(canvas, img);
+                               }
+
+                               return canvas;
+                       }
+
+                       return img;
+               },
+
+               prepareData : function(params, getCopy) {
+                       var ctx = params.canvas.getContext("2d");
+                       var rect = params.options.rect;
+                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
+                       var data = dataDesc.data;
+                       if (!getCopy) params.canvasData = dataDesc;
+                       return data;
+               },
+
+               // load the image file
+               process : function(img, actionName, options, callback)
+               {
+                       if (img.tagName == "IMG") {
+                               var dataImg = new Image();
+                               dataImg.src = img.src;
+                               if (dataImg.complete) {
+                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);
+                                       if (callback) callback(res);
+                                       return res;
+                               } else {
+                                       dataImg.onload = function() {
+                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)
+                                               if (callback) callback(res);
+                                       }
+                               }
+                       }
+                       if (img.tagName == "CANVAS") {
+                               var res = Pixastic.applyAction(img, img, actionName, options);
+                               if (callback) callback(res);
+                               return res;
+                       }
+               },
+
+               Client : {
+                       hasCanvas : (function() {
+                               var c = document.createElement("canvas");
+                               var val = false;
+                               try {
+                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));
+                               } catch(e) {}
+                               return function() {
+                                       return val;
+                               }
+                       })(),
+
+                       hasCanvasImageData : (function() {
+                               var c = document.createElement("canvas");
+                               var val = false;
+                               var ctx;
+                               try {
+                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {
+                                               val = (typeof ctx.getImageData == "function");
+                                       }
+                               } catch(e) {}
+                               return function() {
+                                       return val;
+                               }
+                       })(),
+
+                       isIE : function() {
+                               return !!document.all && !!window.attachEvent && !window.opera;
+                       }
+               },
+
+               Actions : {}
+       }
+
+
+})();
diff --git a/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic.jquery.js b/js2/mwEmbed/libClipEdit/pixastic-lib/pixastic.jquery.js
new file mode 100644 (file)
index 0000000..7664d29
--- /dev/null
@@ -0,0 +1,22 @@
+
+if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {
+       jQuery.fn.pixastic = function(action, options) {
+               var newElements = [];
+               this.each(
+                       function () {
+                               if (this.tagName == "IMG" && !this.complete) {
+                                       return;
+                               }
+                               var res = Pixastic.process(this, action, options);
+                               if (res) {
+                                       newElements.push(res);
+                               }
+                       }
+               );
+               if (newElements.length > 0)
+                       return jQuery(newElements);
+               else
+                       return this;
+       };
+
+};
diff --git a/js2/mwEmbed/libEmbedVideo/embedVideo.js b/js2/mwEmbed/libEmbedVideo/embedVideo.js
new file mode 100644 (file)
index 0000000..2c82944
--- /dev/null
@@ -0,0 +1,2842 @@
+/*  the base video control JSON object with default attributes
+*      for supported attribute details see README
+*/
+
+loadGM({
+       "loading_plugin" : "loading plugin<blink>...</blink>",
+
+       "select_playback" : "Set Playback Preference",
+       "link_back" : "Link Back",
+       "error_load_lib" : "mv_embed: Unable to load required javascript libraries\n insert script via DOM has failed, try reloading?  ",
+                                        
+       "error_swap_vid" : "Error:mv_embed was unable to swap the video tag for the mv_embed interface",
+       
+       "add_to_end_of_sequence" : "Add to End of Sequence",
+       
+       "missing_video_stream" : "The video file for this stream is missing",   
+       
+       "play_clip" : "Play Clip",
+       "pause_clip": "Pause Clip",
+       "volume_control": "Volume Control",
+       "player_options": "Player Options",
+       "closed_captions": "Close Captions",
+       "player_fullscreen": "Fullscreen",      
+
+       "next_clip_msg" : "Play Next Clip",
+       "prev_clip_msg" : "Play Previous Clip",
+       "current_clip_msg" : "Continue Playing this Clip",      
+       "seek_to" : "Seek to",
+       
+       "download_segment" : "Download Selection:",
+       "download_full" : "Download Full Video File:",
+       "download_right_click": "To download right click and select <i>save target as</i>",
+       "download_clip" : "Download the Clip",
+       "download_text" : "Download Text (<a style=\"color:white\" title=\"cmml\" href=\"http://wiki.xiph.org/index.php/CMML\">cmml</a> xml):",
+       
+       "clip_linkback" : "Clip Source Page",
+       
+       "mv_ogg-player-vlc-mozilla" : "VLC Plugin",
+       "mv_ogg-player-videoElement" : "Native Ogg Video Support",
+       "mv_ogg-player-vlc-activex" : "VLC ActiveX",    
+       "mv_ogg-player-oggPlugin" : "Generic Ogg Plugin",
+       "mv_ogg-player-quicktime-mozilla" : "Quicktime Plugin",
+       "mv_ogg-player-quicktime-activex" : "Quicktime ActiveX",
+       "mv_ogg-player-cortado" : "Java Cortado",
+       "mv_ogg-player-flowplayer" : "Flowplayer",
+       "mv_ogg-player-selected" : " (selected)",
+       "mv_ogg-player-omtkplayer" : "OMTK Flash Vorbis",
+       "mv_generic_missing_plugin" : "You browser does not appear to support playback type: <b>$1</b><br> visit the <a href=\"http://commons.wikimedia.org/wiki/Commons:Media_help\">Playback Methods</a> page to download a player<br>",
+       
+       "mv_for_best_experience": "For a better video playback experience we recommend <b><a href=\"http://www.mozilla.com/en-US/firefox/upgrade.html?from=mv_embed\">Firefox 3.5</a></b>",
+       "mv_do_not_warn_again": "Do not warn me again." 
+               
+});
+
+var default_video_attributes = {
+       "id":null,
+       "class":null,
+       "style":null,
+       "name":null,
+       "innerHTML":null,
+       "width":"320",
+       "height":"240",
+
+       //video attributes:
+       "src":null,
+       "autoplay":false,
+       "start":0,
+       "end":null,
+       "controls":true,
+       "muted":false,
+       
+       //roe url (for xml based metadata)
+       "roe":null,
+       //if roe includes metadata tracks we can expose a link to metadata
+       "show_meta_link":true,
+
+       //default state attributes per html5 spec:
+       //http://www.whatwg.org/specs/web-apps/current-work/#video)
+       "paused":true,
+       "readyState":0,  //http://www.whatwg.org/specs/web-apps/current-work/#readystate
+       "currentTime":0, //current playback position (should be updated by plugin)
+       "duration":null,   //media duration (read from file or the temporal url)
+       "networkState":0,
+
+       "startOffset":null, //if serving an ogg_chop segment use this to offset the presentation time 
+
+       //custom attributes for mv_embed:
+       "play_button":true,     
+       "thumbnail":null,
+       "linkback":null,
+       "embed_link":true,
+       "download_link":true,
+       "type":null      //the content type of the media 
+};
+/*
+ * the base source attibute checks
+ */
+var mv_default_source_attr= new Array(
+       'id',
+       'src',
+       'title',
+       'URLTimeEncoding', //boolean if we support temporal url requests on the source media
+       'startOffset',
+       'durationHint',
+       'start',
+       'end',  
+       'default',
+       'lang'
+);
+/*
+* Converts all occurrences of <video> tag into video object
+*/
+function mv_video_embed(swap_done_callback, force_id){
+       mvEmbed.init( swap_done_callback, force_id );
+}
+mvEmbed = {    
+       flist:new Array(),
+       init:function( swap_done_callback, force_id ){
+               if(swap_done_callback)
+                       mvEmbed.flist.push( swap_done_callback );
+               //get mv_embed location if it has not been set
+               js_log('mv_embed ' + MV_EMBED_VERSION);                         
+               
+               var loadPlaylistLib=false;
+               //set up the jQuery selector:                            
+               
+               var eAction = function(this_elm){
+                       js_log( "Do SWAP: " + $j(this_elm).attr("id") + ' tag: '+ this_elm.tagName.toLowerCase() );
+                                       
+                       if( $j(this_elm).attr("id") == '' ){
+                               $j(this_elm).attr("id", 'v'+ global_player_list.length);
+                       }                       
+                       //stre a global reference to the id     
+                  global_player_list.push( $j(this_elm).attr("id") );
+                  //if video doSwap
+                  switch( this_elm.tagName.toLowerCase()){
+                          case 'video':
+                                   var videoInterface = new embedVideo(this_elm);       
+                                       mvEmbed.swapEmbedVideoElement( this_elm, videoInterface );
+                          break;
+                          case 'audio':
+                                  var videoInterface = new embedVideo(this_elm);        
+                                  videoInterface.type ='audio';
+                                  mvEmbed.swapEmbedVideoElement( this_elm, videoInterface );
+                          break;
+                          case 'playlist':
+                                  loadPlaylistLib=true;
+                          break;
+                  }            
+               }
+               
+               if( force_id == null && force_id != '' ){
+                       var j_selector = 'video,audio,playlist';                                
+               }else{
+                       var j_selector = '#'+force_id;
+               }
+               //process selected elements: 
+               //ie8 does not play well with the jQuery video,audio,playlist selector use native: 
+               if($j.browser.msie && $j.browser.version >= 8){
+                       jtags = j_selector.split(',');                          
+                       for(var i=0;i<jtags.length;i++){                                
+                               $j( document.getElementsByTagName( jtags[i] )).each(function(){
+                                       eAction(this);
+                               });
+                       }                               
+               }else{                  
+                       $j( j_selector ).each(function(){
+                               eAction(this);
+                       });     
+               }                               
+               if(loadPlaylistLib){            
+                       mvJsLoader.doLoad([ 
+                               'mvPlayList',
+                               '$j.ui',        //include dialog for pop-ing up thigns
+                               '$j.ui.dialog'  
+                       ], function(){
+                               $j('playlist').each(function(){                                                                                                                                                                                                                                                                 
+                                       //create new playlist interface:
+                                       var plObj = new mvPlayList( this );
+                                       mvEmbed.swapEmbedVideoElement(this, plObj);
+                                       var added_height = plObj.pl_layout.title_bar_height + plObj.pl_layout.control_height;
+                                       //move into a blocking display container with height + controls + title height: 
+                                       $j('#'+plObj.id).wrap('<div style="display:block;height:' + (plObj.height + added_height) + 'px;"></div>');                                                                             
+                               });
+                       });
+               }          
+               this.checkClipsReady();
+       },
+       /*
+       * swapEmbedVideoElement
+       * takes a video element as input and swaps it out with
+       * an embed video interface based on the video_elements attributes
+       */
+       swapEmbedVideoElement:function(video_element, videoInterface){
+               js_log('do swap ' + videoInterface.id + ' for ' + video_element);
+               embed_video = document.createElement('div');
+               //make sure our div has a hight/width set:
+                       
+               $j(embed_video).css({
+                       'width':videoInterface.width,
+                       'height':videoInterface.height
+               }).html( mv_get_loading_img() );                
+               //inherit the video interface
+               for(var method in videoInterface){ //for in loop oky in Element context 
+                       if(method!='readyState'){ //readyState crashes IE
+                               if(method=='style'){
+                                               embed_video.setAttribute('style', videoInterface[method]);
+                               }else if(method=='class'){
+                                       if( $j.browser.msie )
+                                               embed_video.setAttribute("className", videoInterface['class']);
+                                       else
+                                               embed_video.setAttribute("class", videoInterface['class']);
+                               }else{
+                                       //normal inherit:
+                                       embed_video[method]=videoInterface[method];
+                               }
+                       }
+                       //string -> boolean:
+                       if(embed_video[method]=="false")embed_video[method]=false;
+                       if(embed_video[method]=="true")embed_video[method]=true;
+               }       
+               ///js_log('did vI style');  
+               //now swap out the video element for the embed_video obj:         
+                 $j(video_element).after(embed_video).remove();        
+                 //js_log('did swap');           
+                 $j('#'+embed_video.id).get(0).on_dom_swap();            
+               // now that "embed_video" is stable, do more initialization (if we are ready)
+               if($j('#'+embed_video.id).get(0).loading_external_data==false && 
+                          $j('#'+embed_video.id).get(0).init_with_sources_loadedDone==false){
+                       //load and set ready state since source are available: 
+                       $j('#'+embed_video.id).get(0).init_with_sources_loaded();
+               }   
+               js_log('done with child: ' + embed_video.id + ' len:' + global_player_list.length);
+               return true;
+       },
+       //this should not be needed.
+       checkClipsReady : function(){
+               //js_log('checkClipsReady');
+               var is_ready=true;        
+                 for(var i=0; i < global_player_list.length; i++){
+                         if( $j('#'+global_player_list[i]).length !=0){
+                                 var cur_vid =  $j('#'+global_player_list[i]).get(0);            
+                               is_ready = ( cur_vid.ready_to_play ) ? is_ready : false;
+                               if( !is_ready && cur_vid.load_error ){ 
+                                       is_ready=true;
+                                       $j(cur_vid).html( cur_vid.load_error );
+                               }
+                       }
+               }
+               if( is_ready ){
+                       mvEmbed.allClipsReady = true;
+                       // run queued functions 
+                       //js_log('run queded functions:' + mvEmbed.flist[0]);
+                       mvEmbed.runFlist();
+               }else{                           
+                        setTimeout( 'mvEmbed.checkClipsReady()', 25 );
+                }                        
+       },
+       runFlist:function(){
+               while (this.flist.length){                              
+                       this.flist.shift()();
+               }
+       }
+}
+
+/* 
+ * controlsBuilder:
+ * 
+ */
+var ctrlBuilder = {
+       height:29,
+       supports:{
+                 'options':true,                                
+                 'borders':true                           
+       },
+       getControls:function( embedObj ){       
+               js_log('f:controlsBuilder:: opt:' + this.options);              
+               this.id = (embedObj.pc)?embedObj.pc.pp.id:embedObj.id;
+               this.avaliable_width=embedObj.playerPixelWidth();
+               //make pointer to the embedObj
+               this.embedObj =embedObj;
+               var _this = this;               
+               $j.each( embedObj.supports, function( i, sup ){
+                       _this.supports[i] = embedObj.supports[i];
+               });
+                                       
+               //special case vars: 
+               if( ( embedObj.roe || embedObj.media_element.timedTextSources() )  
+                               && embedObj.show_meta_link  )
+                       this.supports['closed_captions']=true;   
+               
+                       
+               //append options to body (if not already there)
+               if($j('#mv_vid_options_'+ctrlBuilder.id).length==0)
+                       $j('body').append( this.components['mv_embedded_options'].o() );                
+                                       
+               var o='';       
+               for( var i in this.components ){
+                       if( this.supports[i] ){
+                               if( this.avaliable_width > this.components[i].w ){
+                                       //special case with playhead don't add unless we have 60px
+                                       if( i=='play_head' && ctrlBuilder.avaliable_width < 60 )
+                                               continue;                                               
+                                       o+=this.components[i].o();
+                                       this.avaliable_width -= this.components[i].w;
+                               }else{
+                                       js_log('not enough space for control component:'+i);
+                               }
+                       }
+               }               
+               return o;
+       },
+        /*
+        * addControlHooks
+        * to be run once controls are attached to the dom
+        */
+       addControlHooks:function(embedObj){                                                             
+               //add in drag/seek hooks: 
+               if(!embedObj.base_seeker_slider_offset &&  $j('#mv_seeker_slider_'+embedObj.id).get(0))
+                       embedObj.base_seeker_slider_offset = $j('#mv_seeker_slider_'+embedObj.id).get(0).offsetLeft;                      
+               
+               //js_log('looking for: #mv_seeker_slider_'+embedObj.id + "\n " +
+               //              'start sec: '+embedObj.start_time_sec + ' base offset: '+embedObj.base_seeker_slider_offset);
+               
+               //add play hook: 
+               $j('#mv_play_pause_button_' + embedObj.id).unbind().btnBind().click(function(){
+                       $j('#' + embedObj.id).get(0).play();
+               })      
+               
+               //big_play_link_ play binding: 
+               $j('#big_play_link_' + embedObj.id).unbind().click(function(){
+                       $j('#' + embedObj.id).get(0).play();
+               });             
+               
+               //add recomend firefox if non-native playback:
+               if( embedObj.doNativeWarningCheck() ){                                                                                                                  
+                       $j('#dc_'+ embedObj.id).hover(
+                               function(){                                                                             
+                                       if($j('#gnp_' + embedObj.id).length==0){
+                                               $j(this).append('<div id="gnp_' + embedObj.id + '" class="ui-state-highlight ui-corner-all" ' +
+                                                       'style="position:absolute;display:none;background:#FFF;top:10px;left:10px;right:10px;height:60px;">' +
+                                                       gM('mv_for_best_experience') + 
+                                               '<br><input id="ffwarn_'+embedObj.id+'" type=\"checkbox\">' + 
+                                                       gM('mv_do_not_warn_again') + 
+                                               '</div>');                                                      
+                                               $j('#ffwarn_'+embedObj.id).click(function(){
+                                                       if( $j(this).checked ){
+                                                               $j.cookie('dismissNativeWarn', true);
+                                                       }else{
+                                                               $j.cookie('dismissNativeWarn', false);
+                                                       }
+                                                       
+                                               });     
+                                       }
+                                       if( $j.cookie('dismissNativeWarn')!== true){
+                                               $j('#gnp_' + embedObj.id).fadeIn('slow');
+                                       }
+                               },
+                               function(){
+                                       $j('#gnp_' + embedObj.id).fadeOut('slow');
+                               }
+                       );
+               }
+               
+               if( $j.browser.msie  &&  $j.browser.version <= 6){                      
+                       $j('#big_play_link_' + embedObj.id).pngFix();
+               }
+               
+               
+               //captions binding:
+               $j('#timed_text_'  + embedObj.id).unbind().btnBind().click(function(){
+                       $j('#' + embedObj.id).get(0).showTextInterface();
+               });
+               
+               //options binding: 
+               $j('#options_button_' + embedObj.id).unbind().btnBind().click(function(){
+                       $j('#' +embedObj.id).get(0).doOptionsHTML();
+               });
+                               
+               //fullscreen binding: 
+               $j('#fullscreen_'+embedObj.id).unbind().btnBind().click(function(){
+                       $j('#' +embedObj.id).get(0).fullscreen();
+               });                             
+               
+               js_log(" should add slider binding: " + $j('#mv_play_head_'+embedObj.id).length) ;
+               $j('#mv_play_head_'+embedObj.id).slider({
+                       range: "min",
+                       value: 0,
+                       min: 0,
+                       max: 1000,
+                       start: function(event, ui){
+                               var id = (embedObj.pc!=null)?embedObj.pc.pp.id:embedObj.id;
+                               embedObj.userSlide=true;
+                               $j('#big_play_link_'+id).fadeOut('fast');
+                               //if playlist always start at 0
+                               embedObj.start_time_sec = (embedObj.instanceOf == 'mvPlayList')?0:
+                                                               npt2seconds(embedObj.getTimeReq().split('/')[0]);        
+                       },
+                       slide: function(event, ui) {                                                                    
+                               var perc = ui.value/1000;                                                                                                                                                                                                                                                                                       
+                               embedObj.jump_time = seconds2npt( parseFloat( parseFloat(embedObj.getDuration()) * perc ) + embedObj.start_time_sec);   
+                               //js_log('perc:' + perc + ' * ' + embedObj.getDuration() + ' jt:'+  this.jump_time);
+                               embedObj.setStatus( gM('seek_to')+' '+embedObj.jump_time );     
+                               //update the thumbnail / frame 
+                               if(embedObj.isPlaying==false){
+                                       embedObj.updateThumbPerc( perc );
+                               }
+                       },
+                       change:function(event, ui){
+                               //only run the onChange event if done by a user slide: 
+                               if(embedObj.userSlide){
+                                       embedObj.userSlide=false;
+                                       embedObj.seeking=true;
+                                       //stop the monitor timer (if we can)
+                                       if(embedObj.stopMonitor)                                 
+                                               embedObj.stopMonitor();                 
+                                                       
+                                       var perc = ui.value/1000;                                                                                                                 
+                                       //set seek time (in case we have to do a url seek)                              
+                                       embedObj.seek_time_sec = npt2seconds( embedObj.jump_time, true );   
+                                       js_log('do jump to: '+embedObj.jump_time + ' perc:' +perc + ' sts:' + embedObj.seek_time_sec);                                                          
+                                       embedObj.doSeek(perc);
+                               }
+                       }                 
+               });
+               //up the z-index of the default status indicator: 
+               $j('#mv_play_head_'+embedObj.id + ' .ui-slider-handle').css('z-index', 4);
+               $j('#mv_play_head_'+embedObj.id + ' .ui-slider-range').addClass('ui-corner-all').css('z-index', 2);
+               //extended class list for jQuery ui themeing (we can probably refactor this with custom buffering highliter) 
+               $j('#mv_play_head_'+embedObj.id).append( ctrlBuilder.getMvBufferHtml() );
+                               
+               //videoOptions: 
+               $j('#mv_vid_options_'+ctrlBuilder.id+' .vo_selection').click(function(){
+                       embedObj.selectPlaybackMethod();
+                       $j('#mv_vid_options_'+ctrlBuilder.id).hide();
+                       return false;
+               });
+               $j('#mv_vid_options_'+ctrlBuilder.id+' .vo_download').click(function(){
+                       embedObj.showVideoDownload();
+                       $j('#mv_vid_options_'+ctrlBuilder.id).hide();
+                       return false;
+               })              
+               $j('#mv_vid_options_'+ctrlBuilder.id+' .vo_showcode').click(function(){
+                       embedObj.showEmbedCode();
+                       $j('#mv_vid_options_'+ctrlBuilder.id).hide();
+                       return false;
+               });             
+                       
+               //volume binding:
+               var hoverOverDelay=false;
+               $j('#volume_control_'+embedObj.id).unbind().btnBind().click(function(){
+                       $j('#' +embedObj.id).get(0).toggleMute();
+               }).hover(
+                       function(){                     
+                               $j('#vol_container_' + embedObj.id).addClass('vol_container_top');
+                               //set to "below" if playing and embedType != native
+                               if(embedObj.isPlaying() && !embedObj.supports['overlays']){
+                                       $j('#vol_container_' + embedObj.id).removeClass('vol_container_top').addClass('vol_container_below');
+                               }
+                               
+                               $j('#vol_container_' + embedObj.id).fadeIn('fast');
+                               hoverOverDelay = true;
+                       },
+                       function(){             
+                               hoverOverDelay= false;          
+                               setTimeout(function doHideVolume(){
+                                       if(!hoverOverDelay){
+                                               $j('#vol_container_' + embedObj.id).fadeOut('fast');
+                                       }
+                               }, 500);        
+                       }
+               );
+               //Volumen Slider
+               $j('#volume_bar_'+embedObj.id).slider({
+                       orientation: "vertical",                        
+                       range: "min",
+                       value: 80,
+                       min: 0,
+                       max: 100,                       
+                       slide: function(event, ui) {                                                                    
+                               var perc = ui.value/100;                
+                               //js_log('update volume:' + perc);
+                               embedObj.updateVolumen(perc);                                                           
+                       },
+                       change:function(event, ui){
+                               var perc = ui.value/100;        
+                               if (perc==0) {
+                                       $j('#volume_control_'+embedObj.id + ' span').removeClass('ui-icon-volume-on').addClass('ui-icon-volume-off');                                                           
+                               }else{                                  
+                                       $j('#volume_control_'+embedObj.id + ' span').removeClass('ui-icon-volume-off').addClass('ui-icon-volume-on');
+                               }
+                               //only run the onChange event if done by a user slide: 
+                               if(embedObj.userSlide){
+                                       embedObj.userSlide=false;
+                                       embedObj.seeking=true;                                                  
+                                       var perc = ui.value/100;                                                                                                                  
+                                       embedObj.updateVolumen(perc);                                   
+                               }
+                       }                 
+               });                                     
+               
+       },      
+       getMvBufferHtml:function(){
+               return '<div class="ui-slider-range ui-slider-range-min ui-widget-header ' +
+                               'ui-state-highlight ui-corner-all '+
+                               'mv_buffer" style="width:0px;height:100%;z-index:1;top:0px" />';
+       },
+       components:{
+               'borders':{
+                       'w':8,
+                       'o':function(){
+                               return  '';
+                       }
+               },
+               'mv_embedded_options':{
+                       'w':0,
+                       'o':function(){
+                               var o= '<div id="mv_vid_options_'+ctrlBuilder.id+'" class="videoOptions">'+
+                               '<div class="videoOptionsTop"></div>'+
+                               '<div class="videoOptionsBox">'+
+                               '<div class="block">'+
+                                       '<h6>Video Options</h6>'+
+                               '</div>'+
+                                       '<div class="block">'+
+                                               '<p class="short_match vo_selection"><a href="#"><span>Stream Selection</span></a></p>'+
+                                               '<p class="short_match vo_download"><a href="#"><span>Download</span></a></p>'+
+                                               '<p class="short_match vo_showcode"><a href="#"><span>Share or Embed</span></a></p>';
+                                       
+                                       //link to the stream page if we are not already there: 
+                                       if( ctrlBuilder.embedObj.roe && typeof mv_stream_interface == 'undefined' )
+                                               o+='<p class="short_match"><a href="javascript:$j(\'#'+ctrlBuilder.id+'\').get(0).doLinkBack()"><span><strong>Source Page</strong></span></a></p>';
+                                                                                       
+                               o+='</div>'+  
+                               '</div><!--videoOptionsInner-->' +   
+                                       '<div class="videoOptionsBot"></div>' +   
+                               '</div><!--videoOptions-->';
+                               return o;
+                       }
+               },
+               'fullscreen':{
+                       'w':20,
+                       'o':function(){
+                               return '<div title="' + gM('player_fullscreen') + '" id="fullscreen_'+ctrlBuilder.id+'" class="ui-state-default ui-corner-all ui-icon_link rButton"><span class="ui-icon ui-icon-arrow-4-diag"></span></div>'
+                       }
+               },
+               'options':{
+                       'w':26,
+                       'o':function(){
+                               return '<div title="'+ gM('player_options') + '" id="options_button_'+ctrlBuilder.id+'" class="ui-state-default ui-corner-all ui-icon_link rButton"><span class="ui-icon ui-icon-wrench"></span></div>';                                                 
+                       }
+               },
+               'pause':{
+                       'w':24,
+                       'o':function(){
+                               return '<div title="' + gM('play_clip') + '" id="mv_play_pause_button_' + ctrlBuilder.id + '" class="ui-state-default ui-corner-all ui-icon_link lButton"><span class="ui-icon ui-icon-play"/></div>';
+                       }
+               },
+               'closed_captions':{
+                       'w':23,
+                       'o':function(){
+                               return '<div title="' + gM('closed_captions') + '" id="timed_text_'+ctrlBuilder.id+'" class="ui-state-default ui-corner-all ui-icon_link rButton"><span class="ui-icon ui-icon-comment"></span></div>'
+                       }                       
+               },
+               'volume_control':{
+                       'w':23,
+                       'o':function(){
+                                       return '<div title="' + gM('volume_control') + '" id="volume_control_'+ctrlBuilder.id+'" class="ui-state-default ui-corner-all ui-icon_link rButton">' +
+                                                               '<span class="ui-icon ui-icon-volume-on"></span>' +
+                                                               '<div style="position:absolute;display:none;" id="vol_container_'+ctrlBuilder.id+'" class="vol_container ui-corner-all">' +
+                                                                       '<div class="volume_bar" id="volume_bar_' + ctrlBuilder.id + '"></div>' +
+                                                               '</div>'+
+                                                       '</div>';                                                                                                               
+                       }
+               },
+               'time_display':{
+                       'w':90,
+                       'o':function(){
+                               return '<div id="mv_time_'+ctrlBuilder.id+'" class="ui-widget time">' + ctrlBuilder.embedObj.getTimeReq() + '</div>';
+                       }
+               },
+               'play_head':{
+                       'w':0, //special case (takes up remaining space) 
+                       'o':function(){
+                               return '<div class="play_head" id="mv_play_head_'+ctrlBuilder.id+'" style="width: ' + (ctrlBuilder.avaliable_width - 30) + 'px;"></div>';
+                       }
+               }                                                                               
+       }       
+}
+
+/**
+  * mediaSource class represents a source for a media element.
+  * @param {String} type MIME type of the source.
+  * @param {String} uri URI of the source.
+  * @constructor
+  */
+function mediaSource(element)
+{
+       this.init(element);
+}
+
+
+mediaSource.prototype =
+{
+       /** MIME type of the source. */
+       mime_type:null,
+       /** URI of the source. */
+       uri:null,
+       /** Title of the source. */
+       title:null,
+       /** True if the source has been marked as the default. */
+       marked_default:false,
+       /** True if the source supports url specification of offset and duration */
+       URLTimeEncoding:false,
+       /** Start offset of the requested segment */
+       start_offset:null,
+       /** Duration of the requested segment (0 if not known) */
+       duration:0,
+       is_playable:null,
+       upddate_interval:null,
+
+       id:null,
+       start_ntp:null,
+       end_ntp:null,
+
+       init : function(element)
+       {
+               //js_log('adding mediaSource: ' + element);                             
+               this.src = $j(element).attr('src');
+               this.marked_default = false;
+               if ( element.tagName.toLowerCase() == 'video')
+                       this.marked_default = true;             
+               
+               //set default URLTimeEncoding if we have a time  url:
+               //not ideal way to discover if content is on an oggz_chop server. 
+               //should check some other way. 
+               var pUrl = parseUri ( this.src );
+               if(typeof pUrl['queryKey']['t'] != 'undefined'){
+                       this['URLTimeEncoding']=true;                   
+               }                               
+               for(var i=0; i < mv_default_source_attr.length; i++){ //array loop:
+                       var attr = mv_default_source_attr[ i ];                 
+                       if( $j(element).attr( attr ) ) {
+                               this[ attr ] =  $j(element).attr( attr );
+                       }
+               }                               
+               //update duration from hit if present: 
+               if(this.durationHint)
+                       this.duration = this.durationHint;
+                       
+               if ( $j(element).attr('type'))
+                       this.mime_type = $j(element).attr('type');
+               else if ($j(element).attr('content-type'))
+                       this.mime_type = $j(element).attr('content-type');
+               else                    
+                       this.mime_type = this.detectType(this.src);
+               
+               //set the title if unset:
+               if( !this.title )
+                       this.title = this.mime_type;
+
+               this.parseURLDuration();
+       },
+       updateSource:function(element){
+               //for now just update the title: 
+               if ($j(element).attr("title"))
+                       this.title = $j(element).attr("title");         
+       },
+       /** updates the src time and start & end
+        *  @param {String} start_time in NTP format
+        *  @param {String} end_time in NTP format
+        */
+       updateSrcTime:function (start_ntp, end_ntp){
+               //js_log("f:updateSrcTime: "+ start_ntp+'/'+ end_ntp + ' from org: ' + this.start_ntp+ '/'+this.end_ntp);
+               //js_log("pre uri:" + this.src);
+               //if we have time we can use:
+               if( this.URLTimeEncoding ){
+                       //make sure its a valid start time / end time (else set default) 
+                       if( !npt2seconds(start_ntp) ) 
+                               start_ntp = this.start_ntp;
+                               
+                       if( !npt2seconds(end_ntp) )
+                               end_ntp = this.end_ntp;
+                                                                                 
+                       this.src = getURLParamReplace(this.src, { 't': start_ntp +'/'+ end_ntp } );                
+                       
+                       //update the duration
+                       this.parseURLDuration();
+               }                
+       },
+       setDuration:function (duration)
+       {
+               this.duration = duration;
+               if(!this.end_ntp){
+                       this.end_ntp = seconds2npt( this.start_offset + duration);
+               }
+       },
+       /** MIME type accessor function.
+               @return the MIME type of the source.
+               @type String
+       */
+       getMIMEType : function()
+       {
+               return this.mime_type;
+       },
+       /** URI accessor function.
+        *       @param int seek_time_sec (used to adjust the URI for url based seeks) 
+               @return the URI of the source.
+               @type String
+       */
+       getURI : function( seek_time_sec )
+       {                               
+          if( !seek_time_sec || !this.URLTimeEncoding ){                       
+                          return this.src;                                               
+          }                            
+          if(!this.end_ntp){
+                 var endvar = '';
+          }else{
+                 var endvar = '/'+ this.end_ntp;
+          }            
+          return getURLParamReplace(this.src,  { 't': seconds2npt( seek_time_sec )+endvar } ); ;
+       },
+       /** Title accessor function.
+               @return the title of the source.
+               @type String
+       */
+       getTitle : function()
+       {
+               return this.title;
+       },
+       /** Index accessor function.
+               @return the source's index within the enclosing mediaElement container.
+               @type Integer
+       */
+       getIndex : function()
+       {
+               return this.index;
+       },
+       /*
+        * function getDuration in milliseconds
+        * special case derive duration from request url
+        * supports media_url?t=ntp_start/ntp_end url request format
+        */
+       parseURLDuration : function(){                    
+               //check if we have a URLTimeEncoding: 
+               if( this.URLTimeEncoding ){               
+                       var annoURL = parseUri( this.src );
+                       if( annoURL.queryKey['t'] ){
+                               var times = annoURL.queryKey['t'].split('/');
+                               this.start_ntp = times[0];
+                               this.end_ntp = times[1];
+                               this.start_offset = npt2seconds( this.start_ntp );
+                               this.duration = npt2seconds( this.end_ntp ) - this.start_offset;
+                       }else{
+                               //look for this info as attributes
+                               if(this.startOffset){
+                                       this.start_offset = this.startOffset;
+                                       this.start_ntp = seconds2npt( this.startOffset);                                        
+                               } 
+                               if(this.duration){
+                                       this.end_ntp = seconds2npt( parseInt(this.duration) + parseInt(this.start_offset) );
+                               }                               
+                       }                                               
+               }
+               //else nothing to parse just keep whatever info we already have
+               
+               //js_log('f:parseURLDuration() for:' + this.src  + ' d:' + this.duration);
+       },
+       /** Attempts to detect the type of a media file based on the URI.
+               @param {String} uri URI of the media file.
+               @returns The guessed MIME type of the file.
+               @type String
+       */
+       detectType:function(uri)
+       {
+               //@@todo if media is on the same server as the javascript or we have mv_proxy configured
+               //we can issue a HEAD request and read the mime type of the media...
+               // (this will detect media mime type independently of the url name)
+               //http://www.jibbering.com/2002/4/httprequest.html (this should be done by extending jquery's ajax objects)
+               var end_inx =  (uri.indexOf('?')!=-1)? uri.indexOf('?') : uri.length;
+               var no_param_uri = uri.substr(0, end_inx);
+               switch( no_param_uri.substr(no_param_uri.lastIndexOf('.'),4).toLowerCase() ){
+                       case '.flv':return 'video/x-flv';break;
+                       case '.ogg': case '.ogv': return 'video/ogg';break;
+                       case '.oga': return 'audio/ogg'; break;
+                       case '.anx':return 'video/ogg';break;
+               }
+       }
+};
+
+/** A media element corresponding to a <video> element.
+       It is implemented as a collection of mediaSource objects.  The media sources
+       will be initialized from the <video> element, its child <source> elements,
+       and/or the ROE file referenced by the <video> element.
+       @param {element} video_element <video> element used for initialization.
+       @constructor
+*/
+function mediaElement(video_element)
+{
+       this.init(video_element);
+};
+
+mediaElement.prototype =
+{
+       /** The array of mediaSource elements. */
+       sources:null,   
+       addedROEData:false,     
+       /** Selected mediaSource element. */
+       selected_source:null,
+       thumbnail:null,
+       linkback:null,  
+
+       /** @private */
+       init:function( video_element )
+       {
+               var _this = this;
+               js_log('Initializing mediaElement...' );
+               this.sources = new Array();
+               this.thumbnail = mv_default_thumb_url;
+               // Process the source element:
+               if($j(video_element).attr("src"))
+                       this.tryAddSource(video_element);                         
+               
+               if($j(video_element).attr('thumbnail'))
+                       this.thumbnail=$j(video_element).attr('thumbnail');
+                       
+               if($j(video_element).attr('poster'))
+                       this.thumbnail=$j(video_element).attr('poster');
+                       
+               // Process all inner <source> elements  
+               //js_log("inner source count: " + video_element.getElementsByTagName('source').length );
+               
+               $j(video_element).find('source,text').each(function(inx, inner_source){                 
+                       _this.tryAddSource( inner_source );
+               });                                               
+       },
+       /** Updates the time request for all sources that have a standard time request argument (ie &t=start_time/end_time)
+        */
+       updateSourceTimes:function(start_ntp, end_ntp){
+               var _this = this;
+               $j.each(this.sources, function(inx, mediaSource){
+                       mediaSource.updateSrcTime(start_ntp, end_ntp);
+               });
+       },
+       /*timed Text check*/
+       timedTextSources:function(){
+               for(var i=0; i < this.sources.length; i++){                     
+                       if(     this.sources[i].mime_type == 'text/cmml' ||
+                               this.sources[i].mime_type == 'text/x-srt')
+                                       return true;                                                            
+               };
+               return false;
+       },
+       /** Returns the array of mediaSources of this element.
+               \returns {Array} Array of mediaSource elements.
+       */
+       getSources:function( mime_filter )
+       {
+               if(!mime_filter)
+                       return this.sources;
+               //apply mime filter: 
+                  var source_set = new Array();
+               for(var i=0; i < this.sources.length ; i++){
+                       if( this.sources[i].mime_type.indexOf( mime_filter ) != -1 )
+                               source_set.push( this.sources[i] );
+               }
+               return source_set;
+       },
+       getSourceById:function( source_id ){            
+               for(var i=0; i < this.sources.length ; i++){
+                       if( this.sources[i].id ==  source_id)
+                               return this.sources[i];
+               }
+               return null;
+       },
+       /** Selects a particular source for playback.
+       */
+       selectSource:function(index)
+       {
+               js_log('f:selectSource:'+index);
+               var playable_sources = this.getPlayableSources();
+               for(var i=0; i < playable_sources.length; i++){
+                       if( i==index ){
+                               this.selected_source = playable_sources[i];
+                               //update the user selected format: 
+                               embedTypes.players.userSelectFormat( playable_sources[i].mime_type );
+                               break;
+                       }
+               }               
+       },
+       /** selects the default source via cookie preference, default marked, or by id order
+        * */
+       autoSelectSource:function(){ 
+               js_log('f:autoSelectSource:');  
+               //@@todo read user preference for source                
+               // Select the default source
+               var playable_sources = this.getPlayableSources();                                                       
+               var flash_flag=ogg_flag=false;            
+               //debugger;
+               for(var source=0; source < playable_sources.length; source++){
+                       var mime_type =playable_sources[source].mime_type;
+                       if( playable_sources[source].marked_default ){
+                               js_log('set via marked default: ' + playable_sources[source].marked_default);
+                               this.selected_source = playable_sources[source];                                
+                               return true;
+                       }
+                       //set via user-preference
+                       if(embedTypes.players.preference['format_prefrence'] == mime_type){
+                                js_log('set via preference: '+playable_sources[source].mime_type);
+                                this.selected_source = playable_sources[source];
+                                return true; 
+                       }                                                                                                                       
+               }          
+               //set Ogg via player support            
+               for(var source=0; source < playable_sources.length; source++){
+                       js_log('f:autoSelectSource:' + playable_sources[source].mime_type);
+                       var mime_type =playable_sources[source].mime_type;                                      
+                          //set source via player                               
+                       if(mime_type=='video/ogg' || mime_type=='ogg/video' || mime_type=='video/annodex' || mime_type=='application/ogg'){                             
+                               for(var i=0; i < embedTypes.players.players.length; i++){ //for in loop on object oky
+                                       var player = embedTypes.players.players[i];                                     
+                                       if(player.library=='vlc' || player.library=='native'){
+                                               js_log('set via ogg via order');                                                
+                                               this.selected_source = playable_sources[source];        
+                                               return true;
+                                       }                                       
+                               }
+                       }
+               }
+               //set basic flash
+               for(var source=0; source < playable_sources.length; source++){  
+                       var mime_type =playable_sources[source].mime_type;                                                                              
+                       if( mime_type=='video/x-flv' ){
+                               js_log('set via by player preference normal flash')
+                               this.selected_source = playable_sources[source];
+                               return true;
+                       }                                               
+               }
+               //set h264 flash 
+               for(var source=0; source < playable_sources.length; source++){  
+                       var mime_type =playable_sources[source].mime_type;                                                                              
+                       if( mime_type=='video/h264' ){
+                               js_log('set via playable_sources preference h264 flash')
+                               this.selected_source = playable_sources[source];
+                               return true;
+                       }                          
+               }               
+               //select first source           
+               if (!this.selected_source)
+               {
+                       js_log('set via first source:' + playable_sources[0]);
+                       this.selected_source = playable_sources[0];
+                       return true;
+               }
+       },
+       /** Returns the thumbnail URL for the media element.
+               \returns {String} thumbnail URL
+       */
+       getThumbnailURL:function()
+       {
+               return this.thumbnail;
+       },
+       /** Checks whether there is a stream of a specified MIME type.
+               @param {String} mime_type MIME type to check.
+               @type {BooleanPrimitive}.
+       */
+       hasStreamOfMIMEType:function(mime_type)
+       {
+               for(source in this.sources)
+               {
+                       if(this.sources[source].getMIMEType() == mime_type)
+                               return true;
+               }
+               return false;
+       },
+       isPlayableType:function(mime_type)
+       {
+               if( embedTypes.players.defaultPlayer( mime_type ) ){
+                       return true;
+               }else{
+                       return false;
+               }
+               //if(this.selected_player){
+               //return mime_type=='video/ogg' || mime_type=='ogg/video' || mime_type=='video/annodex' || mime_type=='video/x-flv';
+       },
+       /** Adds a single mediaSource using the provided element if
+               the element has a 'src' attribute.              
+               @param element {element} <video>, <source> or <mediaSource> element.
+       */
+       tryAddSource:function(element)
+       {
+               js_log('f:tryAddSource:'+ $j(element).attr("src"));             
+               if (! $j(element).attr("src")){
+                       //js_log("element has no src");
+                       return false;
+               }
+               var new_src = $j(element).attr('src');
+               //make sure an existing element with the same src does not already exist:                
+               for( var i=0; i < this.sources.length; i++ ){                           
+                       if(this.sources[i].src == new_src){
+                               //js_log('checking existing: '+this.sources[i].getURI() + ' != '+ new_src);      
+                               //can't add it all but try to update any additional attr: 
+                               this.sources[i].updateSource(element);
+                               return false;
+                       }
+               }
+               var source = new mediaSource( element );                
+               this.sources.push(source);              
+               //alert('pushed source to stack'+ source + 'sl:'+this.sources.length);
+       },
+       getPlayableSources: function(){          
+                var playable_sources= new Array();
+                for(var i=0; i < this.sources.length; i++){                                                               
+                        if( this.isPlayableType( this.sources[i].mime_type ) ){                                 
+                                playable_sources.push( this.sources[i] );
+                        }else{
+                                js_log("type "+ this.sources[i].mime_type + 'is not playable');
+                        }
+                };              
+                return playable_sources;
+       },
+       /* Imports media sources from ROE data.
+        *   @param roe_data ROE data.
+       */
+       addROE:function(roe_data){              
+               js_log('f:addROE');
+               this.addedROEData=true;
+               var _this = this;               
+               if( typeof roe_data == 'string' )
+               {
+                       var parser=new DOMParser();
+                       js_log('ROE data:' + roe_data);
+                       roe_data=parser.parseFromString(roe_data,"text/xml");
+               }
+               if( roe_data ){
+                       $j.each(roe_data.getElementsByTagName('mediaSource'), function(inx, source){
+                               _this.tryAddSource(source);
+                       });
+                       //set the thumbnail:
+                       $j.each(roe_data.getElementsByTagName('img'), function(inx, n){
+                               if($j(n).attr("id")=="stream_thumb"){
+                                       js_log('roe:set thumb to '+$j(n).attr("src"));
+                                       _this['thumbnail'] =$j(n).attr("src");
+                               }
+                       });
+                       //set the linkback:
+                       $j.each(roe_data.getElementsByTagName('link'), function(inx, n){
+                               if($j(n).attr('id')=='html_linkback'){
+                                       js_log('roe:set linkback to '+$j(n).attr("href"));
+                                       _this['linkback'] = $j(n).attr('href');
+                               }
+                       });
+               }else{
+                       js_log('ROE data empty.');
+               }                               
+       }
+};
+
+
+/** base embedVideo object
+       @param element <video> tag used for initialization.
+       @constructor
+*/
+var embedVideo = function(element) {
+       return this.init(element);
+};
+
+embedVideo.prototype = {
+       /** The mediaElement object containing all mediaSource objects */
+       media_element:null,
+       preview_mode:false,                
+       ready_to_play:false, //should use html5 ready state
+       load_error:false, //used to set error in case of error
+       loading_external_data:false,
+       thumbnail_updating:false,
+       thumbnail_disp:true,
+       init_with_sources_loadedDone:false,
+       inDOM:false,
+       //for onClip done stuff: 
+       anno_data_cache:null,
+       seek_time_sec:0,
+       base_seeker_slider_offset:null,
+       onClipDone_disp:false,
+       supports:{},    
+       //for seek thumb updates:
+       cur_thumb_seek_time:0,
+       thumb_seek_interval:null,
+       
+       seeking:false,
+       //set the buffered percent:     
+       bufferedPercent:0,      
+       //utility functions for property values:
+       hx : function ( s ) {
+               if ( typeof s != 'String' ) {
+                       s = s.toString();
+               }
+               return s.replace( /&/g, '&amp;' )
+                       . replace( /</g, '&lt;' )
+                       . replace( />/g, '&gt;' );
+       },
+       hq : function ( s ) {
+               return '"' + this.hx( s ) + '"';
+       },
+       playerPixelWidth : function()
+       {
+               var player = $j('#mv_embedded_player_'+this.id).get(0);
+               if(typeof player!='undefined' && player['offsetWidth'])
+                       return player.offsetWidth;
+               else
+                       return parseInt(this.width);
+       },
+       playerPixelHeight : function()
+       {
+               var player = $j('#mv_embedded_player_'+this.id).get(0);
+               if(typeof player!='undefined' && player['offsetHeight'])
+                       return player.offsetHeight;
+               else
+                       return parseInt(this.height);
+       },
+       init: function(element){                
+               //this.element_pointer = element;
+
+               //inherit all the default video_attributes
+               for(var attr in default_video_attributes){ //for in loop oky on user object
+                       if(element.getAttribute(attr)){
+                               this[attr]=element.getAttribute(attr);
+                               //js_log('attr:' + attr + ' val: ' + element.getAttribute(attr) +'(set by elm)');
+                       }else{
+                               this[attr]=default_video_attributes[attr];
+                               //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)");
+                       }
+               }
+               //make sure startOffset is cast as an int                  
+               if( this.startOffset && this.startOffset.split(':').length >= 2)
+                       this.startOffset = npt2seconds(this.startOffset);
+               //make sure offset is in float: 
+               this.startOffset = parseFloat(this.startOffset);
+                
+               if( this.duration && this.duration.split(':').length >= 2)
+                       this.duration = npt2seconds( this.duration );    
+                  //make sure duration is in float:  
+               this.duration = parseFloat(this.duration);  
+               js_log("duration is: " +  this.duration);
+               //if style is set override width and height
+               var dwh = mv_default_video_size.split('x');
+               this.width = element.style.width ? element.style.width : dwh[0];
+               this.height = element.style.height ? element.style.height : dwh[1];
+               //set the plugin id
+               this.pid = 'pid_' + this.id;
+
+               //grab any innerHTML and set it to missing_plugin_html
+               //@@todo we should strip source tags instead of checking and skipping
+               if(element.innerHTML!='' && element.getElementsByTagName('source').length==0){
+                       js_log('innerHTML: ' + element.innerHTML);
+                       this.user_missing_plugin_html=element.innerHTML;
+               }                                 
+               // load all of the specified sources
+               this.media_element = new mediaElement(element);                                                  
+       },
+       on_dom_swap: function(){
+               js_log('f:on_dom_swap');                                
+               // Process the provided ROE file... if we don't yet have sources
+               if(this.roe && this.media_element.sources.length==0 ){
+                       js_log('loading external data');
+                       this.loading_external_data=true;
+                       var _this = this;                                       
+                       do_request(this.roe, function(data)
+                       {                                                       
+                               //continue                                         
+                               _this.media_element.addROE( data );                                                                       
+                               js_log('added_roe::' + _this.media_element.sources.length);                                                        
+                                                                                                          
+                               js_log('set loading_external_data=false');       
+                               _this.loading_external_data=false;                                                         
+                               
+                               _this.init_with_sources_loaded();                               
+                       });
+               }
+       },
+       init_with_sources_loaded : function()
+       {       
+               js_log('f:init_with_sources_loaded');
+               //set flag that we have run this function:
+               this.init_with_sources_loadedDone=true;                          
+               //autoseletct the source
+               this.media_element.autoSelectSource();          
+               //auto select player based on prefrence or default order
+               if( !this.media_element.selected_source )
+               {
+                       //check for parent clip: 
+                       if( typeof this.pc != 'undefined' ){                    
+                               js_log('no sources, type:' +this.type + ' check for html');     
+                               //debugger;                     
+                               //do load player if just displaying innerHTML: 
+                               if( this.pc.type == 'text/html' ){
+                                       this.selected_player = embedTypes.players.defaultPlayer( 'text/html' );
+                                       js_log('set selected player:'+ this.selected_player.mime_type); 
+                               }
+                       }
+               }else{          
+                       this.selected_player = embedTypes.players.defaultPlayer( this.media_element.selected_source.mime_type );
+               }                                                 
+               if( this.selected_player ){
+                       js_log('selected ' + this.selected_player.getName());
+                       js_log("PLAYBACK TYPE: "+this.selected_player.library);
+                       this.thumbnail_disp = true;             
+                       this.inheritEmbedObj();            
+               }else{                                                   
+                       //no source's playable
+                       var missing_type ='';
+                       var or ='';  
+                       for( var i=0; i < this.media_element.sources.length; i++){
+                               missing_type+=or + this.media_element.sources[i].mime_type;
+                               or=' or ';
+                       }                       
+                       if( this.pc )
+                               var missing_type = this.pc.type;                                                                                
+                          js_log('no player found for given source type ' + missing_type);
+                          this.load_error= this.getPluginMissingHTML(missing_type);                                                                               
+               }               
+       },
+       inheritEmbedObj:function(){       
+               js_log("inheritEmbedObj:duration is: " +  this.duration);  
+               //@@note: tricky cuz direct overwrite is not so ideal.. since the extended object is already tied to the dom
+               //clear out any non-base embedObj stuff:
+               if(this.instanceOf){
+                       eval('tmpObj = '+this.instanceOf);
+                       for(var i in tmpObj){ //for in loop oky for object  
+                               if(this['parent_'+i]){
+                                       this[i]=this['parent_'+i];
+                               }else{
+                                       this[i]=null;
+                               }
+                       }
+               }                                 
+               //set up the new embedObj
+               js_log('f: inheritEmbedObj: embedding with ' + this.selected_player.library);
+               var _this = this;               
+               this.selected_player.load( function()
+               {
+                        js_log("selected_player::load:duration is: " +  _this.duration);  
+                       //js_log('inheriting '+_this.selected_player.library +'Embed to ' + _this.id + ' ' + $j('#'+_this.id).length);
+                       //var _this = $j('#'+_this.id).get(0);
+                       //js_log( 'type of ' + _this.selected_player.library +'Embed + ' +
+                       //              eval('typeof '+_this.selected_player.library +'Embed')); 
+                       eval('embedObj = ' +_this.selected_player.library +'Embed;');
+                       for(var method in embedObj){ //for in loop oky for object  
+                               //parent method preservation for local overwritten methods
+                               if(_this[method])
+                                       _this['parent_' + method] = _this[method];
+                               _this[method]=embedObj[method];
+                       }
+                       js_log('TYPEOF_ppause: ' + typeof _this['parent_pause']);
+                       
+                       if(_this.inheritEmbedOverride){
+                               _this.inheritEmbedOverride();
+                       }
+                       //update controls if possible
+                       if(!_this.loading_external_data)
+                               _this.refreshControlsHTML();                                                                                            
+                       
+                       //js_log("READY TO PLAY:"+_this.id);                    
+                       _this.ready_to_play=true;                               
+                       _this.getDuration();
+                       _this.getHTML();
+               });
+       },
+       selectPlayer:function(player)
+       {
+               var _this = this;
+               if(this.selected_player.id != player.id){
+                       this.selected_player = player;
+                       this.inheritEmbedObj();
+               }                       
+       },
+       doNativeWarningCheck:function(){                        
+               if( $j.cookie('dismissNativeWarn') && $j.cookie('dismissNativeWarn')===true){
+                       return false;
+               }else{                  
+                       //see if we have native support for ogg: 
+                       var supporting_players = embedTypes.players.getMIMETypePlayers( 'video/ogg' );          
+                       for(var i=0; i < supporting_players.length; i++){
+                               if(supporting_players[i].id == 'videoElement'){
+                                       return false;
+                               }                       
+                       }       
+                       //see if we are using mv_embed without a ogg source in which case no point in promoting firefox :P                      
+                       if(this.media_element && this.media_element.sources){
+                               var foundOgg = false;
+                               var playable_sources = this.media_element.getPlayableSources();
+                               for(var sInx=0; sInx < playable_sources.length; sInx++){  
+                                       var mime_type = playable_sources[sInx].mime_type;
+                                       if( mime_type=='video/ogg' ){
+                                               //they  have flash / h.264 fallback no need to push firefox :( 
+                                               foundOgg = true;
+                                       }
+                               }
+                               //no ogg no point in download firefox
+                               if(!foundOgg)
+                                       return false;
+                                                                               
+                       }
+               }
+               return true;    
+       },
+       getTimeReq:function(){
+               //js_log('f:getTimeReq:'+ this.getDurationNTP());
+               var default_time_req = '0:00:00/' + this.getDurationNTP() ;
+               if(!this.media_element)
+                       return default_time_req;
+               if(!this.media_element.selected_source)
+                       return default_time_req;                
+               if(!this.media_element.selected_source.end_ntp)
+                       return default_time_req;                
+               return this.media_element.selected_source.start_ntp+'/'+this.media_element.selected_source.end_ntp;
+       },      
+       getDuration:function(){                                                 
+               //update some local pointers for the selected source:   
+               if(this.media_element && this.media_element.selected_source && this.media_element.selected_source.duration){                                                                     
+                       this.duration = this.media_element.selected_source.duration;                                            
+                       this.start_offset = this.media_element.selected_source.start_offset;
+                       this.start_ntp = this.media_element.selected_source.start_ntp;
+                       this.end_ntp = this.media_element.selected_source.end_ntp;                                      
+               }
+               //update start end_ntp if duration !=0 (set from plugin) 
+               if(!this.start_ntp)
+                       this.start_ntp = '0:0:0';
+               if(!this.end_ntp && this.duration)
+                       this.end_ntp = seconds2npt( this.duration );            
+               //return the duration
+               return this.duration;
+       },
+         /* get the duration in ntp format */
+       getDurationNTP:function(){
+               return seconds2npt(this.getDuration());
+       },
+       /*
+        * wrapEmebedContainer
+        * wraps the embed code into a container to better support playlist function
+        *  (where embed element is swapped for next clip
+        *  (where plugin method does not support playlsits) 
+        */
+       wrapEmebedContainer:function(embed_code){
+               //check if parent clip is set( ie we are in a playlist so name the embed container by playlistID)
+               var id = (this.pc!=null)?this.pc.pp.id:this.id;
+               return '<div id="mv_ebct_'+id+'" style="width:'+this.width+'px;height:'+this.height+'px;">' + 
+                                       embed_code + 
+                               '</div>';
+       },      
+       getEmbedHTML : function(){
+               //return this.wrapEmebedContainer( this.getEmbedObj() );
+               return 'function getEmbedHTML should be overitten by embedLib ';
+       },
+       //do seek function (should be overwritten by implementing embedLibs)
+       // first check if seek can be done on locally downloaded content. 
+       doSeek : function( perc ){              
+               if( this.supportsURLTimeEncoding() ){                   
+                       //make sure this.seek_time_sec is up-to-date:
+                       this.seek_time_sec = npt2seconds( this.start_ntp ) + parseFloat( perc * this.getDuration() );
+                       js_log('updated seek_time_sec: ' + seconds2npt ( this.seek_time_sec) );
+                       this.stop();                                    
+                       this.didSeekJump=true;
+                       //update the slider
+                       this.setSliderValue( perc ); 
+               }               
+               //do play in 100ms (give things time to clear) 
+               setTimeout('$j(\'#' + this.id + '\').get(0).play()',100);
+       },      
+       addPresTimeOffset:function(){
+          //add in the offset:         
+          if(this.seek_time_sec && this.seek_time_sec!=0){
+                       this.currentTime+=this.seek_time_sec;
+          }else if(this.start_offset && this.start_offset!=0){    
+                  this.currentTime = parseFloat(this.currentTime) + parseFloat(this.start_offset);                      
+          }               
+       },
+       doEmbedHTML:function()
+       {
+               js_log('f:doEmbedHTML');
+               js_log('thum disp:'+this.thumbnail_disp);
+               var _this = this;
+               this.closeDisplayedHTML();
+
+//             if(!this.selected_player){
+//                     return this.getPluginMissingHTML();             
+               //Set "loading" here
+               $j('#mv_embedded_player_'+_this.id).html(''+
+                       '<div style="color:black;width:'+this.width+'px;height:'+this.height+'px;">' + 
+                               gM('loading_plugin') + 
+                       '</div>'                                        
+               );
+               // schedule embedding
+               this.selected_player.load(function()
+               {
+                       js_log('performing embed for ' + _this.id);                     
+                       var embed_code = _this.getEmbedHTML();                  
+                       //js_log('shopuld embed:' + embed_code);
+                       $j('#mv_embedded_player_'+_this.id).html(embed_code);   
+               });
+       },
+       onClipDone:function(){
+               js_log('base:onClipDone');
+               //stop the clip (load the thumbnail etc) 
+               this.stop();
+               this.seek_time_sec = 0;
+               this.setSliderValue(0);
+               var _this = this;
+               
+               //if the clip resolution is < 320 don't do fancy onClipDone stuff 
+               if(this.width < 300){
+                       return ;
+               }
+               this.onClipDone_disp=true;
+               this.thumbnail_disp=true;
+               //make sure we are not in preview mode( no end clip actions in preview mode) 
+               if( this.preview_mode )
+                       return ;
+                       
+               $j('#img_thumb_'+this.id).css('zindex',1);
+               $j('#big_play_link_'+this.id).hide();
+               //add the liks_info_div black back 
+               $j('#dc_'+this.id).append('<div id="liks_info_'+this.id+'" ' +
+                                       'style="width:' +parseInt(parseInt(this.width)/2)+'px;'+                
+                                       'height:'+ parseInt(parseInt(this.height)) +'px;'+
+                                       'position:absolute;top:10px;overflow:auto'+                             
+                                       'width: '+parseInt( ((parseInt(this.width)/2)-15) ) + 'px;'+
+                                       'left:'+ parseInt( ((parseInt(this.width)/2)+15) ) +'px;">'+                                    
+                               '</div>' +
+                               '<div id="black_back_'+this.id+'" ' +
+                                       'style="z-index:-2;position:absolute;background:#000;' +
+                                       'top:0px;left:0px;width:'+parseInt(this.width)+'px;' +
+                                       'height:'+parseInt(this.height)+'px;">' +
+                               '</div>'
+                  );           
+               
+               //start animation (make thumb small in upper left add in div for "loading"                      
+               $j('#img_thumb_'+this.id).animate({                             
+                               width:parseInt(parseInt(_this.width)/2),
+                               height:parseInt(parseInt(_this.height)/2),
+                               top:20,
+                               left:10
+                       },
+                       1000, 
+                       function(){
+                               //animation done.. add "loading" to div if empty                
+                               if($j('#liks_info_'+_this.id).html()==''){
+                                       $j('#liks_info_'+_this.id).html(gM('loading_txt'));
+                               }               
+                       }
+               )                                  
+               //now load roe if run the showNextPrevLinks
+               if(this.roe && this.media_element.addedROEData==false){
+                       do_request(this.roe, function(data)
+                       {                                                                                                                          
+                               _this.media_element.addROE(data);
+                               _this.getNextPrevLinks();
+                       });     
+               }else{
+                       this.getNextPrevLinks();
+               }
+       },
+       //@@todo we should merge getNextPrevLinks with textInterface .. there is repeated code between them. 
+       getNextPrevLinks:function(){
+               js_log('f:getNextPrevLinks');
+               var anno_track_url = null;
+               var _this = this; 
+               //check for annoative track
+               $j.each(this.media_element.sources, function(inx, n){                   
+                       if(n.mime_type=='text/cmml'){
+                               if( n.id == 'Anno_en'){
+                                       anno_track_url = n.src;
+                               }
+                       }
+               });
+               if( anno_track_url ){
+                       js_log('found annotative track:'+ anno_track_url);
+                       //zero out seconds (should improve cache hit rate and generally expands metadata search)
+                       //@@todo this could be repalced with a regExp
+                       var annoURL = parseUri(anno_track_url);
+                       var times = annoURL.queryKey['t'].split('/');                     
+                       var stime_parts = times[0].split(':');   
+                       var etime_parts = times[1].split(':');                                           
+                       //zero out the hour:
+                       var new_start = stime_parts[0]+':'+'0:0';
+                       //zero out the end sec
+                       var new_end   = (etime_parts[0]== stime_parts[0])? (etime_parts[0]+1)+':0:0' :etime_parts[0]+':0:0';
+                                        
+                       var etime_parts = times[1].split(':');
+                       
+                       var new_anno_track_url = annoURL.protocol +'://'+ annoURL.host + annoURL.path +'?';
+                       $j.each(annoURL.queryKey, function(i, val){
+                               new_anno_track_url +=(i=='t')?'t='+new_start+'/'+new_end +'&' :
+                                                                                i+'='+ val+'&';
+                       });
+                       var request_key = new_start+'/'+new_end;
+                       //check the anno_data cache: 
+                       //@@todo search cache see if current is in range.  
+                       if(this.anno_data_cache){
+                               js_log('anno data found in cache: '+request_key);
+                               this.showNextPrevLinks();
+                       }else{                                                          
+                               do_request(new_anno_track_url, function(cmml_data){
+                                       js_log('raw response: '+ cmml_data);
+                                       if(typeof cmml_data == 'string')
+                                       {
+                                               var parser=new DOMParser();
+                                               js_log('Parse CMML data:' + cmml_data);
+                                               cmml_data=parser.parseFromString(cmml_data,"text/xml");
+                                       }
+                                       //init anno_data_cache
+                                       if(!_this.anno_data_cache)
+                                               _this.anno_data_cache={};                                       
+                                       //grab all metadata and put it into the anno_data_cache:                                         
+                                       $j.each(cmml_data.getElementsByTagName('clip'), function(inx, clip){
+                                               _this.anno_data_cache[ $j(clip).attr("id") ]={
+                                                               'start_time_sec':npt2seconds($j(clip).attr("start").replace('npt:','')),
+                                                               'end_time_sec':npt2seconds($j(clip).attr("end").replace('npt:','')),
+                                                               'time_req':$j(clip).attr("start").replace('npt:','')+'/'+$j(clip).attr("end").replace('npt:','')
+                                                       };
+                                               //grab all its meta
+                                               _this.anno_data_cache[ $j(clip).attr("id") ]['meta']={};
+                                               $j.each(clip.getElementsByTagName('meta'),function(imx, meta){                                                  
+                                                       //js_log('adding meta: '+ $j(meta).attr("name")+ ' = '+ $j(meta).attr("content"));
+                                                       _this.anno_data_cache[$j(clip).attr("id")]['meta'][$j(meta).attr("name")]=$j(meta).attr("content");
+                                               });
+                                       });
+                                       _this.showNextPrevLinks();                                      
+                               });
+                       }
+               }else{
+                       js_log('no annotative track found');
+                       $j('#liks_info_'+this.id).html('no metadata found for related links');
+               }
+               //query current request time +|- 60s to get prev next speech links. 
+       },
+       showNextPrevLinks:function(){
+               //js_log('f:showNextPrevLinks');
+               //int requested links: 
+               var link = {
+                       'prev':'',
+                       'current':'',
+                       'next':''
+               }               
+               var curTime = this.getTimeReq().split('/');
+               
+               var s_sec = npt2seconds(curTime[0]);
+               var e_sec = npt2seconds(curTime[1]); 
+               js_log('showNextPrevLinks: req time: '+ s_sec + ' to ' + e_sec);
+               //now we have all the data in anno_data_cache
+               var current_done=false;
+               for(var clip_id in this.anno_data_cache){  //for in loop oky for object
+                        var clip =  this.anno_data_cache[clip_id];
+                        //js_log('on clip:'+ clip_id);
+                        //set prev_link (if cur_link is still empty)
+                       if( s_sec > clip.end_time_sec){
+                               link.prev = clip_id;
+                               js_log('showNextPrevLinks: ' + s_sec + ' < ' + clip.end_time_sec + ' set prev');
+                       }
+                               
+                       if(e_sec==clip.end_time_sec && s_sec== clip.start_time_sec)
+                               current_done = true;
+                       //current clip is not done:
+                       if(  e_sec < clip.end_time_sec  && link.current=='' && !current_done){
+                               link.current = clip_id;
+                               js_log('showNextPrevLinks: ' + e_sec + ' < ' + clip.end_time_sec + ' set current'); 
+                       }
+                       
+                       //set end clip (first clip where start time is > end_time of req
+                       if( e_sec <  clip.start_time_sec && link.next==''){
+                               link.next = clip_id;
+                               js_log('showNextPrevLinks: '+  e_sec + ' < '+ clip.start_time_sec + ' && ' + link.next );
+                       }
+               }   
+               var html='';   
+               if(link.prev=='' && link.current=='' && link.next==''){
+                       html='<p><a href="'+this.media_element.linkbackgetMsg+'">clip page</a>';
+               }else{          
+                       for(var link_type in link){
+                               var link_id = link[link_type];                  
+                               if(link_id!=''){
+                                       var clip = this.anno_data_cache[link_id];                               
+                                       var title_msg='';
+                                       for(var j in clip['meta']){
+                                               title_msg+=j.replace(/_/g,' ') +': ' +clip['meta'][j].replace(/_/g,' ') +" <br>";
+                                       }               
+                                       var time_req =   clip.time_req;
+                                       if(link_type=='current') //if current start from end of current clip play to end of current meta:                                
+                                               time_req = curTime[1]+ '/' + seconds2npt( clip.end_time_sec );
+                                       
+                                       //do special linkbacks for metavid content: 
+                                       var regTimeCheck = new RegExp(/[0-9]+:[0-9]+:[0-9]+\/[0-9]+:[0-9]+:[0-9]+/);                            
+                                       html+='<p><a  ';
+                                       if( regTimeCheck.test( this.media_element.linkback ) ){
+                                               html+=' href="'+ this.media_element.linkback.replace(regTimeCheck,time_req) +'" '; 
+                                       }else{
+                                               html+=' href="#" onClick="$j(\'#'+this.id+'\').get(0).playByTimeReq(\''+ 
+                                                               time_req + '\'); return false; "';                              
+                                       }
+                                       html+=' title="' + title_msg + '">' + 
+                                                gM(link_type+'_clip_msg') +                              
+                                       '</a><br><span style="font-size:small">'+ title_msg +'<span></p>';
+                               }                                                       
+                       }
+               }       
+               //js_og("should set html:"+ html);
+               $j('#liks_info_'+this.id).html(html);
+       },
+       playByTimeReq: function(time_req){
+               js_log('f:playByTimeReq: '+time_req );
+               this.stop();
+               this.updateVideoTimeReq(time_req);
+               this.play();            
+       },
+       doThumbnailHTML:function()
+       {         
+               var _this = this;
+               js_log('f:doThumbnailHTML'+ this.thumbnail_disp);               
+               this.closeDisplayedHTML();         
+               $j( '#mv_embedded_player_' + this.id ).html( this.getThumbnailHTML() );
+               this.paused = true;             
+               this.thumbnail_disp = true;
+       },
+       refreshControlsHTML:function(){
+               js_log('refreshing controls HTML');
+               if($j('#mv_embedded_controls_'+this.id).length==0)
+               {
+                       js_log('#mv_embedded_controls_'+this.id + ' not present, returning');
+                       return;
+               }else{
+                       $j('#mv_embedded_controls_'+this.id).html( this.getControlsHTML() );
+                       ctrlBuilder.addControlHooks(this);                                              
+               }               
+       },   
+       getControlsHTML:function()
+       {                       
+               return ctrlBuilder.getControls( this );
+       },      
+       getHTML : function (){          
+               //@@todo check if we have sources avaliable     
+               js_log('f:getHTML : ' + this.id );                      
+               var _this = this;                                
+               var html_code = '';             
+               html_code = '<div id="videoPlayer_'+this.id+'" style="width:'+this.width+'px;" class="videoPlayer">';           
+                       html_code += '<div style="width:'+parseInt(this.width)+'px;height:'+parseInt(this.height)+'px;"  id="mv_embedded_player_'+this.id+'">' +
+                                                       this.getThumbnailHTML() + 
+                                               '</div>';                                                                                       
+                       //js_log("mvEmbed:controls "+ typeof this.controls);                                                                    
+                       if(this.controls)
+                       {
+                               js_log("f:getHTML:AddControls");
+                               html_code +='<div id="mv_embedded_controls_' + this.id + '" class="ui-widget ui-corner-bottom ui-state-default controls" >';
+                               html_code += this.getControlsHTML();       
+                               html_code +='</div>';     
+                               //block out some space by encapulating the top level div 
+                               $j(this).wrap('<div style="width:'+parseInt(this.width)+'px;height:'
+                                               +(parseInt(this.height)+ctrlBuilder.height)+'px"></div>');                                      
+                       }
+               html_code += '</div>'; //videoPlayer div close          
+               //js_log('should set: '+this.id);
+               $j(this).html( html_code );                                     
+               //add hooks once Controls are in DOM
+               ctrlBuilder.addControlHooks(this);              
+                                                 
+               //js_log('set this to: ' + $j(this).html() );   
+               //alert('stop');
+               //if auto play==true directly embed the plugin
+               if(this.autoplay)
+               {
+                       js_log('activating autoplay');
+                       this.play();
+               }
+       },
+       /*
+       * get missing plugin html (check for user included code)
+       */
+       getPluginMissingHTML : function(missing_type){
+               //keep the box width hight:
+               var out = '<div style="width:'+this.width+'px;height:'+this.height+'px">';
+               if(this.user_missing_plugin_html){
+                 out+= this.user_missing_plugin_html;
+               }else{
+                 if(!missing_type)
+                       missing_type='';
+                 out+= gM('mv_generic_missing_plugin', missing_type) + ' or <a title="'+gM('download_clip')+'" href="'+this.src +'">'+gM('download_clip')+'</a>';
+               }
+               return out + '</div>';
+       },
+       updateVideoTimeReq:function(time_req){
+               js_log('f:updateVideoTimeReq');
+               var time_parts =time_req.split('/');
+               this.updateVideoTime(time_parts[0], time_parts[1]);
+       },
+       //update video time
+       updateVideoTime:function(start_ntp, end_ntp){                                   
+               //update media
+               this.media_element.updateSourceTimes( start_ntp, end_ntp );
+               //update mv_time
+               this.setStatus(start_ntp+'/'+end_ntp);
+               //reset slider
+               this.setSliderValue(0);
+               //reset seek_offset:
+               if(this.media_element.selected_source.URLTimeEncoding )
+                       this.seek_time_sec=0;
+               else
+                       this.seek_time_sec=npt2seconds(start_ntp);
+       },              
+       //@@todo overwite by embed library if we can render frames natavily 
+       renderTimelineThumbnail:function( options ){
+               var my_thumb_src = this.media_element.getThumbnailURL();
+               //check if our thumbnail has a time attribute: 
+               if( my_thumb_src.indexOf('t=') !== -1){
+                       var time_ntp =  seconds2npt ( options.time + parseInt(this.start_offset) );
+                       my_thumb_src = getURLParamReplace( my_thumb_src, { 't':time_ntp, 'size': options.size } );
+               }
+               var thumb_class = (typeof options['thumb_class'] != 'undefined' ) ? options['thumb_class'] : '';
+               return '<div class="ui-corner-all ' + thumb_class + '" src="' + my_thumb_src + '" '+
+                               'style="height:' + options.height + 'px;' +
+                               'width:' + options.width + 'px" >' + 
+                                        '<img src="' + my_thumb_src +'" '+
+                                               'style="height:' + options.height + 'px;' +
+                                               'width:' + options.width + 'px">' +
+                               '</div>';
+       },
+       updateThumbTimeNTP:function( time){
+               this.updateThumbTime( npt2seconds(time) - parseInt(this.start_offset) );
+       },
+       updateThumbTime:function( float_sec ){
+               //js_log('updateThumbTime:'+float_sec);
+               var _this = this;                                                                                                          
+               if( typeof this.org_thum_src=='undefined' ){            
+                       this.org_thum_src = this.media_element.getThumbnailURL();
+               }                                                       
+               if( this.org_thum_src.indexOf('t=') !== -1){
+                       this.last_thumb_url = getURLParamReplace(this.org_thum_src, 
+                               { 't' : seconds2npt( float_sec + parseInt(this.start_offset)) } );                                                                      
+                       if(!this.thumbnail_updating){                           
+                               this.updateThumbnail(this.last_thumb_url ,false);
+                               this.last_thumb_url =null;
+                       }
+               }
+       },
+       //for now provide a src url .. but need to figure out how to copy frames from video for plug-in based thumbs
+       updateThumbPerc:function( perc ){       
+               return this.updateThumbTime( (this.getDuration() * perc) );
+       },
+       //updates the thumbnail if the thumbnail is being displayed
+       updateThumbnail : function(src, quick_switch){                          
+               //make sure we don't go to the same url if we are not already updating: 
+               if( !this.thumbnail_updating && $j('#img_thumb_'+this.id).attr('src')== src )
+                       return false;
+               //if we are already updating don't issue a new update: 
+               if( this.thumbnail_updating && $j('#new_img_thumb_'+this.id).attr('src')== src )
+                       return false;
+               
+               js_log('update thumb: ' + src);
+               
+               if(quick_switch){
+                       $j('#img_thumb_'+this.id).attr('src', src);
+               }else{
+                       var _this = this;                       
+                       //if still animating remove new_img_thumb_
+                       if(this.thumbnail_updating==true)
+                               $j('#new_img_thumb_'+this.id).stop().remove();          
+                                       
+                       if(this.thumbnail_disp){
+                               js_log('set to thumb:'+ src);
+                               this.thumbnail_updating=true;
+                               $j('#dc_'+this.id).append('<img src="'+src+'" ' +
+                                       'style="display:none;position:absolute;zindex:2;top:0px;left:0px;" ' +
+                                       'width="'+this.width+'" height="'+this.height+'" '+
+                                       'id = "new_img_thumb_'+this.id+'" />');                                         
+                               //js_log('appended: new_img_thumb_');           
+                               $j('#new_img_thumb_'+this.id).fadeIn("slow", function(){                                                
+                                               //once faded in remove org and rename new:
+                                               $j('#img_thumb_'+_this.id).remove();
+                                               $j('#new_img_thumb_'+_this.id).attr('id', 'img_thumb_'+_this.id);
+                                               $j('#img_thumb_'+_this.id).css('zindex','1');
+                                               _this.thumbnail_updating=false;                                         
+                                               //js_log("done fadding in "+ $j('#img_thumb_'+_this.id).attr("src"));
+                                               
+                                               //if we have a thumb queued update to that
+                                               if(_this.last_thumb_url){
+                                                       var src_url =_this.last_thumb_url;
+                                                       _this.last_thumb_url=null;
+                                                       _this.updateThumbnail(src_url);
+                                               }
+                               });
+                       }
+               }
+       },
+       /** Returns the HTML code for the video when it is in thumbnail mode.
+               This includes the specified thumbnail as well as buttons for
+               playing, configuring the player, inline cmml display, HTML linkback,
+               download, and embed code.
+       */
+       getThumbnailHTML : function ()
+       {
+               var thumb_html = '';
+               var class_atr='';
+               var style_atr='';
+               //if(this.class)class_atr = ' class="'+this.class+'"';
+               //if(this.style)style_atr = ' style="'+this.style+'"';
+               //      else style_atr = 'overflow:hidden;height:'+this.height+'px;width:'+this.width+'px;';
+               this.thumbnail = this.media_element.getThumbnailURL();
+
+               //put it all in the div container dc_id
+               thumb_html+= '<div id="dc_'+this.id+'" style="position:relative;'+
+                       ' overflow:hidden; top:0px; left:0px; width:'+this.playerPixelWidth()+'px; height:'+this.playerPixelHeight()+'px; z-index:0;">'+
+                       '<img width="'+this.playerPixelWidth()+'" height="'+this.playerPixelHeight()+'" style="position:relative;width:'+this.playerPixelWidth()+';height:'+this.playerPixelHeight()+'"' +
+                       ' id="img_thumb_'+this.id+'" src="' + this.thumbnail + '">';
+               
+               if(this.play_button==true)
+                         thumb_html+=this.getPlayButton();
+                         
+                  thumb_html+='</div>';
+               return thumb_html;
+       },
+       getEmbeddingHTML:function()
+       {
+               var thumbnail = this.media_element.getThumbnailURL();
+
+               var embed_thumb_html;
+               if(thumbnail.substring(0,1)=='/'){
+                       eURL = parseUri(mv_embed_path);
+                       embed_thumb_html = eURL.protocol + '://' + eURL.host + thumbnail;
+                       //js_log('set from mv_embed_path:'+embed_thumb_html);
+               }else{
+                       embed_thumb_html = (thumbnail.indexOf('http://')!=-1)?thumbnail:mv_embed_path + thumbnail;
+               }
+               var embed_code_html = '&lt;script type=&quot;text/javascript&quot; ' +
+                                       'src=&quot;'+mv_embed_path+'mv_embed.js&quot;&gt;&lt;/script&gt' +
+                                       '&lt;video ';
+               if(this.roe){
+                       embed_code_html+='roe=&quot;'+this.roe+'&quot; &gt;';
+               }else{
+                       embed_code_html+='src=&quot;'+this.src+'&quot; ' +
+                               'thumbnail=&quot;'+embed_thumb_html+'&quot;&gt;';
+               }
+               //close the video tag
+               embed_code_html+='&lt;/video&gt;';
+
+               return embed_code_html;
+       },
+       doOptionsHTML:function()
+       {
+               var sel_id = (this.pc!=null)?this.pc.pp.id:this.id;
+               var pos = $j('#options_button_'+sel_id).offset();
+               pos['top']=pos['top']+24;
+               pos['left']=pos['left']-124;
+               //js_log('pos of options button: t:'+pos['top']+' l:'+ pos['left']);
+               $j('#mv_vid_options_'+sel_id).css(pos).toggle();
+               return;
+       },
+       getPlayButton:function(id){
+               if(!id)id=this.id;
+               return '<div title="' + gM('play_clip') + '" id="big_play_link_'+id+'" class="large_play_button" '+
+                       'style="left:'+((this.playerPixelWidth()-130)/2)+'px;'+
+                       'top:' + ((this.playerPixelHeight()-96)/2) + 'px;">'+
+                       '<img src="' + mv_skin_img_path + 'player_big_play_button.png">'+
+                       '</div>';
+       },
+       doLinkBack:function(){
+               if(this.roe && this.media_element.addedROEData==false){
+                       var _this = this;
+                       this.displayHTML(gM('loading_txt'));
+                       do_request(this.roe, function(data)
+                          {
+                                 _this.media_element.addROE(data);                                                      
+                                 _this.doLinkBack();
+                          });                     
+               }else{
+                       if(this.media_element.linkback){                        
+                               window.location = this.media_element.linkback;
+                       }else{
+                               this.displayHTML(gM('could_not_find_linkback'));
+                       }
+               }          
+       },
+       //display the code to remotely embed this video:
+       showEmbedCode : function(embed_code){
+               if(!embed_code)
+                       embed_code = this.getEmbeddingHTML();
+               var o='';
+               if(this.linkback){
+                       o+='<a class="email" href="'+this.linkback+'">Share Clip via Link</a> '+
+                       '<p>or</p> ';
+               }
+               o+='<div>' +
+                               '<span style="color:#FFF;font-size:14px;">Embed Clip in Blog or Site</span><br>'+
+                               '<span style="color:#FFF;font-size:12px;"><a style="color:red" href="http://metavid.org/wiki/Security_Notes_on_Remote_Embedding">'+
+                                       'Read This</a> before embeding.</span>'+
+                               '<div class="embed_code"> '+
+                                       '<textarea onClick="this.select();" id="embedding_user_html_'+this.id+'" name="embed">' +
+                                               embed_code+
+                                       '</textarea> '+
+                                       '<button onClick="$j(\'#'+this.id+'\').get(0).copyText(); return false;" class="copy_to_clipboard">Copy to Clipboard</button> '+
+                               '</div> '+
+                       '</div>';
+               this.displayHTML(o);
+       },
+       copyText:function(){
+         $j('#embedding_user_html_'+this.id).focus().select();                 
+         if(document.selection){         
+                 CopiedTxt = document.selection.createRange(); 
+                 CopiedTxt.execCommand("Copy");
+         }
+       },
+       showTextInterface:function(){   
+               var _this = this;
+               //display the text container with loading text: 
+               //@@todo support position config
+               var loc = $j(this).position();                  
+               if($j('#metaBox_'+this.id).length==0){
+                       $j(this).after('<div class="ui-widget ui-widget-content ui-corner-all" style="position:absolute;z-index:10;'+
+                                               'top:' + (loc.top) + 'px;' +
+                                               'left:' + (parseInt( loc.left ) + parseInt(this.width) + 10 )+'px;' +
+                                               'height:'+ parseInt( this.height )+'px;width:400px;' +                                          
+                                               'display:none;" ' +
+                                               'id="metaBox_' + this.id + '">'+
+                                                       gM('loading_txt') +
+                                               '</div>');                                      
+               }
+               //fade in the text display
+               $j('#metaBox_'+this.id).fadeIn("fast"); 
+               //check if textObj present:
+               if(typeof this.textInterface == 'undefined' ){
+                       //load the default text interface:
+                       mvJsLoader.doLoad([
+                                       'mvTextInterface', 
+                                       '$j.fn.hoverIntent'
+                               ], function(){                                  
+                                       _this.textInterface = new mvTextInterface( _this );                                                     
+                                       //show interface
+                                       _this.textInterface.show();
+                                       js_log("NEW TEXT INTERFACE");
+                                       for(var i in _this.textInterface.availableTracks){
+                                               js_log("tracks in new interface: "+_this.id+ ' tid:' + i);                                              
+                                       }
+                               }
+                       );
+               }else{
+                       //show interface
+                       this.textInterface.show();
+               }
+       },
+       closeTextInterface:function(){
+               js_log('closeTextInterface '+ typeof this.textInterface);
+               if(typeof this.textInterface !== 'undefined' ){
+                       this.textInterface.close();
+               }
+       },
+       /** Generic function to display custom HTML inside the mv_embed element.
+               The code should call the closeDisplayedHTML function to close the
+               display of the custom HTML and restore the regular mv_embed display.            
+               @param {String} HTML code for the selection list.
+       */
+       displayHTML:function(html_code)
+       {
+               var sel_id = (this.pc!=null)?this.pc.pp.id:this.id;
+               
+               if(!this.supports['overlays'])
+                       this.stop();
+               
+               //put select list on-top
+               //make sure the parent is relatively positioned:
+               $j('#'+sel_id).css('position', 'relative');
+               //set height width (check for playlist container)
+               var width = (this.pc)?this.pc.pp.width:this.playerPixelWidth();
+               var height = (this.pc)?this.pc.pp.height:this.playerPixelHeight();
+               
+               if(this.pc)
+                       height+=(this.pc.pp.pl_layout.title_bar_height + this.pc.pp.pl_layout.control_height);
+         
+               var fade_in = true;
+               if($j('#blackbg_'+sel_id).length!=0)
+               {
+                       fade_in = false;
+                       $j('#blackbg_'+sel_id).remove();
+               }
+               //fade in a black bg div ontop of everything
+                var div_code = '<div id="blackbg_'+sel_id+'" class="videoComplete" ' +
+                        'style="height:'+parseInt(height)+'px;width:'+parseInt(width)+'px;">'+
+                         '<div class="videoOptionsComplete">'+
+                       //@@TODO: this style should go to .css
+                       '<span style="float:right;margin-right:10px">' +                        
+                                       '<a href="#" style="color:white;" onClick="$j(\'#'+sel_id+'\').get(0).closeDisplayedHTML();return false;">close</a>' +
+                       '</span>'+
+                       '<div id="mv_disp_inner_'+sel_id+'" style="padding-top:10px;">'+
+                                html_code 
+                          +'</div>'+
+                          '</div></div>';
+               $j('#'+sel_id).prepend(div_code);
+               if (fade_in)
+                       $j('#blackbg_'+sel_id).fadeIn("slow");
+               else
+                       $j('#blackbg_'+sel_id).show();
+               return false; //onclick action return false
+       },
+       /** Close the custom HTML displayed using displayHTML and restores the
+               regular mv_embed display.
+       */
+       closeDisplayedHTML:function(){
+                 var sel_id = (this.pc!=null)?this.pc.pp.id:this.id;
+                $j('#blackbg_'+sel_id).fadeOut("slow", function(){
+                        $j('#blackbg_'+sel_id).remove();
+                });
+                return false; //onclick action return false
+       },
+       selectPlaybackMethod:function(){                
+               //get id (in case where we have a parent container)
+               var this_id = (this.pc!=null)?this.pc.pp.id:this.id;
+               
+               var _this=this;                    
+               var out= '<span style="color:#FFF;background-color:black;"><blockquote style="background-color:black;">';
+               var _this=this;
+               //js_log('selected src'+ _this.media_element.selected_source.url);
+               $j.each( this.media_element.getPlayableSources(), function(source_id, source){                   
+                       var default_player = embedTypes.players.defaultPlayer( source.getMIMEType() );                                                             
+                       
+                       var is_selected = (source == _this.media_element.selected_source);
+                       var image_src =  mv_skin_img_path ;
+                       
+                       //set the Playable source type: 
+                       if( source.mime_type == 'video/x-flv' ){
+                               image_src += 'flash_icon_';
+                       }else if( source.mime_type == 'video/h264'){
+                               //for now all mp4 content is pulled from archive.org (so use archive.org icon) 
+                               image_src += 'archive_org_';
+                       }else{
+                               image_src += 'fish_xiph_org_';
+                       }
+                       image_src += is_selected ? 'color':'bw';
+                       image_src += '.png';                                       
+                       
+                       if (default_player)
+                       {
+                               out += '<img src="'+image_src+'"/>';
+                               if( ! is_selected )
+                                       out+='<a href="#" class="sel_source" id="sc_' + source_id + '_' + default_player.id +'">';
+                               out += source.getTitle()+ (is_selected?'</a>':'') + ' ';
+                               
+                               //output the player select code: 
+                               var supporting_players = embedTypes.players.getMIMETypePlayers( source.getMIMEType() );         
+                               out+='<div id="player_select_list_' + source_id + '" class="player_select_list"><ul>';
+                               for(var i=0; i < supporting_players.length ; i++){                              
+                                       if( _this.selected_player.id == supporting_players[i].id && is_selected ){
+                                               out+='<li style="border-style:dashed;margin-left:20px;">'+
+                                                                       '<img border="0" width="16" height="16" src="' + mv_skin_img_path + 'plugin.png">' +
+                                                                       supporting_players[i].getName() +
+                                                       '</li>';
+                                       }else{
+                                               //else gray plugin and the plugin with link to select
+                                               out+='<li style="margin-left:20px;">'+
+                                                               '<a href="#" class="sel_source" id="sc_' + source_id + '_' + supporting_players[i].id +'">'+
+                                                                       '<img border="0" width="16" height="16" src="' + mv_skin_img_path + 'plugin_disabled.png">'+
+                                                                       supporting_players[i].getName() +
+                                                               '</a>'+
+                                                       '</li>';
+                                       }
+                                }
+                                out+='</ul></div>';               
+                       }else
+                               out+= source.getTitle() + ' - no player available';
+               });
+               out+='</blockquote></span>';
+               this.displayHTML(out);
+               
+               //set up the click bindings:
+               $j('.sel_source').each(function(){
+                       $j(this).click(function(){
+                               var iparts = $j(this).attr( 'id' ).replace(/sc_/,'').split('_');
+                               var source_id = iparts[0];
+                               var default_player_id = iparts[1];
+                               js_log('source id: ' +  source_id + ' player id: ' + default_player_id);                                
+                                
+                               $j('#' + this_id  ).get(0).closeDisplayedHTML();                                
+                               $j('#' + _this.id ).get(0).media_element.selectSource( source_id );
+                               
+                               embedTypes.players.userSelectPlayer( default_player_id,
+                                        _this.media_element.sources[ source_id ].getMIMEType() );
+                                        
+                               //be sure to issue a stop
+                               $j('#' + this_id  ).get(0).stop();
+                               
+                               //don't follow the empty # link:
+                               return false;
+                       });
+               });
+       },
+       /*download list is too complicated ... rewrite for clarity: */
+       showVideoDownload:function(){           
+               //load the roe if available (to populate out download options:
+               //js_log('f:showVideoDownload '+ this.roe + ' ' + this.media_element.addedROEData);
+               if(this.roe && this.media_element.addedROEData==false){
+                       var _this = this;
+                       this.displayHTML(gM('loading_txt'));
+                       do_request(this.roe, function(data)
+                       {
+                          _this.media_element.addROE(data);                                                     
+                          $j('#mv_disp_inner_'+_this.id).html( _this.getShowVideoDownload() );
+                       });                        
+               }else{
+                       this.displayHTML( this.getShowVideoDownload() );
+               }          
+       },
+       getShowVideoDownload:function(){ 
+               var out='<div style="color:white">' +
+                               '<b style="color:white;">'+gM('download_segment')+'</b><br>';
+               out+='<blockquote style="background:#000">'+
+                               gM('download_right_click') + '</blockquote><br>';
+               var dl_list='';
+               var dl_txt_list='';             
+               $j.each(this.media_element.getSources(), function(index, source){
+                       var dl_line = '<li>' + '<a style="color:white" href="' + source.getURI() +'"> '
+                               + source.getTitle()+'</a> '+ '</li>'+"\n";                      
+                       if(      source.getURI().indexOf('?t=')!==-1){
+                               out+=dl_line;
+                       }else if(this.getMIMEType()=="text/cmml" || this.getMIMEType()=="text/x-srt"){
+                               dl_txt_list+=dl_line;
+                       }else{
+                               dl_list+=dl_line;
+                       }
+               });             
+               
+               if(dl_list!='')
+                       out+=gM('download_full') + '<blockquote style="background:#000">' + dl_list + '</blockquote>';
+               if(dl_txt_list!='')
+                       out+=gM('download_text')+'<blockquote style="background:#000">' + dl_txt_list +'</blockquote>';
+               out+='</div>';
+               return out;
+       },
+       /*
+       *  base embed controls
+       *       the play button calls
+       */
+       play:function(){
+               var this_id = (this.pc!=null)?this.pc.pp.id:this.id;
+                               
+               //js_log( "mv_embed play:" + this.id);          
+               //js_log('thum disp:'+this.thumbnail_disp);
+               //check if thumbnail is being displayed and embed html
+               if( this.thumbnail_disp ){                      
+                       if( !this.selected_player ){
+                               js_log('no selected_player');
+                               //this.innerHTML = this.getPluginMissingHTML();
+                               //$j(this).html(this.getPluginMissingHTML());
+                               $j('#'+this.id).html( this.getPluginMissingHTML() );
+                       }else{
+                               this.doEmbedHTML();
+                               this.onClipDone_disp=false;                        
+                               this.paused=false;         
+                               this.thumbnail_disp=false;               
+                       }
+               }else{
+                       //the plugin is already being displayed                 
+                       this.paused=false; //make sure we are not "paused"
+                       this.seeking=false;
+               }                               
+               
+                $j("#mv_play_pause_button_" + this_id + ' span').removeClass('ui-icon-play').addClass('ui-icon-pause');                           
+                $j("#mv_play_pause_button_" + this_id).unbind().btnBind().click(function(){                                    
+                  $j('#' + this_id ).get(0).pause();
+                 }).attr('title', gM('pause_clip'));
+                  
+       },
+       load:function(){
+               //should be done by child (no base way to load assets)
+               js_log('baseEmbed:load call');
+       },
+       getSrc:function(){
+          return this.media_element.selected_source.getURI( this.seek_time_sec );
+       }, 
+       /*
+        * base embed pause
+        *       there is no general way to pause the video
+        *  must be overwritten by embed object to support this functionality.
+        */
+       pause: function(){
+               var this_id = (this.pc!=null)?this.pc.pp.id:this.id;                                                      
+               //js_log('mv_embed:do pause');          
+               //(playing) do pause            
+               this.paused = true; 
+               //update the ctrl "paused state"                                
+               $j("#mv_play_pause_button_" + this_id + ' span').removeClass('ui-icon-pause').addClass('ui-icon-play');
+               $j("#mv_play_pause_button_" + this_id).unbind().btnBind().click(function(){                                                      
+                               $j('#'+this_id).get(0).play();
+               }).attr('title', gM('play_clip'));
+       },      
+       /*
+        * base embed stop (can be overwritten by the plugin)
+        */
+       stop: function(){
+               var _this = this;
+               js_log('mvEmbed:stop:'+this.id);
+               
+               //no longer seeking:
+               this.didSeekJump=false;
+               
+               //first issue pause to update interface (only call the parent) 
+               if(this['parent_pause']){
+                       this.parent_pause();
+               }else{
+                       this.pause();
+               }       
+               
+               //reset the currentTime: 
+               this.currentTime=0;
+               //check if thumbnail is being displayed in which case do nothing
+               if( this.thumbnail_disp ){
+                       //already in stooped state
+                       js_log('already in stopped state');
+               }else{
+                       //rewrite the html to thumbnail disp
+                       this.doThumbnailHTML();
+                       this.bufferedPercent=0; //reset buffer state
+                       this.setSliderValue(0);
+                       this.setStatus( this.getTimeReq() );
+               }
+               
+               //make sure the big playbutton is has click action: 
+               $j('#big_play_link_' + _this.id).unbind('click').click(function(){
+                       $j('#' +_this.id).get(0).play();
+               });
+               
+               if(this.update_interval)
+               {
+                       clearInterval(this.update_interval);
+                       this.update_interval = null;
+               }
+       },
+       toggleMute:function(){
+               var this_id = (this.pc!=null)?this.pc.pp.id:this.id;    
+               if(this.muted){
+                       this.muted=false;
+                       $j('#volume_control_'+this_id + ' span').removeClass('ui-icon-volume-off').addClass('ui-icon-volume-on');
+                       $j('#volume_bar_'+this_id).slider('value', 100); 
+                       this.updateVolumen(1);
+               }else{
+                       this.muted=true;
+                       $j('#volume_control_'+this_id + ' span').removeClass('ui-icon-volume-on').addClass('ui-icon-volume-off');
+                       $j('#volume_bar_'+this_id).slider('value', 0);
+                       this.updateVolumen(0); 
+               }
+               js_log('f:toggleMute::' + this.muted);          
+       },
+       updateVolumen:function(perc){
+               js_log('update volume not supported with current playback type');
+       },
+       fullscreen:function(){
+               js_log('fullscreen not supported with current playback type');
+       },
+       /* returns bool true if playing or paused, false if stooped
+        */
+       isPlaying : function(){
+               if(this.thumbnail_disp){
+                       //in stoped state
+                       return false;
+               }else if( this.paused ){
+                       //paused state
+                       return false;
+               }else{
+                       return true;
+               }
+       },
+       isPaused : function(){
+               return this.isPlaying() && this.paused;
+       },
+       isStoped : function(){
+               return this.thumbnail_disp;
+       },
+       playlistSupport:function(){
+               //by default not supported (implemented in js)
+               return false;
+       },
+       postEmbedJS:function(){
+               return '';
+       },
+       //do common monitor code like update the playhead and play status 
+       //plugin objects are responsible for updating currentTime
+       monitor:function(){
+               if( this.currentTime && this.currentTime > 0 && this.duration){
+                       if( !this.userSlide ){
+                               if( this.start_offset  ){ 
+                                       //if start offset include that calculation 
+                                       this.setSliderValue( ( this.currentTime - this.start_offset ) / this.duration );                        
+                                       this.setStatus( seconds2npt(this.currentTime) + '/'+ seconds2npt(parseFloat(this.start_offset)+parseFloat(this.duration) ));            
+                               }else{
+                                       this.setSliderValue( this.currentTime / this.duration );
+                                       this.setStatus( seconds2npt(this.currentTime) + '/' + seconds2npt(this.duration ));
+                               }                               
+                       }
+               }else{
+                       //js_log(' ct:' + this.currentTime + ' dur: ' + this.duration);
+                       if( this.isStoped() ){
+                               this.setStatus( this.getTimeReq() );
+                       }else if( this.isPaused() ){
+                               this.setStatus( "paused" );
+                       }else if( this.isPlaying() ){
+                               if( this.currentTime && ! this.duration ) 
+                                       this.setStatus( seconds2npt( this.currentTime ) + ' /' );
+                               else   
+                                       this.setStatus(" - - - ");
+                       }else{
+                               this.setStatus( this.getTimeReq() );
+                       }                       
+               }
+               //update buffer information 
+               this.updateBufferStatus();
+               
+               //update monitorTimerId to call child monitor
+               if( ! this.monitorTimerId ){
+                       //make sure an instance of this.id exists: 
+                       if( document.getElementById(this.id) ){
+                               this.monitorTimerId = setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
+                       }
+               }
+       },              
+       stopMonitor:function(){
+               if( this.monitorTimerId != 0 )
+               {
+                       clearInterval( this.monitorTimerId );
+                       this.monitorTimerId = 0;
+               }
+       },
+       updateBufferStatus: function(){
+                       
+               //build the buffer targeet based for playlist vs clip 
+               var buffer_select = (this.pc) ? 
+                       '#cl_status_' + this.id + ' .mv_buffer': 
+                       '#mv_play_head_' + this.id + ' .mv_buffer';
+                       
+               //update the buffer progress bar (if available )
+               if( this.bufferedPercent != 0 ){
+                       //js_log('bufferedPercent: ' + this.bufferedPercent);                   
+                       if(this.bufferedPercent > 1)
+                               this.bufferedPercent=1;                                                 
+                       
+                       $j(buffer_select).css("width", (this.bufferedPercent*100) +'%' );
+               }else{
+                       $j(buffer_select).css("width", '0px' );
+               }
+       },
+       relativeCurrentTime: function(){
+               if(!this.start_offset)
+                       this.start_offset =0;
+               var rt = this.currentTime - this.start_offset;
+               if( rt < 0 ) //should not happen but does. 
+                       return 0;
+               return rt;
+       },
+       getPluginEmbed : function(){
+               if (window.document[this.pid]){
+                       return window.document[this.pid];
+               }
+               if ($j.browser.msie){
+                       return document.getElementById(this.pid );
+               }else{
+                        if (document.embeds && document.embeds[this.pid])
+                               return  document.embeds[this.pid];
+               }
+               return null;
+       },
+       //HELPER Functions for selected source  
+       /*
+       * returns the selected source url for players to play
+       */
+       getURI : function( seek_time_sec ){
+               return this.media_element.selected_source.getURI( this.seek_time_sec );
+       },
+       supportsURLTimeEncoding: function(){
+               //do head request if on the same domain
+               return this.media_element.selected_source.URLTimeEncoding;
+       },
+       setSliderValue: function(perc, hide_progress){          
+               var this_id = (this.pc)?this.pc.pp.id:this.id;
+               var val = parseInt( perc*1000 ); 
+               $j('#mv_play_head_'+this_id).slider('value', val);
+               
+               //js_log('set#mv_seeker_slider_'+this_id + ' perc in: ' + perc + ' * ' + $j('#mv_seeker_'+this_id).width() + ' = set to: '+ val + ' - '+ Math.round(this.mv_seeker_width*perc) );
+               //js_log('op:' + offset_perc + ' *('+perc+' * ' + $j('#slider_'+id).width() + ')');
+       },
+       highlightPlaySection:function(options){
+               js_log('highlightPlaySection');         
+               var this_id = (this.pc)?this.pc.pp.id:this.id;
+               var dur = this.getDuration();
+               var hide_progress = true;               
+               //set the left percet and update the slider: 
+               rel_start_sec = npt2seconds( options['start']);
+               //remove the start_offset if relevent: 
+               if(this.start_offset)
+                       rel_start_sec = rel_start_sec - this.start_offset
+               
+               var slider_perc=0;
+               if( rel_start_sec <= 0 ){
+                       left_perc =0;                    
+                       options['start'] = seconds2npt( this.start_offset );
+                       rel_start_sec=0;                        
+                       this.setSliderValue( 0 , hide_progress);
+               }else{
+                       left_perc = parseInt( (rel_start_sec / dur)*100 ) ;             
+                       slider_perc = (left_perc / 100);
+               }               
+               js_log("slider perc:" + slider_perc);   
+               if( ! this.isPlaying() ){
+                       this.setSliderValue( slider_perc , hide_progress);              
+               }
+               
+               width_perc = parseInt( (( npt2seconds( options['end'] ) - npt2seconds( options['start'] ) ) / dur)*100 ) ;                                                       
+               if( (width_perc + left_perc) > 100 ){
+                       width_perc = 100 - left_perc; 
+               }               
+               //js_log('should hl: '+rel_start_sec+ '/' + dur + ' re:' + rel_end_sec+' lp:'  + left_perc + ' width: ' + width_perc);  
+               $j('#mv_seeker_' + this_id + ' .mv_highlight').css({
+                       'left':left_perc+'%',
+                       'width':width_perc+'%'                  
+               }).show();                              
+               
+               this.jump_time =  options['start'];
+               this.seek_time_sec = npt2seconds( options['start']);
+               //trim output to 
+               this.setStatus( gM('seek_to')+' '+ seconds2npt( this.seek_time_sec ) );
+               js_log('DO update: ' +  this.jump_time);
+               this.updateThumbTime( rel_start_sec );  
+       },
+       hideHighlight:function(){
+               var this_id = (this.pc)?this.pc.pp.id:this.id;
+               $j('#mv_seeker_' + this_id + ' .mv_highlight').hide();
+               this.setStatus( this.getTimeReq() );
+               this.setSliderValue( 0 );
+       },
+       setStatus:function(value){
+               var id = (this.pc)?this.pc.pp.id:this.id;
+               //update status:
+               $j('#mv_time_'+id).html(value);
+       }       
+}
+
+
+
+/**
+  * mediaPlayer represents a media player plugin.
+  * @param {String} id id used for the plugin.
+  * @param {Array<String>} supported_types n array of supported MIME types.
+  * @param {String} library external script containing the plugin interface code. (mv_<library>Embed.js)
+  * @constructor
+  */
+function mediaPlayer(id, supported_types, library)
+{
+       this.id=id;
+       this.supported_types = supported_types;
+       this.library = library;
+       this.loaded = false;
+       this.loading_callbacks = new Array();
+       return this;
+}
+mediaPlayer.prototype =
+{
+       id:null,
+       supported_types:null,
+       library:null,
+       loaded:false,
+       loading_callbacks:null, 
+       supportsMIMEType : function(type)
+       {               
+               for (var i=0; i < this.supported_types.length; i++)
+                       if(this.supported_types[i] == type)
+                               return true;
+               return false;
+       },
+       getName : function()
+       {
+               return gM('mv_ogg-player-' + this.id);
+       },
+       load : function(callback){
+               var libName = this.library+'Embed';
+               if( mvJsLoader.checkObjPath( libName ) ){
+                       js_log('plugin loaded, do callback:');
+                       callback();
+               }else{
+                       var _this = this;                                                                                       
+                       //jQuery based get script does not work so well.                                                        
+                       mvJsLoader.doLoad([ 
+                               libName
+                       ],function(){
+                               callback();                                                     
+                       });
+               }
+       }       
+}
+/* players and supported mime types 
+@@todo ideally we query the plugin to get what mime types it supports in practice not always reliable/avaliable
+*/
+var flowPlayer = new mediaPlayer('flowplayer',['video/x-flv', 'video/h264'],'flash');
+
+var omtkPlayer = new mediaPlayer('omtkplayer',['audio/ogg'], 'omtk' );
+
+var cortadoPlayer = new mediaPlayer('cortado',['video/ogg', 'audio/ogg'],'java');
+var videoElementPlayer = new mediaPlayer('videoElement',['video/ogg', 'audio/ogg'],'native');
+
+var vlcMineList = ['video/ogg','audio/ogg', 'video/x-flv', 'video/mp4',  'video/h264'];
+var vlcMozillaPlayer = new mediaPlayer('vlc-mozilla',vlcMineList,'vlc');
+var vlcActiveXPlayer = new mediaPlayer('vlc-activex',vlcMineList,'vlc');
+
+//add generic
+var oggPluginPlayer = new mediaPlayer('oggPlugin',['video/ogg'],'generic');
+
+//depricate quicktime in favor of safari native 
+//var quicktimeMozillaPlayer = new mediaPlayer('quicktime-mozilla',['video/ogg'],'quicktime');
+//var quicktimeActiveXPlayer = new mediaPlayer('quicktime-activex',['video/ogg'],'quicktime');
+
+var htmlPlayer = new mediaPlayer('html',['text/html', 'image/jpeg', 'image/png', 'image/svg'], 'html');
+
+/**
+  * mediaPlayers is a collection of mediaPlayer objects supported by the client.
+  * It could be merged with embedTypes, since there is one embedTypes per script
+  * and one mediaPlayers per embedTypes.
+  */
+function mediaPlayers()
+{
+       this.init();
+}
+
+mediaPlayers.prototype =
+{
+       players : null,
+       preference : null,
+       default_players : {},
+       init : function()
+       {
+               this.players = new Array();
+               this.loadPreferences();
+               
+               //set up default players order for each library type            
+               this.default_players['video/x-flv'] = ['flash','vlc'];
+               this.default_players['video/h264'] = ['flash', 'vlc'];
+               
+               this.default_players['video/ogg'] = ['native','vlc','java', 'generic'];         
+               this.default_players['application/ogg'] = ['native','vlc','java', 'generic'];           
+               this.default_players['audio/ogg'] = ['native','vlc', 'java', 'omtk' ];          
+               this.default_players['video/mp4'] = ['vlc'];
+               
+               this.default_players['text/html'] = ['html'];
+               this.default_players['image/jpeg'] = ['html'];
+               
+       },
+       addPlayer : function(player, mime_type)
+       {               
+               //js_log('Adding ' + player.id + ' with mime_type ' + mime_type);
+               for (var i =0; i < this.players.length; i++){
+                       if (this.players[i].id == player.id)
+                       {
+                               if(mime_type!=null)
+                               {
+                                       //make sure the mime_type is not already there:
+                                       var add_mime = true; 
+                                       for(var j=0; j < this.players[i].supported_types.length; j++ ){
+                                               if( this.players[i].supported_types[j]== mime_type)
+                                                       add_mime=false;
+                                       }                                       
+                                       if(add_mime)
+                                               this.players[i].supported_types.push(mime_type);
+                               }
+                               return;
+                       }
+               }
+               //player not found: 
+               if(mime_type!=null)
+                       player.supported_types.push(mime_type);   
+                                
+               this.players.push( player );
+       },
+       getMIMETypePlayers : function(mime_type)
+       {                               
+               var mime_players = new Array();
+               var _this = this;
+               var inx = 0;
+               if( this.default_players[mime_type] ){                                          
+                       $j.each( this.default_players[mime_type], function(d, lib){                             
+                               var library = _this.default_players[mime_type][d];                              
+                               for ( var i=0; i < _this.players.length; i++ ){                                 
+                                       if ( _this.players[i].library == library && _this.players[i].supportsMIMEType(mime_type) ){
+                                               mime_players[ inx ] = _this.players[i];                                         
+                                               inx++;
+                                       }
+                               }
+                       });
+               }               
+               return mime_players;
+       },
+       defaultPlayer : function(mime_type)
+       {                               
+               js_log("f:defaultPlayer: " + mime_type);
+               var mime_players = this.getMIMETypePlayers(mime_type);          
+               if( mime_players.length > 0)
+               {
+                       // check for prior preference for this mime type
+                       for( var i=0; i < mime_players.length; i++ ){
+                               if( mime_players[i].id==this.preference[mime_type] )
+                                       return mime_players[i];
+                       }                                       
+                       // otherwise just return the first compatible player
+                       // (it will be chosen according to the default_players list
+                       return mime_players[0];
+               }
+               js_log( 'No default player found for ' + mime_type );
+               return null;
+       },
+       userSelectFormat : function (mime_format){
+                this.preference['format_prefrence'] = mime_format;
+                this.savePreferences();
+       },
+       userSelectPlayer : function(player_id, mime_type)
+       {
+               var selected_player=null;
+               for(var i=0; i < this.players.length; i++){
+                       if(this.players[i].id == player_id)
+                       {
+                               selected_player = this.players[i];
+                               js_log('choosing ' + player_id + ' for ' + mime_type);
+                               this.preference[mime_type]=player_id;
+                               this.savePreferences();
+                               break;
+                       }
+               }
+               if( selected_player )
+               {
+                       for(var i=0; i < global_player_list.length; i++)
+                       {
+                               var embed = $j('#'+global_player_list[i]).get(0);
+                               if(embed.media_element.selected_source && (embed.media_element.selected_source.mime_type == mime_type))
+                               {
+                                       embed.selectPlayer(selected_player);
+                                       js_log('using ' + embed.selected_player.getName() + ' for ' + embed.media_element.selected_source.getTitle());
+                               }
+                       }
+               }
+       },
+       loadPreferences : function()
+       {
+               this.preference = new Object();                         
+               // see if we have a cookie set to a clientSupported type:
+               var cookieVal = $j.cookie( 'ogg_player_exp' );
+               if (cookieVal)
+               {
+                       var pairs = cookieVal.split('&');
+                       for(var i=0; i < pairs.length; i++)
+                       {
+                               var name_value = pairs[i].split('=');
+                               this.preference[name_value[0]]=name_value[1];
+                               //js_log('load preference for ' + name_value[0] + ' is ' + name_value[1]);
+                       }
+               }
+       },
+       savePreferences : function()
+       {
+               var cookieVal = '';             
+               for(var i in this.preference)
+                       cookieVal+= i + '='+ this.preference[i] + '&';
+                       
+               cookieVal=cookieVal.substr(0, cookieVal.length-1);              
+               var week = 7*86400*1000;
+               $j.cookie( 'ogg_player_exp', cookieVal, { 'expires':week } );
+       }
+};
+
+/*
+ * embedTypes object handles setting and getting of supported embed types:
+ * closely mirrors OggHandler so that its easier to share efforts in this area:
+ * http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/OggHandler/OggPlayer.js
+ */
+var embedTypes = {
+        // List of players
+        players: null,
+        detect_done:false,      
+        init: function(){
+               //detect supported types
+               this.detect();
+               this.detect_done=true;
+       },
+       clientSupports: { 'thumbnail' : true },
+       supportedMimeType: function(mimetype) {
+               for (var i = navigator.plugins.length; i-- > 0; ) {
+                       var plugin = navigator.plugins[i];
+                       if (typeof plugin[mimetype] != "undefined")
+                         return true;
+               }
+               return false;
+       },
+
+        detect: function() {
+                js_log("running detect");
+               this.players = new mediaPlayers();
+               //every browser supports html rendering:
+               this.players.addPlayer( htmlPlayer );                   
+                // In Mozilla, navigator.javaEnabled() only tells us about preferences, we need to
+                // search navigator.mimeTypes to see if it's installed
+                var javaEnabled = navigator.javaEnabled();
+                // In Opera, navigator.javaEnabled() is all there is
+                var invisibleJava = $j.browser.opera;
+                // Some browsers filter out duplicate mime types, hiding some plugins
+                var uniqueMimesOnly = $j.browser.opera || $j.browser.safari;
+                // Opera will switch off javaEnabled in preferences if java can't be found.
+                // And it doesn't register an application/x-java-applet mime type like Mozilla does.
+                if ( invisibleJava && javaEnabled )
+                        this.players.addPlayer( cortadoPlayer );
+               
+                // ActiveX plugins
+                if($j.browser.msie){
+                         // check for flash             
+                          if ( this.testActiveX( 'ShockwaveFlash.ShockwaveFlash')){                               
+                                  //try to get the flash version for omtk include: 
+                                  try {
+                                       a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".7");
+                                       d = a.GetVariable("$version");  // Will crash fp6.0.21/23/29
+                                       if (d) {
+                                               d = d.split(" ")[1].split(",");                                         
+                                               //we need flash version 10 or greater:
+                                               if(parseInt( d[0]) >=10){
+                                                       this.players.addPlayer( omtkPlayer );
+                                               }
+                                               
+                                       }                                       
+                               }catch(e) {}                            
+                               
+                                  //flowplayer has pretty good compatiablity 
+                                  // (but if we wanted to be fancy we would check for version of flash and update the mp4/h.264 support
+                                  this.players.addPlayer( flowPlayer );                                   
+                          }
+                        // VLC
+                        if ( this.testActiveX( 'VideoLAN.VLCPlugin.2' ) )
+                                this.players.addPlayer(vlcActiveXPlayer);
+                        // Java
+                        if ( javaEnabled && this.testActiveX( 'JavaWebStart.isInstalled' ) )
+                                this.players.addPlayer(cortadoPlayer);
+                        // quicktime
+                        //if ( this.testActiveX( 'QuickTimeCheckObject.QuickTimeCheck.1' ) )
+                        //     this.players.addPlayer(quicktimeActiveXPlayer);                  
+                }                               
+               // <video> element
+               if ( typeof HTMLVideoElement == 'object' // Firefox, Safari
+                               || typeof HTMLVideoElement == 'function' ) // Opera
+               {
+                       //do another test for safari: 
+                       if( $j.browser.safari ){                                
+                               try{
+                                       var dummyvid = document.createElement("video");
+                                       if (dummyvid.canPlayType && dummyvid.canPlayType("video/ogg;codecs=\"theora,vorbis\"") == "probably")
+                                       {
+                                               this.players.addPlayer( videoElementPlayer );
+                                       } else if(this.supportedMimeType('video/ogg')) {
+                                               /* older versions of safari do not support canPlayType,
+                                                  but xiph qt registers mimetype via quicktime plugin */
+                                               this.players.addPlayer( videoElementPlayer );
+                                       } else {
+                                               //@@todo add some user nagging to install the xiph qt 
+                                       }
+                               }catch(e){
+                                       js_log('could not run canPlayType in safari');
+                               }
+                       }else{
+                               this.players.addPlayer( videoElementPlayer );
+                       }
+               }                
+               
+                // Mozilla plugins
+               if( navigator.mimeTypes && navigator.mimeTypes.length > 0) {
+                       for ( var i = 0; i < navigator.mimeTypes.length; i++ ) {
+                               var type = navigator.mimeTypes[i].type;
+                               var semicolonPos = type.indexOf( ';' );
+                               if ( semicolonPos > -1 ) {
+                                       type = type.substr( 0, semicolonPos );
+                               }
+                               //js_log('on type: '+type);
+                               var pluginName = navigator.mimeTypes[i].enabledPlugin ? navigator.mimeTypes[i].enabledPlugin.name : '';
+                               if ( !pluginName ) {
+                                       // In case it is null or undefined
+                                       pluginName = '';
+                               }                               
+                               if ( pluginName.toLowerCase() == 'vlc multimedia plugin' || pluginName.toLowerCase() == 'vlc multimedia plug-in' ) {
+                                       this.players.addPlayer(vlcMozillaPlayer, type);
+                                       continue;
+                               }
+               
+                               if ( javaEnabled && type == 'application/x-java-applet' ) {
+                                       this.players.addPlayer(cortadoPlayer);
+                                       continue;
+                               }                               
+               
+                               if ( type == 'application/ogg' ) {
+                                       if ( pluginName.toLowerCase() == 'vlc multimedia plugin' ){
+                                               this.players.addPlayer(vlcMozillaPlayer, type);
+                                       //else if ( pluginName.indexOf( 'QuickTime' ) > -1 )
+                                       //      this.players.addPlayer(quicktimeMozillaPlayer);
+                                       }else{
+                                               this.players.addPlayer(oggPluginPlayer);
+                                       }
+                                       continue;
+                               } else if ( uniqueMimesOnly ) {
+                                       if ( type == 'application/x-vlc-player' ) {
+                                               this.players.addPlayer(vlcMozillaPlayer, type);
+                                               continue;
+                                       } else if ( type == 'video/quicktime' ) {
+                                               //this.players.addPlayer(quicktimeMozillaPlayer);
+                                               continue;
+                                       }
+                               }
+               
+                               /*if ( type == 'video/quicktime' ) {
+                                       this.players.addPlayer(vlcMozillaPlayer, type);
+                                       continue;
+                               }*/
+                               if(type=='application/x-shockwave-flash'){
+                                       this.players.addPlayer( flowPlayer );
+                                       
+                                       //check version to add omtk:
+                                       var flashDescription = navigator.plugins["Shockwave Flash"].description;
+                                       var descArray = flashDescription.split(" ");
+                                       var tempArrayMajor = descArray[2].split(".");
+                                       var versionMajor = tempArrayMajor[0];
+                                       //js_log("version of flash: " + versionMajor);
+                                       if(versionMajor >= 10){
+                                               this.players.addPlayer( omtkPlayer );
+                                       }                                       
+                                       continue;
+                               }
+                       }
+               }
+               //@@The xiph quicktime component does not work well with annodex streams (temporarly disable)
+               //this.clientSupports['quicktime-mozilla'] = false;
+               //this.clientSupports['quicktime-activex'] = false;
+               //js_log(this.clientSupports);
+       },
+       testActiveX : function ( name ) {
+                var hasObj = true;
+                try {
+                        // No IE, not a class called "name", it's a variable
+                        var obj = new ActiveXObject( '' + name );
+                } catch ( e ) {
+                        hasObj = false;
+                }
+                return hasObj;
+       }        
+};
diff --git a/js2/mwEmbed/libEmbedVideo/flashEmbed.js b/js2/mwEmbed/libEmbedVideo/flashEmbed.js
new file mode 100644 (file)
index 0000000..ef83a2d
--- /dev/null
@@ -0,0 +1,1838 @@
+/**
+ * metavid: mv_flashEmbed builds off of flowplayer api (included first in this file) 
+ */
+ /**
+ * flowplayer.js 3.0.0-rc5. The Flowplayer API.
+ * 
+ * This file is part of Flowplayer, http://flowplayer.org
+ *
+ * Author: Tero Piirainen, <support@flowplayer.org>
+ * Copyright (c) 2008 Flowplayer Ltd
+ *
+ * Released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * 
+ * Version: 3.0.0-rc5 - Thu Nov 20 2008 22:09:49 GMT-0000 (GMT+00:00)
+ */
+(function() {
+/* 
+       FEATURES 
+       --------
+       - handling multiple instances 
+       - Flowplayer programming API 
+       - Flowplayer event model        
+       - player loading / unloading
+       - $f() function
+       - jQuery support
+*/ 
+
+/*jslint glovar: true, browser: true */
+/*global flowplayer, $f */
+
+// {{{ private utility methods
+       
+       function log(args) {
+               
+               // write into opera console
+               if (typeof opera == 'object') {
+                       opera.postError("$f.fireEvent: " + args.join(" | "));   
+
+                       
+               } else if (typeof console == 'object') {
+                       console.log("$f.fireEvent", [].slice.call(args));       
+               }
+       }
+
+               
+       // thanks: http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
+       function clone(obj) {   
+               if (!obj || typeof obj != 'object') { return obj; }             
+               var temp = new obj.constructor();       
+               for (var key in obj) {  
+                       if (obj.hasOwnProperty(key)) {
+                               temp[key] = clone(obj[key]);
+                       }
+               }               
+               return temp;
+       }
+
+       // stripped from jQuery, thanks John Resig 
+       function each(obj, fn) {
+               if (!obj) { return; }
+               
+               var name, i = 0, length = obj.length;
+       
+               // object
+               if (length === undefined) {
+                       for (name in obj) {
+                               if (fn.call(obj[name], name, obj[name]) === false) { break; }
+                       }
+                       
+               // array
+               } else {
+                       for (var value = obj[0];
+                               i < length && fn.call( value, i, value ) !== false; value = obj[++i]) {                         
+                       }
+               }
+       
+               return obj;
+       }
+
+       
+       // convenience
+       function el(id) {
+               return document.getElementById(id);      
+       }       
+
+       
+       // used extensively. a very simple implementation. 
+       function extend(to, from, skipFuncs) {
+               if (to && from) {                       
+                       each(from, function(name, value) {
+                               if (!skipFuncs || typeof value != 'function') {
+                                       to[name] = value;               
+                               }
+                       });
+               }
+       }
+       
+       // var arr = select("elem.className"); 
+       function select(query) {
+               var index = query.indexOf("."); 
+               if (index != -1) {
+                       var tag = query.substring(0, index) || "*";
+                       var klass = query.substring(index + 1, query.length);
+                       var els = [];
+                       each(document.getElementsByTagName(tag), function() {
+                               if (this.className && this.className.indexOf(klass) != -1) {
+                                       els.push(this);         
+                               }
+                       });
+                       return els;
+               }
+       }
+       
+       // fix event inconsistencies across browsers
+       function stopEvent(e) {
+               e = e || window.event;
+               
+               if (e.preventDefault) {
+                       e.stopPropagation();
+                       e.preventDefault();
+                       
+               } else {
+                       e.returnValue = false;  
+                       e.cancelBubble = true;
+               } 
+               return false;
+       }
+
+       // push an event listener into existing array of listeners
+       function bind(to, evt, fn) {
+               to[evt] = to[evt] || [];
+               to[evt].push(fn);               
+       }
+       
+       
+       // generates an unique id
+   function makeId() {
+         return "_" + ("" + Math.random()).substring(2, 10);   
+   }
+       
+//}}}  
+       
+
+// {{{ Clip
+
+       var Clip = function(json, index, player) {
+               
+               // private variables
+               var self = this;
+               var cuepoints = {};
+               var listeners = {}; 
+               this.index = index;
+               
+               // instance variables
+               if (typeof json == 'string') {
+                       json = {url:json};      
+               }
+       
+               extend(this, json, true);       
+               
+               // event handling 
+               each(("Begin*,Start,Pause*,Resume*,Seek*,Stop*,Finish*,LastSecond,Update,BufferFull,BufferEmpty,BufferStop").split(","),
+                       function() {
+                       
+                       var evt = "on" + this;
+                               
+                       // before event
+                       if (evt.indexOf("*") != -1) {
+                               evt = evt.substring(0, evt.length -1); 
+                               var before = "onBefore" + evt.substring(2); 
+                               
+                               self[before] = function(fn) {
+                                       bind(listeners, before, fn);
+                                       return self;
+                               };                              
+                       }  
+                       
+                       self[evt] = function(fn) {
+                               bind(listeners, evt, fn);
+                               return self;
+                       };
+                       
+                       
+                       // set common clip event listeners to player level
+                       if (index == -1) {
+                               if (self[before]) {
+                                       player[before] = self[before];          
+                               }                               
+                               if (self[evt])  {
+                                       player[evt] = self[evt];                
+                               }
+                       }
+                       
+               });                       
+               
+               extend(this, {
+                       
+                        
+                       onCuepoint: function(points, fn) {
+                               
+                               // embedded cuepoints
+                               if (arguments.length == 1) {
+                                       cuepoints.embedded = [null, points];
+                                       return self;
+                               }
+                               
+                               if (typeof points == 'number') {
+                                       points = [points];      
+                               }
+                               
+                               var fnId = makeId();  
+                               cuepoints[fnId] = [points, fn]; 
+                               
+                               if (player.isLoaded()) {
+                                       player._api().fp_addCuepoints(points, index, fnId);     
+                               }  
+                               
+                               return self;
+                       },
+                       
+                       update: function(json) {
+                               extend(self, json);
+
+                               if (player.isLoaded()) {
+                                       player._api().fp_updateClip(json, index);       
+                               }
+                               var conf = player.getConfig(); 
+                               var clip = (index == -1) ? conf.clip : conf.playlist[index];
+                               extend(clip, json, true);
+                       },
+                       
+                       
+                       // internal event for performing clip tasks. should be made private someday
+                       _fireEvent: function(evt, arg1, arg2, target) {                          
+                               
+                               if (evt == 'onLoad') { 
+                                       each(cuepoints, function(key, val) {
+                                               player._api().fp_addCuepoints(val[0], index, key);               
+                                       }); 
+                                       return false;
+                               }                                       
+                               
+                               // target clip we are working against
+                               if (index != -1) {
+                                       target = self;  
+                               }
+                               
+                               if (evt == 'onCuepoint') {
+                                       var fn = cuepoints[arg1];
+                                       if (fn) {
+                                               return fn[1].call(player, target, arg2);
+                                       }
+                               }  
+       
+                               if (evt == 'onStart' || evt == 'onUpdate') {
+                                       
+                                       extend(target, arg1);                                   
+                                       
+                                       if (!target.duration) {
+                                               target.duration = arg1.metaData.duration;        
+                                       } else {
+                                               target.fullDuration = arg1.metaData.duration;   
+                                       }                                         
+                               }  
+                               
+                               var ret = true;
+                               each(listeners[evt], function() {
+                                       ret = this.call(player, target, arg1);          
+                               }); 
+                               return ret;                             
+                       }                       
+                       
+               });
+               
+               
+               // get cuepoints from config
+               if (json.onCuepoint) {
+                       self.onCuepoint.apply(self, json.onCuepoint);
+                       delete json.onCuepoint;
+               } 
+               
+               // get other events
+               each(json, function(key, val) {
+                       if (typeof val == 'function') {
+                               bind(listeners, key, val);
+                               delete json[key];       
+                       }
+               });
+
+               
+               // setup common clip event callbacks for Player object too (shortcuts)
+               if (index == -1) {
+                       player.onCuepoint = this.onCuepoint;    
+               }
+       
+       };
+
+//}}}
+
+
+// {{{ Plugin
+               
+       var Plugin = function(name, json, player, fn) {
+       
+               var listeners = {};
+               var self = this;   
+               var hasMethods = false;
+       
+               if (fn) {
+                       extend(listeners, fn);  
+               }   
+               
+               // custom callback functions in configuration
+               each(json, function(key, val) {
+                       if (typeof val == 'function') {
+                               listeners[key] = val;
+                               delete json[key];       
+                       }
+               });  
+               
+               // core plugin methods          
+               extend(this, {
+  
+                       animate: function(props, speed, fn) { 
+                               if (!props) {
+                                       return self;    
+                               }
+                               
+                               if (typeof speed == 'function') { 
+                                       fn = speed; 
+                                       speed = 500;
+                               }
+                               
+                               if (typeof props == 'string') {
+                                       var key = props;
+                                       props = {};
+                                       props[key] = speed;
+                                       speed = 500; 
+                               }
+                               
+                               if (fn) {
+                                       var fnId = makeId();
+                                       listeners[fnId] = fn;
+                               }
+               
+                               if (speed === undefined) { speed = 500; }
+                               json = player._api().fp_animate(name, props, speed, fnId);      
+                               return self;
+                       },
+                       
+                       css: function(props, val) {
+                               if (val !== undefined) {
+                                       var css = {};
+                                       css[props] = val;
+                                       props = css;                                    
+                               }
+                               try{
+                                       json = player._api().fp_css(name, props);
+                                       extend(self, json);
+                                       return self;
+                               }catch(e){
+                                       js_log('flow player could not set css: ' + json);
+                               }
+                       },
+                       
+                       show: function() {
+                               this.display = 'block';
+                               player._api().fp_showPlugin(name);
+                               return self;
+                       },
+                       
+                       hide: function() {
+                               this.display = 'none';
+                               player._api().fp_hidePlugin(name);
+                               return self;
+                       },
+                       
+                       toggle: function() {
+                               this.display = player._api().fp_togglePlugin(name);
+                               return self;
+                       },                      
+                       
+                       fadeTo: function(o, speed, fn) {
+                               
+                               if (typeof speed == 'function') { 
+                                       fn = speed; 
+                                       speed = 500;
+                               }
+                               
+                               if (fn) {
+                                       var fnId = makeId();
+                                       listeners[fnId] = fn;
+                               }                               
+                               this.display = player._api().fp_fadeTo(name, o, speed, fnId);
+                               this.opacity = o;
+                               return self;
+                       },
+                       
+                       fadeIn: function(speed, fn) { 
+                               return self.fadeTo(1, speed, fn);                               
+                       },
+       
+                       fadeOut: function(speed, fn) {
+                               return self.fadeTo(0, speed, fn);       
+                       },
+                       
+                       getName: function() {
+                               return name;    
+                       },
+                       
+                       
+                       // internal method not meant to be used by clients
+                _fireEvent: function(evt, arg) {
+
+                               
+                       // update plugins properties & methods
+                       if (evt == 'onUpdate') {
+                          var json = arg || player._api().fp_getPlugin(name); 
+                                       if (!json) { return;    }                                       
+                                       
+                          extend(self, json);
+                          delete self.methods;
+                                       
+                          if (!hasMethods) {
+                                 each(json.methods, function() {
+                                        var method = "" + this;           
+                                                       
+                                        self[method] = function() {
+                                               var a = [].slice.call(arguments);
+                                               var ret = player._api().fp_invoke(name, method, a); 
+                                               return ret == 'undefined' ? self : ret;
+                                        };
+                                 });
+                                 hasMethods = true;             
+                          }
+                       }
+                       
+                       // plugin callbacks
+                       var fn = listeners[evt];
+
+                               if (fn) {
+                                       
+                                       fn.call(self, arg);
+                                       
+                                       // "one-shot" callback
+                                       if (evt.substring(0, 1) == "_") {
+                                               delete listeners[evt];  
+                                       } 
+                       }                
+                }                                       
+                       
+               });
+
+       };
+
+
+//}}}
+
+
+function Player(wrapper, params, conf) {   
+               
+       // private variables (+ arguments)
+       var 
+               self = this, 
+               api = null, 
+               html, 
+               commonClip, 
+               playlist = [], 
+               plugins = {},
+               listeners = {},
+               playerId,
+               apiId,
+               activeIndex,
+               swfHeight,
+               wrapperHeight;  
+
+  
+// {{{ public methods 
+       
+       extend(self, {
+                       
+               id: function() {
+                       return playerId;        
+               }, 
+               
+               isLoaded: function() {
+                       return (api !== null);  
+               },
+               
+               getParent: function() {
+                       return wrapper; 
+               },
+               
+               hide: function(all) {
+                       if (all) { wrapper.style.height = "0px"; }
+                       if (api) { api.style.height = "0px"; } 
+                       return self;
+               },
+
+               show: function() {
+                       wrapper.style.height = wrapperHeight + "px";
+                       if (api) { api.style.height = swfHeight + "px"; }
+                       return self;
+               }, 
+                                       
+               isHidden: function() {
+                       return api && parseInt(api.style.height, 10) === 0;
+               },
+               
+               
+               load: function(fn) { 
+                       
+                       if (!api && self._fireEvent("onBeforeLoad") !== false) {
+                               
+                               // unload all instances
+                               each(players, function()  {
+                                       this.unload();          
+                               });
+                               
+                               html = wrapper.innerHTML; 
+                               flashembed(wrapper, params, {config: conf});
+                               
+                               // function argument
+                               if (fn) {
+                                       fn.cached = true;
+                                       bind(listeners, "onLoad", fn);  
+                               }
+                       }
+                       
+                       return self;    
+               },
+               
+               unload: function() {  
+                       
+                if (api && html.replace(/\s/g, '') !== '' && !api.fp_isFullscreen() && 
+                       self._fireEvent("onBeforeUnload") !== false) { 
+                               api.fp_close();
+                               wrapper.innerHTML = html; 
+                               self._fireEvent("onUnload");
+                               api = null;
+                       }
+                       
+                       return self;
+               },
+
+               getClip: function(index) {
+                       if (index === undefined) {
+                               index = activeIndex;    
+                       }
+                       return playlist[index];
+               },
+               
+               
+               getCommonClip: function() {
+                       return commonClip;      
+               },              
+               
+               getPlaylist: function() {
+                       return playlist; 
+               },
+               
+         getPlugin: function(name) {  
+                var plugin = plugins[name];
+                
+                       // create plugin if nessessary
+                if (!plugin && self.isLoaded()) {
+                               var json = self._api().fp_getPlugin(name);
+                               if (json) {
+                                       plugin = new Plugin(name, json, self);
+                                       plugins[name] = plugin;                                           
+                               } 
+                }              
+                return plugin; 
+         },
+               
+               getScreen: function() { 
+                       return self.getPlugin("screen");
+               }, 
+               
+               getControls: function() { 
+                       return self.getPlugin("controls");
+               }, 
+
+               getConfig: function() { 
+                       return clone(conf);
+               },
+               
+               getFlashParams: function() { 
+                       return params;
+               },              
+               
+               loadPlugin: function(name, url, props, fn) { 
+
+                       // properties not supplied                      
+                       if (typeof props == 'function') { 
+                               fn = props; 
+                               props = {};
+                       } 
+                       
+                       // if fn not given, make a fake id so that plugin's onUpdate get's fired
+                       var fnId = fn ? makeId() : "_"; 
+                       self._api().fp_loadPlugin(name, url, props, fnId); 
+                       
+                       // create new plugin
+                       var arg = {};
+                       arg[fnId] = fn;
+                       var p = new Plugin(name, null, self, arg);
+                       plugins[name] = p;
+                       return p;                       
+               },
+               
+               
+               getState: function() {
+                       return api ? api.fp_getState() : -1;
+               },
+               
+               // "lazy" play
+               play: function(clip) {
+                       
+                       function play() {
+                               if (clip !== undefined) {
+                                       self._api().fp_play(clip);
+                               } else {
+                                       if(typeof self._api().fp_play == 'function')
+                                               self._api().fp_play();  
+                               }
+                       }
+                       
+                       if (api) {
+                               play();
+                               
+                       } else {
+                               self.load(function() { 
+                                       play();
+                               });
+                       }
+                       
+                       return self;
+               },
+               
+               getVersion: function() {
+                       var js = "flowplayer.js 3.0.0-rc5";
+                       if (api) {
+                               var ver = api.fp_getVersion();
+                               ver.push(js);
+                               return ver;
+                       }
+                       return js; 
+               },
+               
+               _api: function() {
+                       if (!api) {
+                               throw "Flowplayer " +self.id()+ " not loaded. Try moving your call to player's onLoad event";
+                       }
+                       return api;                             
+               },
+               
+               _dump: function() {
+                       console.log(listeners);
+               }
+               
+       }); 
+       
+       
+       // event handlers
+       each(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,Fullscreen*,FullscreenExit,Error").split(","),
+               function() {             
+                       var name = "on" + this;
+                       
+                       // before event
+                       if (name.indexOf("*") != -1) {
+                               name = name.substring(0, name.length -1); 
+                               var name2 = "onBefore" + name.substring(2);
+                               self[name2] = function(fn) {
+                                       bind(listeners, name2, fn);     
+                                       return self;
+                               };                                              
+                       }
+                       
+                       // normal event
+                       self[name] = function(fn) {
+                               bind(listeners, name, fn);      
+                               return self;
+                       };                       
+               }
+       ); 
+       
+       
+       // core API methods
+       each(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,reset").split(","),         
+               function() {             
+                       var name = this;
+                       
+                       self[name] = function(arg) {
+                               if (!api) { return self; }
+                               try{
+                                       var ret = (arg === undefined) ? api["fp_" + name]() : api["fp_" + name](arg);
+                                       return ret == 'undefined' ? self : ret;
+                               }catch (e){
+                                       js_log('flowplayer could not access fp_ '+ name);
+                               }
+                       };                       
+               }
+       );               
+       
+//}}}
+
+
+// {{{ public method: _fireEvent
+               
+       self._fireEvent = function(evt, arg0, arg1, arg2) {             
+                               
+               if (conf.debug) {
+                       log(arguments);         
+               }                               
+               
+               // internal onLoad
+               if (evt == 'onLoad' && !api) {  
+                       
+                       api = api || el(apiId); 
+                       swfHeight = api.clientHeight;
+                       
+                       each(playlist, function() {
+                               this._fireEvent("onLoad");              
+                       });
+                       
+                       each(plugins, function(name, p) {
+                               p._fireEvent("onUpdate");               
+                       });
+                       
+                       
+                       commonClip._fireEvent("onLoad");  
+               }
+               
+         if (evt == 'onContextMenu') {
+                each(conf.contextMenu[arg0], function(key, fn)  {
+                       fn.call(self);
+                });
+                return;
+         }
+
+               if (evt == 'onPluginEvent') {
+                       var name = arg0.name || arg0;
+                       var p = plugins[name];
+                       if (p) {
+                               if (arg0.name) {
+                                       p._fireEvent("onUpdate", arg0);         
+                               }
+                               p._fireEvent(arg1);             
+                       }
+                       return;
+               }               
+
+               // onPlaylistReplace
+               if (evt == 'onPlaylistReplace') {
+                       playlist = [];
+                       var index = 0;
+                       each(arg0, function() {
+                               playlist.push(new Clip(this, index++));
+                       });             
+               }
+               
+               var ret = true;
+               
+               // clip event
+               if (arg0 === 0 || (arg0 && arg0 >= 0)) {
+                       
+                       activeIndex = arg0;
+                       var clip = playlist[arg0];                      
+                       
+                       if (clip) {
+                               ret = clip._fireEvent(evt, arg1, arg2); 
+                       } 
+                       
+                       if (!clip || ret !== false) {
+                               
+                               // clip argument is given for common clip, because it behaves as the target
+                               ret = commonClip._fireEvent(evt, arg1, arg2, clip);     
+                       }  
+               } 
+               
+               // player event 
+               var i = 0;
+               each(listeners[evt], function() {
+                       ret = this.call(self, arg0);            
+                       
+                       // remove cached entry
+                       if (this.cached) {
+                               listeners[evt].splice(i, 1);    
+                       }
+                       
+                       // break loop
+                       if (ret === false) { return false;       }
+                       i++;
+                       
+               }); 
+
+               return ret;
+       };
+
+//}}}
+
+// {{{ init
+       
+   function init() {
+               
+               if ($f(wrapper)) {
+                       return null;    
+               }               
+               
+               wrapperHeight = parseInt(wrapper.style.height) || wrapper.clientHeight;
+               
+               // register this player into global array of instances
+               players.push(self);  
+               
+               
+               // flashembed parameters
+               if (typeof params == 'string') {
+                       params = {src: params}; 
+               }       
+               
+               // playerId     
+               playerId = wrapper.id || "fp" + makeId();
+               apiId = params.id || playerId + "_api";          
+               params.id = apiId;
+               conf.playerId = playerId;
+               
+               
+               // plain url is given as config
+               if (typeof conf == 'string') {
+                       conf = {clip:{url:conf}};       
+               } 
+               
+               // common clip is always there
+               conf.clip = conf.clip || {};
+               commonClip = new Clip(conf.clip, -1, self);  
+               
+               
+               // wrapper href as playlist
+               if (wrapper.getAttribute("href")) { 
+                       conf.playlist = [{url:wrapper.getAttribute("href", 2)}];                        
+               } 
+               
+               // playlist
+               conf.playlist = conf.playlist || [conf.clip]; 
+               
+               var index = 0;
+               each(conf.playlist, function() {
+
+                       var clip = this;
+                       
+                       // clip is an array, we don't allow that
+                       if (typeof clip == 'object' && clip.length)  {
+                               clip = "" + clip;       
+                       }
+                       
+                       if (!clip.url && typeof clip == 'string') {                             
+                               clip = {url: clip};                             
+                       } 
+                       
+                       // populate common clip properties to each clip
+                       extend(clip, conf.clip, true);          
+                       
+                       // modify configuration playlist
+                       conf.playlist[index] = clip;                    
+                       
+                       // populate playlist array
+                       clip = new Clip(clip, index, self);
+                       playlist.push(clip);                                            
+                       index++;                        
+               });
+                       
+               
+               // event listeners
+               each(conf, function(key, val) {
+                       if (typeof val == 'function') {
+                               bind(listeners, key, val);
+                               delete conf[key];       
+                       }
+               });              
+               
+               
+               // plugins
+               each(conf.plugins, function(name, val) {
+                       if (val) {
+                               plugins[name] = new Plugin(name, val, self);
+                       }
+               });
+               
+               
+               // setup controlbar plugin if not explicitly defined
+               if (!conf.plugins || conf.plugins.controls === undefined) {
+                       plugins.controls = new Plugin("controls", null, self);  
+               } 
+               
+               // Flowplayer uses black background by default
+               params.bgcolor = params.bgcolor || "#000000";
+               
+               
+               // setup default settings for express install
+               params.version = params.version || [9,0];               
+               params.expressInstall = 'http://www.flowplayer.org/swf/expressinstall.swf';
+               
+               
+               // click function
+               function doClick(e) {
+                       if (self._fireEvent("onBeforeClick") !== false) {
+                               self.load();            
+                       } 
+                       return stopEvent(e);                                    
+               }
+               
+               // defer loading upon click
+               html = wrapper.innerHTML;
+               if (html.replace(/\s/g, '') !== '') {    
+                       
+                       if (wrapper.addEventListener) {
+                               wrapper.addEventListener("click", doClick, false);      
+                               
+                       } else if (wrapper.attachEvent) {
+                               wrapper.attachEvent("onclick", doClick);        
+                       }
+                       
+               // player is loaded upon page load 
+               } else {
+                       
+                       // prevent default action from wrapper (safari problem) loaded
+                       if (wrapper.addEventListener) {
+                               wrapper.addEventListener("click", stopEvent, false);    
+                       }
+                       
+                       // load player
+                       self.load();
+               }
+               
+       }
+
+       // possibly defer initialization until DOM get's loaded
+       if (typeof wrapper == 'string') { 
+               flashembed.domReady(function() {
+                       var node = el(wrapper); 
+                       
+                       if (!node) {
+                               throw "Flowplayer cannot access element: " + wrapper;   
+                       } else {
+                               wrapper = node; 
+                               init();                                 
+                       } 
+               });
+               
+       // we have a DOM element so page is already loaded
+       } else {                
+               init();
+       }
+       
+       
+//}}}
+
+
+}
+
+
+// {{{ flowplayer() & statics 
+
+// container for player instances
+var players = [];
+
+
+// this object is returned when multiple player's are requested 
+function Iterator(arr) {
+       
+       this.length = arr.length;
+       
+       this.each = function(fn)  {
+               each(arr, fn);  
+       };
+       
+       this.size = function() {
+               return arr.length;      
+       };      
+}
+
+// these two variables are the only global variables
+window.flowplayer = window.$f = function() {
+       
+       var instance = null;
+       var arg = arguments[0]; 
+       
+       
+       // $f()
+       if (!arguments.length) {
+               each(players, function() {
+                       if (this.isLoaded())  {
+                               instance = this;        
+                               return false;
+                       }
+               });
+               
+               return instance || players[0];
+       } 
+       
+       if (arguments.length == 1) {
+               
+               // $f(index);
+               if (typeof arg == 'number') { 
+                       return players[arg];    
+       
+                       
+               // $f(wrapper || 'containerId' || '*');
+               } else {
+                       
+                       // $f("*");
+                       if (arg == '*') {
+                               return new Iterator(players);   
+                       }
+                       
+                       // $f(wrapper || 'containerId');
+                       each(players, function() {
+                               if (this.id() == arg.id || this.id() == arg || this.getParent() == arg)  {
+                                       instance = this;        
+                                       return false;
+                               }
+                       });
+                       
+                       return instance;                                        
+               }
+       }                        
+
+       // instance builder 
+       if (arguments.length > 1) {             
+
+               var swf = arguments[1];
+               var conf = (arguments.length == 3) ? arguments[2] : {};
+                                               
+               if (typeof arg == 'string') {
+                       
+                       // select arg by classname
+                       if (arg.indexOf(".") != -1) {
+                               var instances = [];
+                               
+                               each(select(arg), function() { 
+                                       instances.push(new Player(this, clone(swf), clone(conf)));               
+                               });     
+                               
+                               return new Iterator(instances);
+                               
+                       // select node by id
+                       } else {                
+                               var node = el(arg);
+                               return new Player(node !== null ? node : arg, swf, conf);         
+                       } 
+                       
+                       
+               // arg is a DOM element
+               } else if (arg) {
+                       return new Player(arg, swf, conf);                                              
+               }
+               
+       } 
+       
+       return null; 
+};
+       
+extend(window.$f, {
+
+       // called by Flash External Interface            
+       fireEvent: function(id, evt, a0, a1, a2) {              
+               var p = $f(id);         
+               return p ? p._fireEvent(evt, a0, a1, a2) : null;
+       },
+       
+       
+       // create plugins by modifying Player's prototype
+       addPlugin: function(name, fn) {
+               Player.prototype[name] = fn;
+               return $f;
+       },
+       
+       // utility methods for plugin developers
+       each: each,
+       
+       extend: extend
+       
+});
+       
+//}}}
+
+
+//{{{ jQuery support
+
+if (typeof jQuery == 'function') {
+       
+       jQuery.prototype.flowplayer = function(params, conf) {  
+               
+               // select instances
+               if (!arguments.length || typeof arguments[0] == 'number') {
+                       var arr = [];
+                       this.each(function()  {
+                               var p = $f(this);
+                               if (p) {
+                                       arr.push(p);    
+                               }
+                       });
+                       return arguments.length ? arr[arguments[0]] : new Iterator(arr);
+               }
+               
+               // create flowplayer instances
+               return this.each(function() { 
+                       $f(this, clone(params), conf ? clone(conf) : {});       
+               }); 
+               
+       };
+       
+}
+
+//}}}
+
+
+})();
+/** 
+ * flashembed 0.34. Adobe Flash embedding script
+ * 
+ * http://flowplayer.org/tools/flash-embed.html
+ *
+ * Copyright (c) 2008 Tero Piirainen (support@flowplayer.org)
+ *
+ * Released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * 
+ * >> Basically you can do anything you want but leave this header as is <<
+ *
+ * first version 0.01 - 03/11/2008 
+ * version 0.34 - Tue Nov 11 2008 09:09:52 GMT-0000 (GMT+00:00)
+ */
+(function() { 
+//{{{ utility functions 
+               
+var jQ = typeof jQuery == 'function';
+
+
+// from "Pro JavaScript techniques" by John Resig
+function isDomReady() {
+       
+       if (domReady.done)  { return false; }
+       
+       var d = document;
+       if (d && d.getElementsByTagName && d.getElementById && d.body) {
+               clearInterval(domReady.timer);
+               domReady.timer = null;
+               
+               for (var i = 0; i < domReady.ready.length; i++) {
+                       domReady.ready[i].call();       
+               }
+               
+               domReady.ready = null;
+               domReady.done = true;
+       } 
+}
+
+// if jQuery is present, use it's more effective domReady method
+var domReady = jQ ? jQuery : function(f) {
+       
+       if (domReady.done) {
+               return f();     
+       }
+       
+       if (domReady.timer) {
+               domReady.ready.push(f); 
+               
+       } else {
+               domReady.ready = [f];
+               domReady.timer = setInterval(isDomReady, 13);
+       } 
+};     
+
+
+// override extend params function 
+function extend(to, from) {
+       if (from) {
+               for (key in from) {
+                       if (from.hasOwnProperty(key)) {
+                               to[key] = from[key];
+                       }
+               }
+       }
+       
+       return to;
+}      
+
+
+function concatVars(vars) {            
+       var out = "";
+       
+       for (var key in vars) { 
+               if (vars[key]) {
+                       out += [key] + '=' + asString(vars[key]) + '&';
+               }
+       }                       
+       return out.substring(0, out.length -1);                         
+}  
+
+
+
+// JSON.asString() function
+function asString(obj) {
+
+       switch (typeOf(obj)){
+               case 'string':
+                       obj = obj.replace(new RegExp('(["\\\\])', 'g'), '\\$1');
+                       
+                       // flash does not handle %- characters well. transforms "50%" to "50pct" (a dirty hack, I admit)
+                       obj = obj.replace(/^\s?(\d+)%/, "$1pct");
+                       return '"' +obj+ '"';
+                       
+               case 'array':
+                       return '['+ map(obj, function(el) {
+                               return asString(el);
+                       }).join(',') +']'; 
+                       
+               case 'function':
+                       return '"function()"';
+                       
+               case 'object':
+                       var str = [];
+                       for (var prop in obj) {
+                               if (obj.hasOwnProperty(prop)) {
+                                       str.push('"'+prop+'":'+ asString(obj[prop]));
+                               }
+                       }
+                       return '{'+str.join(',')+'}';
+       }
+       
+       // replace ' --> "  and remove spaces
+       return String(obj).replace(/\s/g, " ").replace(/\'/g, "\"");
+}
+
+
+// private functions
+function typeOf(obj) {
+       if (obj === null || obj === undefined) { return false; }
+       var type = typeof obj;
+       return (type == 'object' && obj.push) ? 'array' : type;
+}
+
+
+// version 9 bugfix: (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
+if (window.attachEvent) {
+       window.attachEvent("onbeforeunload", function() {
+               __flash_unloadHandler = function() {};
+               __flash_savedUnloadHandler = function() {};
+       });
+}
+
+function map(arr, func) {
+       var newArr = []; 
+       for (var i in arr) {
+               if (arr.hasOwnProperty(i)) {
+                       newArr[i] = func(arr[i]);
+               }
+       }
+       return newArr;
+}
+       
+function getEmbedCode(p, c) {
+       var html = '<embed type="application/x-shockwave-flash" ';
+
+       if (p.id) { extend(p, {name:p.id}); }
+       
+       for (var key in p) { 
+               if (p[key] !== null) { 
+                       html += key + '="' +p[key]+ '"\n\t';
+               }
+       }
+
+       if (c) {
+                html += 'flashvars=\'' + concatVars(c) + '\'';
+       }
+       
+       // thanks Tom Price (07/17/2008)
+       html += '/>';
+       
+       return html;
+}
+
+function getObjectCode(p, c, embeddable) {
+       
+       var html = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ';
+       html += 'width="' + p.width + '" height="' + p.height + '"'; 
+       
+       // force id for IE. otherwise embedded Flash object cannot be returned
+       if (!p.id && document.all) {
+               p.id = "_" + ("" + Math.random()).substring(5);
+       } 
+       
+       if (p.id) {
+               html += ' id="' + p.id + '"';
+       }
+       
+       html += '>';  
+       
+       // sometimes ie fails to load flash if it's on cache
+       if (document.all) {
+               p.src += ((p.src.indexOf("?") != -1 ? "&" : "?") + Math.random());              
+       } 
+       
+       html += '\n\t<param name="movie" value="'+ p.src +'" />';
+
+       var e = extend({}, p);
+       e.id = e.width = e.height = e.src = null;
+       
+       for (var k in e) {
+               if (e[k] !== null) {
+                       html += '\n\t<param name="'+ k +'" value="'+ e[k] +'" />';
+               }
+       }
+       
+       if (c) {
+               html += '\n\t<param name="flashvars" value=\'' + concatVars(c) + '\' />';
+       }
+       
+       if (embeddable) {
+               html += getEmbedCode(p, c);     
+       }
+        
+       html += "</object>";
+       
+       return html;
+}
+
+function getFullHTML(p, c) {
+       return getObjectCode(p, c, true);       
+}
+
+function getHTML(p, c) { 
+       var isNav = navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length; 
+       return (isNav) ? getEmbedCode(p, c) : getObjectCode(p, c);
+}
+
+//}}}
+
+       
+window.flashembed = function(root, userParams, flashvars) {    
+       
+       
+//{{{ construction
+               
+       // setup params
+       var params = {
+               
+               // very common params
+               src: '#',
+               width: '100%',
+               height: '100%',         
+               
+               // flashembed specific options
+               version:null,
+               onFail:null,
+               expressInstall:null,  
+               debug: false,
+               
+               // flashembed defaults
+               // bgcolor: 'transparent',
+               allowfullscreen: true,
+               allowscriptaccess: 'always',
+               quality: 'high',
+               type: 'application/x-shockwave-flash',
+               pluginspage: 'http://www.adobe.com/go/getflashplayer'
+       };
+       
+       
+       if (typeof userParams == 'string') {
+               userParams = {src: userParams}; 
+       }
+       
+       extend(params, userParams);                      
+               
+       var version = flashembed.getVersion(); 
+       var required = params.version; 
+       var express = params.expressInstall;             
+       var debug = params.debug;
+
+       
+       if (typeof root == 'string') {
+               var el = document.getElementById(root);
+               if (el) {
+                       root = el;      
+               } else {
+                       domReady(function() {
+                               flashembed(root, userParams, flashvars);
+                       });
+                       return;          
+               } 
+       }
+       
+       if (!root) { return; }
+
+       
+       // is supported 
+       if (!required || flashembed.isSupported(required)) {
+               params.onFail = params.version = params.expressInstall = params.debug = null;
+               
+               // root.innerHTML may cause broplems: http://domscripting.com/blog/display/99
+               // thanks to: Ryan Rud
+               // var tmp = document.createElement("extradiv");
+               // tmp.innerHTML = getHTML();
+               // root.appendChild(tmp);
+               
+               root.innerHTML = getHTML(params, flashvars);
+               
+               // return our API                       
+               return root.firstChild;
+               
+       // custom fail event
+       } else if (params.onFail) {
+               var ret = params.onFail.call(params, flashembed.getVersion(), flashvars);
+               if (ret === true) { root.innerHTML = ret; }             
+               
+
+       // express install
+       } else if (required && express && flashembed.isSupported([6,65])) {
+               
+               extend(params, {src: express});
+               
+               flashvars = {
+                       MMredirectURL: location.href,
+                       MMplayerType: 'PlugIn',
+                       MMdoctitle: document.title
+               };
+               
+               root.innerHTML = getHTML(params, flashvars);    
+               
+       // not supported
+       } else {
+
+               // minor bug fixed here 08.04.2008 (thanks JRodman)
+               
+               if (root.innerHTML.replace(/\s/g, '') !== '') {
+                       // custom content was supplied
+               
+               } else {
+                       root.innerHTML = 
+                               "<h2>Flash version " + required + " or greater is required</h2>" + 
+                               "<h3>" + 
+                                       (version[0] > 0 ? "Your version is " + version : "You have no flash plugin installed") +
+                               "</h3>" + 
+                               "<p>Download latest version from <a href='" + params.pluginspage + "'>here</a></p>";
+               }
+       }
+
+       return root;
+       
+//}}}
+       
+       
+};
+
+
+//{{{ static methods
+
+extend(window.flashembed, {
+
+       // returns arr[major, fix]
+       getVersion: function() {
+       
+               var version = [0, 0];
+               
+               if (navigator.plugins && typeof navigator.plugins["Shockwave Flash"] == "object") {
+                       var _d = navigator.plugins["Shockwave Flash"].description;
+                       if (typeof _d != "undefined") {
+                               _d = _d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
+                               var _m = parseInt(_d.replace(/^(.*)\..*$/, "$1"), 10);
+                               var _r = /r/.test(_d) ? parseInt(_d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
+                               version = [_m, _r];
+                       }
+                       
+               } else if (window.ActiveXObject) {
+                       
+                       try { // avoid fp 6 crashes
+                               var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
+                               
+                       } catch(e) {
+                               try { 
+                                       _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
+                                       version = [6, 0];
+                                       _a.AllowScriptAccess = "always"; // throws if fp < 6.47 
+                                       
+                               } catch(ee) {
+                                       if (version[0] == 6) { return; }
+                               }
+                               try {
+                                       _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
+                               } catch(eee) {
+                               
+                               }
+                               
+                       }
+                       
+                       if (typeof _a == "object") {
+                               _d = _a.GetVariable("$version"); // bugs in fp 6.21 / 6.23
+                               if (typeof _d != "undefined") {
+                                       _d = _d.replace(/^\S+\s+(.*)$/, "$1").split(",");
+                                       version = [parseInt(_d[0], 10), parseInt(_d[2], 10)];
+                               }
+                       }
+               } 
+               
+               return version;
+       },
+       
+       isSupported: function(version) {
+               var now = flashembed.getVersion();
+               var ret = (now[0] > version[0]) || (now[0] == version[0] && now[1] >= version[1]);                      
+               return ret;
+       },
+       
+       domReady: domReady,
+       
+       // returns a String representation from JSON object 
+       asString: asString,
+       
+       getHTML: getHTML,
+       
+       getFullHTML: getFullHTML
+       
+});
+
+//}}}
+
+
+// setup jquery support
+if (jQ) {
+       
+       jQuery.prototype.flashembed = function(params, flashvars) { 
+               return this.each(function() { 
+                       flashembed(this, params, flashvars);
+               });
+       };
+
+}
+
+})();
+
+/************************************************
+********* mv_embed extension to flowplayer.js ***
+************************************************/       
+var flashEmbed = {
+       instanceOf:'flashEmbed',
+       monitorTimerId : 0,
+       old_pid:0,
+       didSeekJump:false,
+       startedTimedPlayback:false,             
+       didDateStartTimeRestore:false,
+       supports: {
+               'play_head':true, 
+               'pause':true,
+               'stop':true, 
+               //'fullscreen':true, 
+               'time_display':true, 
+               'volume_control':true,
+               'overlay':false,
+               'fullscreen':false
+       },
+       getEmbedHTML: function (){
+               setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
+               return this.wrapEmebedContainer( this.getEmbedObj() );
+       },
+       getEmbedObj:function(){ 
+               //give the embed element a unique pid (work around for flowplayer persistence)
+               if( this.old_pid!=0 ){
+                       this.pid = this.pid +'_'+ this.old_pid;
+               }                               
+               return '<a  '+
+                                       'href="'+ this.getSrc() + '" '+  
+                                       'style="display:block;width:' + parseInt(this.width) + 'px;height:' + parseInt(this.height) + 'px" '+  
+                                       'id="'+this.pid+'">'+ 
+                               '</a>';
+       },
+       postEmbedJS: function()
+       {   
+               var _this = this;
+               js_log('embedFlow: uri:'+ this.getSrc() + "\n"+ mv_embed_path + 'binPlayers/flowplayer/flowplayer-3.0.1.swf' ) ;
+               var flowConfig = { 
+                       clip: { 
+                               url: this.getSrc(),                               
+                               // when this is false playback does not start until play button is pressed 
+                               autoPlay: true
+                       },
+                       plugins: { 
+                               controls: { 
+                                  all: false, 
+                                  fullscreen: true,
+                                  backgroundColor: 'transparent',
+                                  backgroundGradient: 'none',
+                                  autoHide:'always',
+                                  top:'95%',
+                                  right:'0px'
+                               }                                
+                       },
+                       screen: {
+                               opacity : '1.0'
+                       }                       
+               };
+               
+               //if in preview mode set grey and lower volume until "ready"
+               if( this.preview_mode ){
+                       flowConfig.screen.opacity = 0.2;                                 
+               }                                       
+               
+               $f(this.pid,  mv_embed_path + 'binPlayers/flowplayer/flowplayer-3.0.1.swf', flowConfig);                                  
+               //get the this.fla value:                
+               this.getFLA();          
+               //set up bindings (for when interacting with the swf causes action:  
+               this.fla.onPause(function(){                                                                                                                            
+                       _this.parent_pause();   //update the interface                   
+               })
+               this.fla.onResume( function(){
+                       _this.parent_play();    //update the interface  
+               });                             
+                  
+               //start monitor: 
+               this.monitor();  
+               this.old_pid++;
+       },   
+       /* js hooks/controls */
+       play: function(){                               
+               this.getFLA();          
+               //update play/pause button etc
+               this.parent_play();                             
+               if( this.fla ){                 
+                       this.fla.play();                        
+                       
+                       //on a resume make sure volume and opacity are correct 
+                       this.restorePlayer();                                            
+                       setTimeout('$j(\'#'+this.id+'\').get(0).monitor()', 250);
+               }
+       },
+       //@@todo support mute
+       toggleMute: function(){
+               this.parent_toggleMute();
+               this.getFLA();
+               if(this.fla){
+                       if(this.muted){
+                               
+                       }else{
+                               
+                       }
+               }
+       },
+       //@@ Suport UpDateVolumen 
+       updateVolumen:function(perc){
+               this.getFLA();          
+               if(this.fla)this.fla.setVolume(perc*100);
+                           
+    }, 
+    //@@ Get Volumen
+       getVolumen:function(){
+               this.getFLA();          
+               if(this.fla)
+                       return this.fla.getVolume() / 100;                         
+    }, 
+       fullscreen:function(){
+               if(this.fla){
+                       this.fla.fullscreen();
+               }else{
+                       js_log('must be playing before you can go fullscreen');
+               }
+       },
+       pause : function()
+       {
+               this.getFLA();
+               if(!this.thumbnail_disp){
+                       this.parent_pause();
+                       if(this.fla){           
+                               js_log("Flash:Pause: " + this.fla.isPaused() );
+                               if( this.fla['pause'] ){
+                                       if( ! this.fla.isPaused() ){
+                                               js_log('calling plugin pause');                         
+                                               this.fla.pause();  
+                                               
+                                               //restore volume and opacity 
+                                               this.restorePlayer();              
+                                       }
+                               }
+                       }
+               }
+       },
+       monitor : function()
+       {                       
+               var _this = this;
+               //date time
+               if( !this.dateStartTime ){
+                       var d = new Date();
+                       this.dateStartTime = d.getTime();
+                       
+               }else{
+                       var d = new Date();                                              
+                       if( !this.didDateStartTimeRestore  && this.preview_mode)
+                               this.fla.setVolume(0);
+                               
+                       if( (d.getTime() - this.dateStartTime) > 6000  && !this.didDateStartTimeRestore){                                                        
+                               this.restorePlayer(); 
+                       }
+               }                                         
+                                         
+               var flash_state = this.fla.getStatus();
+               //update the duration from the clip if its zero or not set: 
+               if( !this.duration || this.duration==0 ){
+                       if( this.fla.getClip() ){
+                               this.duration = this.fla.getClip().fullDuration;                                
+                               js_log('set duration via clip value: ' + this.getDuration() );
+                       }
+               }
+               //update the duration ntp values: 
+               this.getDuration();             
+
+               if( typeof flash_state == 'undefined' ){
+                        var flash_state = {
+                                "time" : this.fla.getTime()
+                        };                              
+                       //we are not getting buffered data restore volume and opacity
+                       this.restorePlayer();                                              
+               }else{
+                       //simplification of buffer state ... should move to support returning time rages like:
+                       //http://www.whatwg.org/specs/web-apps/current-work/#normalized-timeranges-object                       
+                       this.bufferedPercent = flash_state.bufferEnd / this.getDuration();                                                                      
+               }                          
+               //set the current Time (based on timeFormat)            
+               if( this.supportsURLTimeEncoding() ){
+                       this.currentTime = flash_state.time;                      
+                       //js_log('set buffer: ' + flash_state.bufferEnd + ' at time: ' + flash_state.time +' of total dur: ' + this.getDuration()); 
+               }else{
+                       this.currentTime = flash_state.time + this.start_offset;                                                
+                       //stop buffering if greater than the duration: 
+                       if( flash_state.bufferEnd > this.getDuration() + 5 ){
+                               //js_log('should stop buffering (does not seem to work)' + flash_state.bufferEnd + ' > dur: ' + this.getDuration() );
+                               this.fla.stopBuffering();
+                       } 
+               }                                 
+               
+               if(this.currentTime > npt2seconds(this.start_ntp) && !this.startedTimedPlayback){
+                       var fail = false;
+                       try
+                       {
+                               this.restorePlayer();                           
+                       }
+                       catch(err)
+                       {
+                               js_log('failed to set values');
+                               fail = true;
+                       }
+                       if(!fail)
+                               this.startedTimedPlayback=true;                                                                          
+               }
+               
+               /* to support local seeks */
+               if(this.currentTime > 1 && this.seek_time_sec != 0 && !this.supportsURLTimeEncoding() )
+               {
+                       js_log('flashEmbed: _local_ Seeking to ' + this.seek_time_sec);
+                       this.fla.seek( this.seek_time_sec );
+                       this.seek_time_sec = 0;
+               }                                               
+               
+               //checks to see if we reached the end of playback:                              
+               if(this.duration && this.startedTimedPlayback && 
+                       (        this.currentTime > (npt2seconds(this.end_ntp)+2) 
+                               || 
+                               ( this.currentTime > (npt2seconds(this.end_ntp)-1) 
+                                       && this.prevTime == this.currentTime) )
+                       ){                                                      
+                       js_log('prbally reached end of stream: '+ seconds2npt( this.currentTime) );
+                       this.onClipDone();                                
+               }               
+               
+               //update the status and check timmer via universal parent monitor
+               this.parent_monitor();
+               
+               
+               this.prevTime = this.currentTime;       
+               //js_log('cur perc loaded: ' + this.fla.getPercentLoaded() +' cur time : ' + (this.currentTime - npt2seconds(this.start_ntp)) +' / ' +(npt2seconds(this.end_ntp)-npt2seconds(this.start_ntp)));
+       },
+       restorePlayer:function(){               
+               if(!this.fla)
+                       this.getFLA();
+               if(this.fla){
+                       js_log('f:do restorePlayer');
+                       this.fla.setVolume(90); 
+                       $f().getPlugin('screen').css({'opacity':'1.0'} );
+                       //set the fallback date restore flag to true:
+                       this.didDateStartTimeRestore=true;                                
+               }               
+       },
+       // get the embed fla object 
+       getFLA : function (){
+               this.fla = $f(this.pid);                   
+       },
+       stop : function(){      
+               js_log('f:flashEmbed:stop');            
+               this.startedTimedPlayback=false;        
+               if (this.monitorTimerId != 0 )
+               {
+                       clearInterval(this.monitorTimerId);
+                       this.monitorTimerId = 0;
+               }
+               if(this.fla)
+                       this.fla.unload();
+               this.parent_stop();
+       },
+       onStop: function(){
+               js_log('f:onStop');
+               //stop updates: 
+               if( this.monitorTimerId != 0 )
+               {
+                       clearInterval(this.monitorTimerId);
+                       this.monitorTimerId = 0;
+               }
+       },
+       onClipDone: function(){                 
+               js_log('f:flash:onClipDone');           
+               if( ! this.startedTimedPlayback){
+                       js_log('clip done before timed playback started .. not good. (ignoring) ');                     
+                       //keep monitoring: 
+                       this.monitor();
+               }else{
+                       js_log('clip done and '+ this.startedTimedPlayback);
+                       //stop the clip if its not stopped already:
+                       this.stop();
+                       this.setStatus("Clip Done...");
+                       //run the onClip done action: 
+                       this.parent_onClipDone();
+               }
+       }
+};
diff --git a/js2/mwEmbed/libEmbedVideo/genericEmbed.js b/js2/mwEmbed/libEmbedVideo/genericEmbed.js
new file mode 100644 (file)
index 0000000..5f65868
--- /dev/null
@@ -0,0 +1,17 @@
+/* the most simple implementation used for unknown application/ogg plugin */
+var genericEmbed={
+        supports: {
+               'play_head':false, 
+               'pause':false, 
+               'stop':true, 
+               'fullscreen':false, 
+               'time_display':false, 
+               'volume_control':false
+       },
+       instanceOf:'genericEmbed',
+       getEmbedHTML:function(){
+               return '<object type="application/ogg" '+
+                                 'width="'+this.width+'" height="'+this.height+'" ' +
+                                 'data="' + this.getURI( this.seek_time_sec ) + '"></object>';
+       }
+};
\ No newline at end of file
diff --git a/js2/mwEmbed/libEmbedVideo/htmlEmbed.js b/js2/mwEmbed/libEmbedVideo/htmlEmbed.js
new file mode 100644 (file)
index 0000000..70d1af8
--- /dev/null
@@ -0,0 +1,181 @@
+/* 
+ * used to embed HTML as a movie clip 
+ * for use with mv_playlist SMIL additions 
+ * (we make assumptions about this.pc (parent clip) being available)
+ */
+var pcHtmlEmbedDefaults={
+       'dur':4 //default duration of 4 seconds
+}
+var htmlEmbed ={
+        supports: {
+               'play_head':true, 
+               'pause':true,            
+               'fullscreen':false, 
+               'time_display':true, 
+               'volume_control':true,
+               
+               'overlays':true,
+               'playlist_swap_loader':true //if the object supports playlist functions         
+          },
+          ready_to_play:true,
+          pauseTime:0,
+          currentTime:0,
+          start_offset:0,
+          monitorTimerId:false,
+       play:function(){
+               //call the parent
+               this.parent_play();
+               
+               js_log('f:play: htmlEmbedWrapper');
+               var ct = new Date();    
+               this.clockStartTime = ct.getTime();
+                       
+               //start up monitor: 
+               this.monitor();                         
+       },
+       stop:function(){
+               this.pause();
+               //window.clearInterval( this.monitorTimerId );
+       },
+       pause:function(){
+               js_log('f:pause: htmlEmbedWrapper');
+               var ct = new Date();
+               this.pauseTime = this.currentTime;
+               js_log('pause time: '+ this.pauseTime);                         
+               
+               window.clearInterval( this.monitorTimerId );
+       },
+       //monitor just needs to keep track of time (do it at frame rate time) . 
+       monitor:function(){     
+               //js_log('html:monitor: '+ this.currentTime);
+               var ct = new Date();    
+               this.currentTime =( ( ct.getTime() - this.clockStartTime )/1000 ) +this.pauseTime;
+               var ct = new Date();    
+               //js_log('mvPlayList:monitor trueTime: '+ this.currentTime);                                                                            
+               
+               if( ! this.monitorTimerId ){
+                       if(document.getElementById(this.id)){
+                               if( !MV_ANIMATION_CB_RATE )
+                                       var MV_ANIMATION_CB_RATE= 33;                                   
+                               this.monitorTimerId = window.setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
+                       }
+               }
+       },
+       //set up minimal media_element emulation:        
+       media_element:{
+               autoSelectSource:function(){
+                       return true;
+               },              
+               selectedPlayer:{
+                       library:"html"
+               },
+               selected_source:{
+                       URLTimeEncoding:false                   
+               },
+               timedTextSources:function(){
+                       return false;
+               }
+       },
+       inheritEmbedObj:function(){
+               return true;
+       },
+       renderTimelineThumbnail:function( options ){
+               js_log("HTMLembed req w, height: " + options.width + ' ' + options.height);
+               //generate a scaled down version _that_ we can clone if nessisary  
+               //add a not vissiable container to the body:            
+               var do_refresh = (typeof options['refresh'] != 'undefined')?true:false;
+               
+               var thumb_render_id =   this.id +'_thumb_render_'+ options.height;
+               if( $j('#' + thumb_render_id ).length == 0  ||  do_refresh ){
+                       //set the font scale down percentage: (kind of arbitrary) 
+                       var scale_perc = options.width / this.pc.pp.width;
+                       js_log('scale_perc:'+options.width + ' / '+ $j(this).width()+ ' = '+scale_perc );                       
+                       //min scale font percent of 70 (overflow is hidden) 
+                       var font_perc  = ( Math.round( scale_perc*100 ) < 80 ) ? 80 : Math.round( scale_perc*100 );              
+                       var thumb_class = (typeof options['thumb_class'] !='undefined')? options['thumb_class'] : '';                   
+                       $j('body').append( '<div id="' + thumb_render_id + '" style="display:none">'+
+                                                                       '<div class="' + thumb_class + '" '+ 
+                                                                       'style="width:'+options.width+'px;height:'+options.height+'px;" >'+                                                                             
+                                                                                       this.getThumbnailHTML({
+                                                                                               'width':  options.width,
+                                                                                               'height': options.height
+                                                                                       }) + 
+                                                                       '</div>' +
+                                                               '</div>' 
+                                                         );
+                       //scale down the fonts:         
+                       $j('#' + thumb_render_id + ' *').filter('span,div,p,h,h1,h2,h3,h4,h5,h6').css('font-size',font_perc+'%')
+                       
+                       //replace out links:
+                       $j('#' + thumb_render_id +' a').each(function(){
+                               $j(this).replaceWith("<span>" + $j(this).html() + "</span>");
+                       });     
+                       
+                       //scale images that have width or height:
+                       $j('#' + thumb_render_id + ' img').filter('[width]').each(function(){                                                           
+                               $j(this).attr({ 
+                                               'width': Math.round( $j(this).attr('width') * scale_perc ),
+                                               'height': Math.round( $j(this).attr('height') * scale_perc )
+                                        } 
+                               );                              
+                       });
+               }                        
+               return $j('#' + thumb_render_id ).html();                          
+       },
+       //nothing to update in static html display: (return a static representation) 
+       //@@todo render out a mini text "preview"
+       updateThumbTime:function( float_time ){
+               return ;
+       },      
+       getEmbedHTML:function(){
+               js_log('f:html:getEmbedHTML: ' + this.id);
+               //set up the css for our parent div:             
+               $j(this).css({'width':this.pc.pp.width, 'height':this.pc.pp.height, 'overflow':"hidden"});
+               //@@todo support more smil animation layout stuff: 
+               
+               //wrap output in videoPlayer_ div:
+               $j(this).html('<div id="videoPlayer_'+ this.id+'">'+this.getThumbnailHTML()+'</div>');
+       },
+       getThumbnailHTML:function( opt ){
+               var out='';
+               if(!opt)
+                       opt = {};                       
+               var height = (opt.height)?opt.height:this.pc.pp.height;
+               var width = (opt.width)?opt.width: this.pc.pp.width;    
+               js_log('1req '+ opt.height + ' but got: ' + height);    
+               if( this.pc.type =='image/jpeg'){
+                       js_log('should put src: '+this.pc.src);
+                       out = '<img style="width:'+width+'px;height:'+height+'px" src="'+this.pc.src+'">';
+               }else{
+                       out = this.pc.wholeText;
+               }
+               //js_log('f:getThumbnailHTML: got thumb: '+out);
+               return out;
+       },
+       doThumbnailHTML:function(){
+               js_log('f:htmlEmbed:doThumbnailHTML');
+               this.getEmbedHTML();
+       },
+       /* since its just html display get the "embed" right away */
+       getHTML:function(){
+               js_log('getHTML: htmlEmbed');
+               this.getEmbedHTML();
+       },
+       getDuration:function(){
+               if(this.pc.dur)
+                       return this.pc.dur;
+               //return default value:  
+               return pcHtmlEmbedDefaults.dur;         
+       },
+       updateVideoTime:function(start_ntp, end_ntp){
+               //since we don't really have timeline for html elements just take the delta and set it as the duration
+               this.pc.dur = npt2seconds(end_ntp) - npt2seconds(start_ntp);                    
+       },      
+       //gives a chance to make any nesseary external requests
+       //@@todo we can "start loading images" if we want
+       on_dom_swap:function(){
+               this.loading_external_data=false
+               this.ready_to_play=true;                                
+               return ;                
+       }       
+};
\ No newline at end of file
diff --git a/js2/mwEmbed/libEmbedVideo/javaEmbed.js b/js2/mwEmbed/libEmbedVideo/javaEmbed.js
new file mode 100644 (file)
index 0000000..f3409e1
--- /dev/null
@@ -0,0 +1,187 @@
+window.cortadoDomainLocations = {
+       'upload.wikimedia.org'  : 'http://upload.wikimedia.org/jars/cortado.jar',
+       'tinyvid.tv'                    : 'http://tinyvid.tv/static/cortado.jar',
+       'media.tinyvid.tv'              : 'http://media.tinyvid.tv/cortado.jar'
+} 
+
+var javaEmbed = {
+       instanceOf:'javaEmbed',
+       iframe_src:'',
+       logged_domain_error:false,
+       supports: {
+               'play_head':true, 
+               'pause':true, 
+               'stop':true, 
+               'fullscreen':false, 
+               'time_display':true, 
+               'volume_control':false
+       },
+       getEmbedHTML : function (){
+               //big delay on embed html cuz its just for status updates and ie6 is crazy. 
+               if(this.controls)
+                       setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 500);
+               //set a default duration of 30 seconds: cortao should detect duration.
+               return this.wrapEmebedContainer( this.getEmbedObj() );
+       },
+       getEmbedObj:function(){ 
+               js_log("java play url:" + this.getURI( this.seek_time_sec ));
+               //get the duration
+               this.getDuration();
+               //if still unset set to an arbitrary time 60 seconds: 
+               if(!this.duration)this.duration=60;
+               //@@todo we should have src property in our base embed object
+               var mediaSrc = this.getSrc();
+               
+               if(mediaSrc.indexOf('://')!=-1 & parseUri(document.URL).host !=  parseUri(mediaSrc).host){
+                       if(window.cortadoDomainLocations[parseUri(mediaSrc).host]){
+                               applet_loc =  window.cortadoDomainLocations[parseUri(mediaSrc).host];
+                       }else{
+                               applet_loc  = 'http://theora.org/cortado.jar';
+                       }
+               }else{
+                       //should be identical to cortado.jar
+                       applet_loc = mv_embed_path+'binPlayers/cortado/cortado.jar';
+               }
+                       //load directly in the page..
+                       // (media must be on the same server or applet must be signed)
+                       var appplet_code = ''+
+                       '<applet id="' + this.pid + '" code="com.fluendo.player.Cortado.class" archive="' + applet_loc + '" width="' + this.width + '" height="' + this.height + '">    '+ "\n"+
+                               '<param name="url" value="' + mediaSrc + '" /> ' + "\n"+
+                               '<param name="local" value="false"/>'+ "\n"+
+                               '<param name="keepaspect" value="true" />'+ "\n"+
+                               '<param name="video" value="true" />'+"\n"+
+                               '<param name="showStatus" value="hide" />' + "\n"+
+                               '<param name="audio" value="true" />'+"\n"+
+                               '<param name="seekable" value="true" />'+"\n"+
+                               '<param name="duration" value="' + this.duration + '" />'+"\n"+
+                               '<param name="bufferSize" value="4096" />'+"\n"+
+                       '</applet>';                                                            
+                                                                       
+                       // Wrap it in an iframe to avoid hanging the event thread in FF 2/3 and similar
+                       // Doesn't work in MSIE or Safari/Mac or Opera 9.5
+                       if ( embedTypes.mozilla ) {
+                               var iframe = document.createElement( 'iframe' );
+                               iframe.setAttribute( 'width', params.width );
+                               iframe.setAttribute( 'height', playerHeight );
+                               iframe.setAttribute( 'scrolling', 'no' );
+                               iframe.setAttribute( 'frameborder', 0 );
+                               iframe.setAttribute( 'marginWidth', 0 );
+                               iframe.setAttribute( 'marginHeight', 0 );
+                               iframe.setAttribute( 'id', 'cframe_' + this.id)
+                               elt.appendChild( iframe );
+                               var newDoc = iframe.contentDocument;
+                               newDoc.open();
+                               newDoc.write( '<html><body>' + appplet_code + '</body></html>' );
+                               newDoc.close(); // spurious error in some versions of FF, no workaround known
+                       } else {
+                               return appplet_code;
+                       }
+       }, 
+       postEmbedJS:function(){
+               //reset logged domain error flag:
+               this.logged_domain_error = false;
+               //start monitor: 
+               this.monitor();
+       },
+       monitor:function(){
+               this.getJCE()   
+               if(this.jce && this.jce.getPlayPosition){                 
+                       try{                                     
+                          //java reads ogg media time.. so no need to add the start or seek offset:
+                          //js_log(' ct: ' + this.jce.getPlayPosition() + ' ' +  this.supportsURLTimeEncoding());                                                                                                 
+                          this.currentTime = this.jce.getPlayPosition();       
+                          if( this.jce.getPlayPosition() < 0){
+                                       js_log('pp:'+this.jce.getPlayPosition());                                
+                                       //probably reached clip end 
+                                       this.onClipDone();
+                          }                                              
+                       }catch (e){
+                          js_log('could not get time from jPlayer: ' + e);
+                       }                                                       
+               }  
+               //once currentTime is updated call parent_monitor 
+               this.parent_monitor();
+       },   
+   /* 
+       * (local cortado seek does not seem to work very well)  
+       */
+       doSeek:function(perc){           
+               js_log('java:seek:p: ' + perc+ ' : '  + this.supportsURLTimeEncoding() + ' dur: ' + this.getDuration() + ' sts:' + this.seek_time_sec );                
+               this.getJCE();
+               
+               if( this.supportsURLTimeEncoding() ){            
+                       this.parent_doSeek(perc);   
+                       //this.seek_time_sec = npt2seconds( this.start_ntp ) + parseFloat( perc * this.getDuration() );                                         
+                  // this.jce.setParam('url', this.getURI( this.seek_time_sec ))
+                       //this.jce.restart();
+               }else if(this.jce){                                      
+                  //do a (genneraly broken) local seek:   
+                  js_log("cortado javascript seems to always fail ... but here we go... doSeek(" + (perc * parseFloat(this.getDuration()) ) );  
+                  this.jce.doSeek( perc * parseFloat(this.getDuration())  );                           
+               }else{
+                       this.doPlayThenSeek(perc);
+               }               
+       },
+       doPlayThenSeek:function(perc){
+               js_log('doPlayThenSeek Hack');
+               var _this = this;
+               this.play();
+               var rfsCount = 0;
+               var readyForSeek = function(){
+                       _this.getJCE(); 
+                       //if we have .jre ~in theory~ we can seek (but probably not) 
+                       if(_this.jce){
+                               _this.doSeek(perc);
+                       }else{                  
+                               //try to get player for 10 seconds: 
+                               if( rfsCount < 200 ){
+                                       setTimeout(readyForSeek, 50);
+                                       rfsCount++;
+                               }else{
+                                       js_log('error:doPlayThenSeek failed');
+                               }
+                       }
+               }
+               readyForSeek();
+       },
+       //get java cortado embed object
+       getJCE:function(){              
+               if ( embedTypes.mozilla ) {
+                       this.jce = window.frames['cframe_' + this.id ].document.getElementById( this.pid );
+               }else{
+                       this.jce = $j('#'+this.pid).get( 0 );
+               }
+               /*if( ! mv_java_iframe ){
+                       
+               }else{
+                       if( $j('#iframe_' + this.pid ).length > 0 )
+                               try{
+                                       this.jce = $j('#iframe_' + this.pid ).get(0).contentWindow.jPlayer;
+                               }catch (e){
+                                       if(!this.logged_domain_error)
+                                               js_log("failed to grab jce we wont have time updates for java");
+                                       this.logged_domain_error = true;
+                               }
+                       else
+                               return false;
+               }   */           
+       },
+       doThumbnailHTML:function(){             
+               //empty out player html (jquery with java applets does not work) :                      
+               var pelm = document.getElementById('mv_embedded_player_' + this.id );
+               pelm.innerHTML = '';            
+               this.parent_doThumbnailHTML();
+       },
+       play:function(){
+               this.getJCE();
+               this.parent_play();
+               if( this.jce )
+                       this.jce.doPlay();
+       },
+       pause:function(){
+               this.getJCE();
+               this.parent_pause();
+               if( this.jce )
+                       this.jce.doPause();              
+       }
+};
diff --git a/js2/mwEmbed/libEmbedVideo/nativeEmbed.js b/js2/mwEmbed/libEmbedVideo/nativeEmbed.js
new file mode 100644 (file)
index 0000000..f8adb18
--- /dev/null
@@ -0,0 +1,261 @@
+//native embed library:
+var nativeEmbed = {
+       instanceOf:'nativeEmbed',
+       canPlayThrough:false,
+       grab_try_count:0,
+       onlyLoadFlag:false,     
+       urlAppend:'',
+       supports: {
+               'play_head':true, 
+               'pause':true,            
+               'fullscreen':false, 
+               'time_display':true, 
+               'volume_control':true,
+               
+               'overlays':true,
+               'playlist_swap_loader':true //if the object supports playlist functions         
+   },
+       getEmbedHTML : function (){                                     
+               var embed_code =  this.getEmbedObj();
+               js_log("embed code: " + embed_code)                             
+               setTimeout('$j(\'#' + this.id + '\').get(0).postEmbedJS()', 150);
+               return this.wrapEmebedContainer( embed_code);           
+       },
+       getEmbedObj:function(){
+               //we want to let mv_embed handle the controls so notice the absence of control attribute
+               // controls=false results in controls being displayed: 
+               //http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2008-August/016159.html           
+               js_log("native play url:" + this.getSrc() + ' start_offset: '+ this.start_ntp + ' end: ' + this.end_ntp);
+               var eb = '<video ' +
+                                       'id="' + this.pid + '" ' +
+                                       'style="width:' + this.width+'px;height:' + this.height + 'px;" ' +
+                                       'width="' + this.width + '" height="'+this.height+'" '+
+                                          'src="' + this.getSrc() + '" ';
+                                          
+               /*if(!this.onlyLoadFlag)
+                       eb+='autoplay="true" ';*/
+                       
+               //continue with the other attr:                                         
+               eb+=            'oncanplaythrough="$j(\'#'+this.id+'\').get(0).oncanplaythrough();return false;" ' +
+                                          'onloadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' + 
+                                          'loadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' +
+                                          'onprogress="$j(\'#'+this.id+'\').get(0).onprogress( event );return false;" '+
+                                          'onended="$j(\'#'+this.id+'\').get(0).onended();return false;" >' +
+                       '</video>';
+               return eb;
+       },
+       //@@todo : loading progress     
+       postEmbedJS:function(){
+               var _this = this;
+               js_log("f:native:postEmbedJS:");                
+               this.getVID();
+               var doActualPlay= function(){
+                       js_log("doActualPlay ");
+                       _this.vid.play();
+               }
+               if(typeof this.vid != 'undefined'){                     
+                       //always load the media:
+                       if( this.onlyLoadFlag ){ 
+                               this.vid.load();
+                       }else{  
+                               this.vid.load();
+                               setTimeout(doActualPlay, 500);                                                          
+                       }                                                       
+                       setTimeout('$j(\'#'+this.id+'\').get(0).monitor()',100);                
+               }else{
+                       js_log('could not grab vid obj trying again:' + typeof this.vid);
+                       this.grab_try_count++;
+                       if(     this.grab_count == 10 ){
+                               js_log(' could not get vid object after 10 tries re-run: getEmbedObj()' ) ;                                             
+                       }else{
+                               setTimeout('$j(\'#'+this.id+'\').get(0).postEmbedJS()',100);
+                       }                       
+               }
+       },      
+       doSeek:function(perc){                          
+               //js_log('native:seek:p: ' + perc+ ' : '  + this.supportsURLTimeEncoding() + ' dur: ' + this.getDuration() + ' sts:' + this.seek_time_sec );            
+               //@@todo check if the clip is loaded here (if so we can do a local seek)
+               if( this.supportsURLTimeEncoding() || !this.vid){                       
+                       //make sure we could not do a local seek instead:
+                       if( perc < this.bufferedPercent && this.vid.duration && !this.didSeekJump ){
+                               js_log("do local seek " + perc + ' is already buffered < ' + this.bufferedPercent);
+                               this.doNativeSeek(perc);
+                       }else{
+                               this.parent_doSeek(perc);
+                       }                       
+               }else if(this.vid && this.vid.duration ){          
+                       //(could also check bufferedPercent > perc seek (and issue oggz_chop request or not) 
+                       this.doNativeSeek(perc);        
+               }else{
+                       this.doPlayThenSeek(perc)
+               }                                 
+       },      
+       doNativeSeek:function(perc){
+               this.seek_time_sec=0;                    
+               this.vid.currentTime = perc * this.vid.duration;
+               this.parent_monitor();  
+       },
+       doPlayThenSeek:function(perc){
+               js_log('native::doPlayThenSeek::');
+               var _this = this;
+               this.play();
+               var rfsCount = 0;
+               var readyForSeek = function(){
+                       _this.getVID();         
+                       //if we have duration then we are ready to do the seek
+                       if(this.vid && this.vid.duration){
+                               _this.doSeek(perc);
+                       }else{                  
+                               //try to get player for 10 seconds: 
+                               if( rfsCount < 200 ){
+                                       setTimeout(readyForSeek, 50);
+                                       rfsCount++;
+                               }else{
+                                       js_log('error:doPlayThenSeek failed');
+                               }
+                       }
+               }
+               readyForSeek();
+       },
+       setCurrentTime: function(pos, callback){
+               var _this = this;
+               this.getVID();
+               if(!this.vid) {
+                       js_log('native:setCurrentTime: load video');
+                       this.load();
+                       var loaded = function(event) {
+                               js_log('native:setCurrentTime (after load): ' + pos + ' :  dur: ' + this.getDuration());
+                               _this.vid.currentTime = pos;
+                               var once = function(event) { callback(); _this.vid.removeEventListener('seeked', once, false) };
+                               _this.vid.addEventListener('seeked', once, false);
+                               _this.removeEventListener('loadedmetadata', loaded, false);
+                       };
+                       _this.addEventListener('loadedmetadata', loaded, false);
+               } else {
+                       js_log('native:setCurrentTime: ' + pos + ' : '  + this.supportsURLTimeEncoding() + ' dur: ' + this.getDuration() + ' sts:' + this.seek_time_sec );
+                       _this.vid.currentTime = pos;
+                       var once = function(event) { callback(); _this.vid.removeEventListener('seeked', once, false) };
+                       _this.vid.addEventListener('seeked', once, false);
+               }
+       },
+       monitor : function(){
+               this.getVID(); //make shure we have .vid obj
+               if(!this.vid){
+                       js_log('could not find video embed: '+this.id + ' stop monitor');
+                       this.stopMonitor();                     
+                       return false;
+               }               
+               //don't update status if we are not the current clip (playlist leekage?) .. should move to playlist overwite of monitor? 
+               if(this.pc){
+                       if(this.pc.pp.cur_clip.id != this.pc.id)
+                               return true;
+               }                                                               
+                               
+               //update currentTime                            
+               this.currentTime = this.vid.currentTime;                
+               this.addPresTimeOffset();
+               //js_log('currentTime:' + this.currentTime);
+               //js_log('this.currentTime: ' + this.currentTime );
+               //once currentTime is updated call parent_monitor
+               this.parent_monitor();
+       },      
+       getSrc:function(){
+               var src = this.parent_getSrc();
+               if(  this.urlAppend != '')
+                       return src + ( (src.indexOf('?')==-1)?'?':'&') + this.urlAppend;
+               return src;
+       },
+       /*
+        * native callbacks for the video tag: 
+        */
+       oncanplaythrough : function(){          
+               js_log('f:oncanplaythrough');
+               this.getVID();
+               if( ! this.paused )
+                       this.vid.play();
+       },
+       onloadedmetadata: function(){
+               this.getVID();
+               js_log('f:onloadedmetadata metadata ready (update duration)');  
+               //update duration if not set (for now trust the getDuration more than this.vid.duration         
+               if( this.getDuration()==0  &&  !isNaN( this.vid.duration )){
+                       js_log('updaed duration via native video duration: '+ this.vid.duration)
+                       this.duration = this.vid.duration;
+               }
+       },
+       onprogress: function(e){                
+               this.bufferedPercent =   e.loaded / e.total;
+               //js_log("onprogress:" +e.loaded + ' / ' +  (e.total) + ' = ' + this.bufferedPercent);
+       },
+       onended:function(){       
+               var _this = this         
+               this.getVID();   
+               js_log('native:onended:' + this.vid.currentTime + ' real dur:' +  this.getDuration() );
+               //if we just started (under 1 second played) & duration is much longer.. don't run onClipDone just yet . (bug in firefox native sending onended event early) 
+               if(this.vid.currentTime  < 1 && this.getDuration() > 1 && this.grab_try_count < 5){                     
+                       js_log('native on ended called with time:' + this.vid.currentTime + ' of total real dur: ' +  this.getDuration() + ' attempting to reload src...');
+                       var doRetry = function(){
+                               _this.urlAppend = 'retry_src=' + _this.grab_try_count; 
+                               _this.doEmbedHTML();
+                               _this.grab_try_count++;
+                       }
+                       setTimeout(doRetry, 100);                       
+               }else{
+                       this.onClipDone();
+               }
+       },      
+       pause : function(){             
+               this.getVID();
+               this.parent_pause(); //update interface         
+               if(this.vid){                   
+                       this.vid.pause();
+               }
+               //stop updates: 
+               this.stopMonitor();
+       },
+       play:function(){
+               this.getVID();
+               this.parent_play(); //update interface
+               if( this.vid ){
+                       this.vid.play();
+                       //re-start the monitor: 
+                       this.monitor();
+               }
+       },
+       toggleMute:function(){
+               this.parent_toggleMute();
+               this.getVID();
+               if(this.vid)
+                       this.vid.muted = this.muted;
+       },      
+       updateVolumen:function(perc){
+               this.getVID();          
+               if(this.vid)
+                       this.vid.volume = perc;                     
+       },              
+    getVolumen:function(){
+               this.getVID();          
+               if(this.vid)
+                       return this.vid.volume;                    
+       },      
+       load:function(){
+               this.getVID();
+               if( !this.vid ){
+                       //no vid loaded
+                       js_log('native::load() ... doEmbed');
+                       this.onlyLoadFlag = true;
+                       this.doEmbedHTML();
+               }else{
+                       //won't happen offten
+                       this.vid.load();
+               }
+       },
+       // get the embed vlc object 
+       getVID : function (){
+               this.vid = $j('#'+this.pid).get(0);               
+       },  
+       /* 
+        * playlist driver        
+        * mannages native playlist calls                 
+        */     
+};
diff --git a/js2/mwEmbed/libEmbedVideo/omtkEmbed.js b/js2/mwEmbed/libEmbedVideo/omtkEmbed.js
new file mode 100644 (file)
index 0000000..6e2b13d
--- /dev/null
@@ -0,0 +1,65 @@
+var omtkEmbed={
+       instanceOf:'omtkEmbed',
+       supports: {
+               'pause':true,   
+                       'time_display':true
+       },
+       getEmbedHTML : function (){             
+               var embed_code =  this.getEmbedObj();
+               //need omtk to fire an onReady event.
+               setTimeout('$j(\'#' + this.id + '\').get(0).postEmbedJS()', 2000);
+               return this.wrapEmebedContainer( embed_code);                   
+       },
+       getEmbedObj:function(){
+               var player_path = mv_embed_path + 'binPlayers/omtk-fx/omtkp.swf';       
+               //player_path = 'omtkp.swf';
+               js_log("player path: " + player_path);
+               return  '<object id="'+this.pid+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="1" height="1">' +                                
+                                       '<param name="movie" value="' + player_path +'" />'+"\n"+                                       
+                                       '<!--[if !IE]>-->'+"\n"+
+                                               '<object id="'+this.pid+'_ie" type="application/x-shockwave-flash" data="'+player_path+'" width="1" height="1">'+"\n"+
+                                       '<!--<![endif]-->'+"\n"+
+                                                 '<p>Error with Display of Flash Plugin</p>'+"\n"+
+                                       '<!--[if !IE]>-->'+"\n"+
+                                               '</object>'+"\n"+
+                                       '<!--<![endif]-->'+"\n"+
+                                 '</object>';                  
+       },
+       postEmbedJS:function(){
+               this.getOMTK();
+               //play the url: 
+               js_log("play: pid:"+ this.pid + ' src:' + this.src);
+                               
+               this.omtk.play( this.src );
+               
+               this.monitor();
+               //$j('#omtk_player').get(0).play(this.src);
+               //$j('#'+this.pid).get(0).play( this.src );
+       },
+       pause:function(){
+               this.stop();
+       },
+       monitor:function(){
+               if(this.omtk.getPosition)               
+                       this.currentTime = this.omtk.getPosition() / 1000;
+               
+               this.parent_monitor();  
+       },
+       getOMTK : function (){
+               this.omtk = $j('#'+this.pid).get(0);            
+               if(!this.omtk.play)
+                       this.omtk = $j('#'+this.pid+'_ie').get(0); 
+               
+               if(this.omtk.play){
+                       //js_log('omtk obj is missing .play (probably not omtk obj)');
+               }
+       },  
+}
+
+function OMTK_P_complete(){
+       js_log('OMTK_P_complete');                      
+}
+
+function OMTK_P_metadataUpdate(){
+       js_log('OMTK_P_metadataUpdate');
+}
diff --git a/js2/mwEmbed/libEmbedVideo/vlcEmbed.js b/js2/mwEmbed/libEmbedVideo/vlcEmbed.js
new file mode 100644 (file)
index 0000000..0e5a8d8
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+* vlc embed based on: http://people.videolan.org/~damienf/plugin-0.8.6.html
+* javascript api: http://www.videolan.org/doc/play-howto/en/ch04.html
+*  assume version > 0.8.5.1
+*/
+var vlcEmbed = { 
+       instanceOf:'vlcEmbed',
+       supports: {'play_head':true, 
+               'pause':true, 
+               'stop':true, 
+               'fullscreen':true, 
+               'time_display':true, 
+               'volume_control':true,
+               
+               'playlist_driver':true, //if the object supports playlist functions
+               'overlay':false
+       },
+       //init vars: 
+       monitorTimerId : 0,
+       prevState : 0,                    
+       pejs_count:0, //post embed js count
+        
+       getEmbedHTML: function(){               
+               //give VLC 150ms to initialize before we start playback 
+               //@@todo should be able to do this as an ready event
+               this.pejs_count=0;
+               setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()', 150);
+                  return this.getEmbedObj();
+       },
+       getEmbedObj:function(){
+               var embed_code = '<object classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" '+
+                       'codebase="http://downloads.videolan.org/pub/videolan/vlc/latest/win32/axvlc.cab#Version=0,8,6,0" '+
+                       'id="' + this.pid + '" events="True" height="'+this.height+'" width="'+this.width+'"' +
+                       '>'+
+                               '<param name="MRL" value="">'+
+                               '<param name="ShowDisplay" value="True">'+
+                               '<param name="AutoLoop" value="False">'+
+                               '<param name="AutoPlay" value="False">'+
+                               '<param name="Volume" value="50">'+
+                               '<param name="StartTime" value="0">'+
+                               '<embed pluginspage="http://www.videolan.org" type="application/x-vlc-plugin" '+
+                                       'progid="VideoLAN.VLCPlugin.2" name="' + this.pid + '" '+
+                                       'height="'+this.height+'" width="'+this.width+'" ' +
+                                       //set the style too 'just to be sure'
+                                       'style="width:'+this.width+'px;height:'+this.height+'px;" '+ 
+                               '>'+
+                       '</object>';
+               js_log('embed with: ' + embed_code);
+               return embed_code;              
+       },
+       
+       /*
+       * some java script to start vlc playback after the embed:
+       */
+       postEmbedJS: function(){   
+               //load a pointer to the vlc into the object (this.vlc)
+               this.getVLC();
+               if( this.vlc.log ){
+                       //manipulate the dom object to make sure vlc has the correct size: 
+                       this.vlc.style.width=this.width;
+                       this.vlc.style.height=this.height;         
+                       this.vlc.playlist.items.clear();
+                       //@@todo if client supports seeking no need to send seek_offset to URI
+                       js_log('vlc play::' + this.getSrc() );                    
+                       var itemId = this.vlc.playlist.add( this.getSrc() );
+                       if( itemId != -1 ){
+                               //play
+                               this.vlc.playlist.playItem(itemId);
+                       }else{
+                               js_log("error:cannot play at the moment !");
+                       }
+                       //if controls enabled start up javascript interface and monitor:
+                       if(this.controls){                              
+                               //activate the slider: scriptaculus based)
+                               //this.activateSlider();  
+                               //start doing status updates every 1/10th of a second                                                      
+                       }               
+                       setTimeout('$j(\'#'+this.id+'\').get(0).monitor()',100);                                                
+               }else{
+                       js_log('postEmbedJS:vlc not ready');
+                       this.pejs_count++;
+                       if( this.pejs_count < 10 ){
+                               setTimeout('document.getElementById(\''+this.id+'\').postEmbedJS()',100);
+                       }else{
+                               js_log('vlc never ready');
+                       }       
+               }
+       },   
+       //disable local seeking (while we don't know what we have avaliable)
+       doSeek : function(perc){
+               if( this.supportsURLTimeEncoding() ){
+                       this.parent_doSeek(perc);
+               }else if( this.vlc ) {
+                       this.seeking=true;
+                       js_log("do vlc http seek to: " + perc)
+                       if( (this.vlc.input.state == 3) && (this.vlc.input.position != perc) )
+                       {
+                               this.vlc.input.position = perc;
+                               this.setStatus( 'seeking...' );            
+                       }                               
+               }else{
+                       this.doPlayThenSeek(perc);
+               }
+               this.parent_monitor();
+       },
+       doPlayThenSeek:function(perc){
+               js_log('doPlayThenSeekHack');
+               var _this = this;
+               this.play();
+               var rfsCount = 0;
+               var readyForSeek = function(){
+                       _this.getVLC();
+                       var newState = _this.vlc.input.state;
+                       //if playing we are ready to do the 
+                       if(newState==3){
+                               _this.doSeek(perc);
+                       }else{                  
+                               //try to get player for 10 seconds: 
+                               if( rfsCount < 200 ){
+                                       setTimeout(readyForSeek, 50);
+                                       rfsCount++;
+                               }else{
+                                       js_log('error:doPlayThenSeek failed');
+                               }
+                       }
+               }
+               readyForSeek();
+       },
+       playMovieAt: function (order){
+               //@@todo add clips to playlist after (order) and then play
+               this.play();
+       },
+       /* 
+       * updates the status time
+       */
+       monitor: function(){
+               this.getVLC();
+               if(!this.vlc)
+                       return ;
+               if( this.vlc.log ){
+                       //js_log( 'state:' + this.vlc.input.state);
+                       //js_log('time: ' + this.vlc.input.time);
+                       //js_log('pos: ' + this.vlc.input.position);
+                       if( this.vlc.log.messages.count > 0 ){
+                               // there is one or more messages in the log
+                               var iter = this.vlc.log.messages.iterator();
+                               while( iter.hasNext ){
+                                       var msg = iter.next();
+                                  var msgtype = msg.type.toString();
+                                  if( (msg.severity == 1) && (msgtype == "input") )
+                                  {
+                                                  js_log( msg.message );
+                                  }
+                               }
+                               // clear the log once finished to avoid clogging
+                               this.vlc.log.messages.clear();
+                       }
+                       var newState = this.vlc.input.state;
+                       if( this.prevState != newState ){
+                                  if( newState == 0 )
+                               {
+                                       // current media has stopped 
+                                       this.onStop();
+                               }
+                               else if( newState == 1 )
+                               {
+                                       // current media is opening/connecting
+                                       this.onOpen();
+                               }
+                               else if( newState == 2 )
+                               {
+                                       // current media is buffering data
+                                       this.onBuffer();
+                               }
+                               else if( newState == 3 )
+                               {
+                                  // current media is now playing
+                                  this.onPlay();
+                               }
+                                  else if( this.vlc.input.state == 4 )
+                               {
+                                       // current media is now paused
+                                       this.onPause();
+                               }
+                               this.prevState = newState;
+                       }else if( newState == 3 ){
+                               // current media is playing
+                               this.onPlaying();
+                       }
+               }
+               //update the status and check timmer via universal parent monitor
+               this.parent_monitor();
+       },
+/* events */
+       onOpen: function(){
+               this.setStatus("Opening...");
+               //document.getElementById("info_"+this.id).innerHTML = "Opening...";
+               //document.getElementById("PlayOrPause").disabled = true;
+               //document.getElementById("Stop").disabled = false;
+       },
+       onBuffer: function(){
+               this.setStatus("Buffering...");
+               //document.getElementById("info_"+this.id).innerHTML = "Buffering...";
+               //document.getElementById("PlayOrPause").disabled = true;
+               //document.getElementById("Stop").disabled = false;
+       },
+       onPlay: function(){
+               //document.getElementById("PlayOrPause").value = "Pause";
+               //document.getElementById("PlayOrPause").disabled = false;
+               //document.getElementById("Stop").disabled = false;
+               this.onPlaying();               
+       },
+       liveFeedRoll: 0,
+       onPlaying: function(){          
+               this.seeking=false;
+               //for now trust the duration from url over vlc input.length
+               if( !this.getDuration() && this.vlc.input.length > 0 )
+               {
+                       //js_log('setting duration to ' + this.vlc.input.length /1000);                 
+                       this.duration = this.vlc.input.length /1000;
+               }
+               this.currentTime = this.vlc.input.time/1000;            
+   },
+   onPause: function(){                   
+               this.parent_pause(); //update the inteface if paused via native control
+   },
+   onStop: function(){ 
+          js_log('vlc:onStop:');
+          if(!this.seeking)
+                 this.onClipDone();
+       },
+   /* js hooks/controls */
+       play : function(){
+               js_log('f:vlcPlay');
+                       this.getVLC();
+                       //call the parent
+               this.parent_play();
+               if( this.vlc ){
+                       //plugin is already being present send play call: 
+                       // clear the message log and enable error logging
+                       if( this.vlc.log ){
+                               this.vlc.log.messages.clear();
+                       }
+                       if(this.vlc.playlist)
+                               this.vlc.playlist.play();
+                               
+                       this.monitor();
+                       this.paused=false;
+               }               
+       },
+       stop : function(){
+               if(this.vlc){
+                       if(typeof this.vlc != 'undefined' ){
+                               if(typeof this.vlc.playlist != 'undefined'){
+                                       //dont' stop (issues all the plugin-stop actions) 
+                                       //this.vlc.playlist.stop();
+                                       if( this.monitorTimerId != 0 )
+                                       {
+                                               clearInterval(this.monitorTimerId);
+                                               this.monitorTimerId = 0;
+                                       }
+                               }
+                       }
+               }
+               //this.onStop();
+               //do parent stop
+               this.parent_stop();
+       },
+       pause : function(){
+               this.parent_pause(); //update the inteface if paused via native control
+               if( this.vlc ){
+                       this.vlc.playlist.togglePause();
+               }
+       },
+       toggleMute:function(){
+               this.parent_toggleMute();
+               this.getVLC();
+               if(this.vlc)
+                       this.vlc.audio.toggleMute();
+    }, 
+    //@@ Suport UpDateVolumen 
+    updateVolumen:function(perc){
+       this.getVLC();
+               if(this.vlc)
+                       this.vlc.audio.volume = perc*100;                           
+    }, 
+    //@@ Get Volumen
+    getVolumen:function(){
+       this.getVLC();
+       if(this.vlc) 
+               return this.vlc.audio.volume / 100;
+    }, 
+       fullscreen : function(){
+               if(this.vlc){
+                       if(this.vlc.video)
+                               this.vlc.video.toggleFullscreen();
+               }
+       },
+       /* returns current time in float seconds 
+        * as per html5 we should just have an attribute by name of CurrentTime
+        * http://www.whatwg.org/specs/web-apps/current-work/#currenttime
+       currentTime : function(){
+               if(typeof this.vlc != 'undefined' ){
+                       if(typeof this.vlc.input != 'undefined' ){
+                               return this.vlc.input.time/1000;        
+                       }
+               }
+               return '0';
+       },
+       */
+       // get the embed vlc object 
+       getVLC : function(){
+               this.vlc = this.getPluginEmbed();                  
+       }
+};
+
diff --git a/js2/mwEmbed/libSequencer/mvPlayList.js b/js2/mwEmbed/libSequencer/mvPlayList.js
new file mode 100644 (file)
index 0000000..a140927
--- /dev/null
@@ -0,0 +1,2199 @@
+/* 
+ * the mvPlayList object code 
+ * only included if playlist object found
+ * 
+ * part of mv_embed: 
+ * http://metavid.org/wiki/index.php/Mv_embed 
+ */
+var mv_default_playlist_attributes = {
+       //playlist attributes :
+       "id":null,
+       "title":null,
+       "width":400,
+       "height":300,
+       "desc":'',
+       "controls":true,
+       //playlist user controlled features
+       "linkback":null, 
+       "src":null,
+       "embed_link":true,
+       
+       //enable sequencer? (only display top frame no navigation or accompanying text
+       "sequencer":false
+}
+//the call back rate for animations and internal timers in ms: 33 is about 30 frames a second: 
+var MV_ANIMATION_CB_RATE = 33;
+
+//globals:
+//10 possible colors for clips: (can be in hexadecimal)
+var mv_clip_colors = new Array('aqua', 'blue', 'fuchsia', 'green', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red');
+//the base url for requesting stream metadata 
+if(typeof wgServer=='undefined'){
+       var defaultMetaDataProvider = 'http://metavid.org/overlay/archive_browser/export_cmml?stream_name=';
+}else{
+       var defaultMetaDataProvider = wgServer + wgScript + '?title=Special:MvExportStream&feed_format=roe&stream_name=';
+}
+
+var mvPlayList = function(element) {           
+       return this.init(element);
+};
+//set up the mvPlaylist object
+mvPlayList.prototype = {
+       instanceOf:'mvPlayList',
+       pl_duration:null,
+       update_tl_hook:null,
+       clip_ready_count:0,
+       cur_clip:null,  
+       start_clip:null, 
+       start_clip_src:null,
+       disp_play_head:null,
+       userSlide:false,
+       loading:true,   
+       loading_external_data:true, //if we are loading external data (set to loading by default)
+       
+       activeClipList:null,
+       playlist_buffer_time: 20, // how many seconds of future clips we should buffer
+       
+       interface_url:null, //the interface url 
+       tracks:{},
+       default_track:null, // the default track to add clips to.
+       //the layout for the playlist object
+       pl_layout : {
+               seq_title:.1,
+               clip_desc:.63, //displays the clip description
+               clip_aspect:1.33,  // 4/3 video aspect ratio
+               seq:.25,                                 //display clip thumbnails 
+               seq_thumb:.25,   //size for thumbnails (same as seq by default) 
+               seq_nav:0,      //for a nav bar at the base (currently disabled)
+               //some pl_layout info:
+               title_bar_height:17,
+               control_height:29
+       },
+       init : function(element){
+               js_log('mvPlayList:init:');             
+               this.tracks={};         
+               this.default_track=null;                                                
+               
+               this.activeClipList = new activeClipList();
+               //add default track & default track pointer: 
+               this.tracks[0]= new trackObj({'inx':0});
+               this.default_track = this.tracks[0];                            
+               
+               //get all the attributes:
+                 for(var attr in mv_default_playlist_attributes){         
+                       if( element.getAttribute(attr) ){
+                               this[attr]=element.getAttribute(attr);
+                               //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+'elm_val:' + element.getAttribute(attr) + "\n (set by elm)");  
+                       }else{          
+                               this[attr]=mv_default_playlist_attributes[attr];
+                               //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)");  
+                       }
+               }
+               //make sure height and width are int:
+               this.width =parseInt(this.width);
+               this.height=parseInt(this.height);
+               
+               //if style is set override width and height
+               if(element.style.width)this.width = parseInt(element.style.width.replace('px',''));
+               if(element.style.height)this.height = parseInt(element.style.height.replace('px',''));                  
+                               
+               //if controls=false hide the title and the controls:
+               if(this.controls===false){                       
+                       this.pl_layout.control_height=0;        
+                       this.pl_layout.title_bar_height=0;                      
+               }                                                
+       },                      
+       //the element has now been swapped into the dom: 
+       on_dom_swap:function(){
+               js_log('pl: dom swap');
+               //get and load the html:
+               this.getHTML();
+       },
+       //run inheritEmbedObj on every clip (we have changed the playback method) 
+       inheritEmbedObj:function(){             
+               $j.each(this.tracks, function(i,track){ 
+                       track.inheritEmbedObj();                        
+               });
+       },      
+       doOptionsHTML:function(){
+               //grab "options" use current clip:
+               this.cur_clip.embed.doOptionsHTML();
+       },
+       //pulls up the video editor inline
+       doEditor:function(){
+               //black out the page: 
+               //$j('body').append('<div id="ui-widget-overlay"/> <div id="modalbox" class="ui-widget ui-widget-content ui-corner-all modal_editor">' );
+               $j('body').append('<div class="ui-widget-overlay" style="width: 100%; height: 100%px; z-index: 10;"></div>');
+               $j('body').append('<div id="sequencer_target" style="z-index:11;position:fixed;top:10px;left:10px;right:10px;bottom:10px;" ' +
+                               'class="ui-widget ui-widget-content ui-corner-all"></div>');                    
+                                       
+               //@@todo clone the playlist (for faster startup)
+               /*
+                * var this_plObj_Clone = $j('#'+this.id).get(0).cloneNode(true);
+                *      this_plObj_Clone.sequencer=true;
+                *      this_plObj_Clone.id= 'seq_plobj';
+                *      debugger;
+               */              
+               //load sequencer: 
+               $j("#sequencer_target").sequencer({                             
+                       "mv_pl_src" : this.src                                          
+               });
+                                       
+       },
+       selectPlaybackMethod:function(){
+               this.cur_clip.embed.selectPlaybackMethod();
+       },
+       closeDisplayedHTML:function(){
+               this.cur_clip.embed.closeDisplayedHTML();
+       },
+       showVideoDownload:function(){
+               this.cur_clip.embed.showVideoDownload();
+       },
+       showEmbedCode:function(){
+               var embed_code = '&lt;script type=&quot;text/javascript&quot; '+
+                                               'src=&quot;'+mv_embed_path+'mv_embed.js&quot;&gt;&lt;/script&gt '+"\n" + 
+                                               '&lt;playlist id=&quot;'+this.id+'&quot; ';
+                                               if(this.src){
+                                                       embed_code+='src=&quot;'+this.src+'&quot; /&gt;';
+                                               }else{
+                                                       embed_code+='&gt;'+"\n";
+                                                       embed_code+= this.data.htmlEntities();
+                                                       embed_code+='&lt;playlist/&gt;';
+                                               }
+               this.cur_clip.embed.showEmbedCode(embed_code);
+       },
+       getPlaylist:function(){         
+               js_log("f:getPlaylist: " + this.srcType );
+               //@@todo lazy load plLib
+               eval('var plObj = '+this.srcType+'Playlist;');  
+               //import methods from the plObj to this
+               for(var method in plObj){
+                       //js parent preservation for local overwritten methods
+                       if(this[method])this['parent_' + method] = this[method];
+                       this[method]=plObj[method];
+                       js_log('inherit:'+ method);
+               } 
+                       
+               if(typeof this.doParse != 'function'){
+                       js_log('error: method doParse not found in plObj'+ this.srcType);
+                       return false;                                   
+               }   
+                                                
+               if(typeof this.doParse == 'function'){
+                                if( this.doParse() ){
+                                        this.doWhenParseDone();        
+                                }else{
+                                        js_log("error: failed to parse playlist");
+                                        return false;
+                                        //error or parse needs to do ajax requests     
+                                }
+               }                          
+       },
+       doNativeWarningCheck:function(){
+               var clip =       this.default_track.clips[0];
+               return clip.embed.doNativeWarningCheck();
+       },
+       doWhenParseDone:function(){                             
+               js_log('f:doWhenParseDone');
+               //do additional init for clips: 
+               var _this = this;
+               var error=false;
+               _this.clip_ready_count=0;               
+               for( var i in this.default_track.clips ){
+                       var clip =       this.default_track.clips[i];
+                       if(clip.embed.load_error){
+                               var error = clip.embed.load_error;                              
+                               //break on any clip we can't playback:
+                               break;
+                       }
+                       if( clip.embed.ready_to_play ){
+                               _this.clip_ready_count++;
+                               continue;
+                       }
+                       //js_log('clip sources count: '+ clip.embed.media_element.sources.length);              
+                       clip.embed.on_dom_swap();
+                       if( clip.embed.loading_external_data==false && 
+                                  clip.embed.init_with_sources_loadedDone==false){
+                                       clip.embed.init_with_sources_loaded();
+                       }                                       
+               }
+               
+               //@@todo for some plugins we have to conform types of clips
+               // ie vlc can play flash _followed_by_ ogg _followed_by_ whatever 
+               //               but
+               // native ff 3.1a2 can only play ogg 
+               if( error){
+                       this.load_error=error;
+                       this.is_ready=false;
+               }else if( _this.clip_ready_count == _this.getClipCount() ){
+                       js_log("done init all clips: " +  _this.clip_ready_count + ' = ' + _this.getClipCount());                       
+                       this.doWhenClipLoadDone();
+               }else{
+                       js_log("only "+ _this.clip_ready_count +" clips done, scheduling callback:");
+                       if( !mvJsLoader.load_error )    //re-issue request if no load error:
+                               setTimeout('document.getElementById(\''+this.id+'\').doWhenParseDone()', 250);
+               }                                                               
+       },
+       doWhenClipLoadDone:function(){          
+               js_log('mvPlaylist:doWhenClipLoadDone');
+               this.ready_to_play = true;
+               this.loading = false;
+               this.getHTML();         
+       },      
+       getDuration:function( regen ){                  
+               //js_log("GET PL DURRATION for : "+ this.tracks[this.default_track_id].clips.length + 'clips');
+               if(!regen && this.pl_duration)
+                       return this.pl_duration;
+                                               
+               var durSum=0;           
+               $j.each( this.default_track.clips, function( i, clip ){ 
+                       if( clip.embed ){
+                               clip.dur_offset = durSum;
+                               //only calculate the solo Duration if a smil clip that could contain a transition: 
+                               if( clip.instanceOf == 'mvSMILClip' ){
+                                       //don't include transition time (for playlist_swap_loader compatible clips)                             
+                                       durSum += clip.getSoloDuration(); 
+                               }else{
+                                       durSum += clip.getDuration();   
+                               }                                                               
+                       }else{
+                               js_log("ERROR: clip " +clip.id + " not ready");
+                       }
+               });
+               this.pl_duration=durSum;                
+               //js_log("return dur: " + this.pl_duration);
+               return this.pl_duration;
+       },
+       getDataSource:function(){       
+               js_log("f:getDataSource "+ this.src);
+               //determine the type / first is it m3u or xml?   
+               var pl_parent = this;
+               this.makeURLAbsolute();
+               if(this.src!=null){                     
+                       do_request(this.src, function(data){
+                               pl_parent.data=data;
+                               pl_parent.getSourceType();
+                       });     
+               }
+       },
+       getSourceType:function(){
+               js_log('data type of: '+ this.src + ' = ' + typeof (this.data) + "\n"+ this.data);
+               this.srcType =null;
+               //if not external use different detection matrix
+               if(this.loading_external_data){                         
+                       if( typeof this.data == 'object' ){
+                               js_log('object');               
+                               //object assume xml (either xspf or rss) 
+                               plElm = this.data.getElementsByTagName('playlist')[0];
+                               if( plElm ){
+                                       if(plElm.getAttribute('xmlns')=='http://xspf.org/ns/0/'){
+                                               this.srcType ='xspf';
+                                       }
+                               }
+                               //check itunes style rss "items" 
+                               rssElm = this.data.getElementsByTagName('rss')[0];
+                               if(rssElm){
+                                       if(rssElm.getAttribute('xmlns:itunes')=='http://www.itunes.com/dtds/podcast-1.0.dtd'){
+                                               this.srcType='itunes';                                          
+                                       }                                       
+                               }                               
+                               //check for smil tag: 
+                               smilElm = this.data.getElementsByTagName('smil')[0];
+                               if(smilElm){
+                                       //don't check dtd yet.. (have not defined the smil subset) 
+                                       this.srcType='smil';
+                               }
+                       }else if(typeof this.data == 'string'){         
+                               js_log('String');
+                               //look at the first line: 
+                               var first_line = this.data.substring(0, this.data.indexOf("\n"));
+                               js_log('first line: '+ first_line);     
+                               //string
+                               if(first_line.indexOf('#EXTM3U')!=-1){
+                                       this.srcType = 'm3u';
+                               }else if(first_line.indexOf('<smil')!=-1){
+                                       //@@todo parse string
+                                       this.srcType = 'smil';
+                               }
+                       }
+               }               
+               if(this.srcType){
+                       js_log('is of type:'+ this.srcType);
+                       this.getPlaylist();
+               }else{
+                       //unknown playlist type
+                       js_log('unknown playlist type?');
+                       if(this.src){
+                               this.innerHTML= 'error: unknown playlist type at url:<br> ' + this.src;
+                       }else{
+                               this.innerHTML='error: unset src or unknown inline playlist data<br>';
+                       }
+               }                       
+       },      
+       //simple function to make a path into an absolute url if its not already
+       makeURLAbsolute:function(){             
+               if(this.src){
+                       if(this.src.indexOf('://')==-1){
+                               var purl = parseUri(document.URL);                      
+                               if(this.src.charAt(0)=='/'){                                            
+                                       this.src = purl.protocol +'://'+ purl.host + this.src;
+                               }else{
+                                       this.src= purl.protocol +'://'+ purl.host + purl.directory + this.src;                          
+                               }
+                       }
+               }
+       },      
+       //set up minimal media_element emulation:        
+       media_element:{ 
+               selected_source:{
+                       supports_url_time_encoding:true
+               }
+       },
+       //@@todo needs to update for multi-track clip counts
+       getClipCount:function(){
+               return this.default_track.clips.length; 
+       },      
+       //},
+       //takes in the playlist 
+       // inherits all the properties 
+       // swaps in the playlist object html/interface div      
+       getHTML:function(){     
+               js_log('mvPlaylist:getHTML:  loading:' + this.loading);                                         
+               if(this.loading){               
+                       $j('#'+this.id).html('loading playlist<blink>...</blink>'); 
+                       if( this.loading_external_data ){
+                               //load the data source chain of functions (to update the innerHTML)                        
+                               this.getDataSource();  
+                       }else{
+                               //detect datatype and parse directly: 
+                               this.getSourceType();
+                       }
+               }else{
+                       //check for empty playlist otherwise renderDisplay:             
+                       if(this.default_track.getClipCount()==0){
+                               $j(this).html('empty playlist');
+                               return ;
+                       }else{
+                               this.renderDisplay();
+                       }                                                               
+               }
+       },
+       renderDisplay:function(){               
+               js_log('mvPlaylist:renderDisplay:: track length: ' +this.default_track.getClipCount() );''
+               
+               var _this=this;                 
+               //setup layout for title and dc_ clip container  
+                                                                               
+               
+               //add the playlist controls:
+                                                       
+               //append container and videoPlayer; 
+               $j(this).html('<div id="dc_'+this.id+'" style="width:'+this.width+'px;' +
+                               'height:'+(this.height+this.pl_layout.title_bar_height + this.pl_layout.control_height)+'px;position:relative;">' +                             
+                       '</div>');              
+               if(this.controls==true){        
+                       //append title & controler:
+                       $j('#dc_'+_this.id).append(
+                               '<div style="font-size:13px;border:solid thin;width:'+this.width+'px;" id="ptitle_'+this.id+'"></div>' +
+                               '<div class="videoPlayer" style="position:absolute;top:'+(_this.height+_this.pl_layout.title_bar_height+4)+'px">' +
+                               '<div id="mv_embedded_controls_'+_this.id+'" class="ui-widget ui-corner-bottom ui-state-default controls" '+
+                                       'style="width:' + _this.width + 'px" >' + 
+                                                _this.getControlsHTML() +
+                                       '</div>'+
+                               '</div>'
+                       );                                                                                      
+                                       
+                       //add the play button:                                          
+                       $j('#dc_'+_this.id).append(
+                               this.cur_clip.embed.getPlayButton()
+               );
+               //once the controls are in the DOM add hooks: 
+                       ctrlBuilder.addControlHooks(this);
+               }else{
+                       //just append the video: 
+                       $j('#dc_'+_this.id).append(
+                               '<div class="videoPlayer" style="position:absolute;top:'+(_this.height+_this.pl_layout.title_bar_height+4)+'px"></div>'
+                       );
+               }                       
+               this.setupClipDisplay();                                                                                 
+                                               
+               //update the title and status bar
+               this.updateBaseStatus();        
+       },
+       setupClipDisplay:function(){
+               js_log('mvPlaylist:setupClipDisplay:: clip len:'+ this.default_track.clips.length);
+               var _this = this;       
+               $j.each(this.default_track.clips, function(i, clip){                                    
+                       var cout = '<div class="clip_container cc_" id="clipDesc_'+clip.id+'" '+
+                               'style="display:none;position:absolute;text-align: center;width:'+_this.width + 'px;'+
+                               'height:'+(_this.height )+'px;'+
+                               'top:' + this.title_bar_height + 'px;left:0px;';        
+                       if(_this.controls){                             
+                               cout+='border:solid thin black;';
+                       }                       
+                       cout+='"></div>';
+                       $j('#dc_'+_this.id).append( cout );     
+                       //update the embed html:                                         
+                       clip.embed.height=_this.height;
+                       clip.embed.width=_this.width;                           
+                       clip.embed.play_button=false;
+                       
+                       clip.embed.getHTML();//get the thubnails for everything                 
+                       
+                       $j(clip.embed).css({ 
+                               'position':"absolute",
+                               'top':"0px", 
+                               'left':"0px"
+                       });
+                       if($j('#clipDesc_'+clip.id).length != 0){
+                               js_log("should set: #clipDesc_"+clip.id + ' to: ' + $j(clip.embed).html() )
+                               $j('#clipDesc_'+clip.id).append( clip.embed );                          
+                       }else{
+                               js_log('cound not find: clipDesc_'+clip.id);                                    
+                       }                                                                                                                               
+               });                                     
+               if(this.cur_clip)
+                       $j('#clipDesc_'+this.cur_clip.id).css( { display:'inline' } );
+       },      
+       updateThumbPerc:function( perc ){
+               //get float seconds:
+               var float_sec =  ( this.getDuration() * perc );
+               this.updateThumbTime( float_sec );                      
+       },
+       updateThumbTime:function( float_sec ){                  
+               //update display & cur_clip:
+               var pl_sum_time =0; 
+               var clip_float_sec=0;           
+               //js_log('seeking clip: ');
+               for(var i in this.default_track.clips){
+                       var clip = this.default_track.clips[i];
+                       if( (clip.getDuration() + pl_sum_time) >= float_sec ){
+                               if(this.cur_clip.id != clip.id){                                        
+                                       $j('#clipDesc_'+this.cur_clip.id).hide();
+                                       this.cur_clip = clip;
+                                       $j('#clipDesc_'+this.cur_clip.id).show();
+                               }                                                               
+                               break;
+                       }
+                       pl_sum_time+=clip.getDuration();
+               }                               
+               
+               //issue thumbnail update request: (if plugin supports it will render out frame 
+               // if not then we do a call to the server to get a new jpeg thumbnail  
+               this.cur_clip.embed.updateThumbTime( float_sec - pl_sum_time );
+               
+               this.cur_clip.embed.currentTime = (float_sec -pl_sum_time) + this.cur_clip.embed.start_offset ;
+               this.cur_clip.embed.seek_time_sec = (float_sec -pl_sum_time );
+               
+               //render effects ontop: (handled by doSmilActions)              
+               this.doSmilActions( single_line = true );       
+       },
+       updateBaseStatus:function(){
+               var _this = this;
+               js_log('f:updateBaseStatus');
+               $j('#ptitle_'+this.id).html(''+
+                       '<b>' + this.title + '</b> '+                           
+                       this.getClipCount()+' clips, <i>'+
+                       seconds2npt( this.getDuration() ) + '</i>');
+                       
+               //only show the inline edit button if mediaWiki write API is enabled:
+               
+               //should probably be based on if we have a provider api url
+               if( typeof wgEnableWriteAPI != 'undefined'){
+                       $j( $j.btnHtml('edit', 'editBtn_'+this.id, 'pencil', 
+                               {'style':'position:absolute;right:0;;font-size:x-small;height:10px;margin-bottom:0;padding-bottom:7px;padding-top:0;'} )
+                       ).click(function(){     
+                               _this.stop();
+                                       _this.doEditor();
+                                       return false;
+                       }).appendTo('#ptitle_'+this.id);        
+               $j('.editBtn_'+this.id).btnBind();              
+               }
+               //render out the dividers on the timeline: 
+               this.colorPlayHead();           
+               //update status:
+               this.setStatus( '0:0:00/' + seconds2npt( this.getDuration() ) );                                
+       },      
+       /*setStatus override (could call the jquery directly) */
+       setStatus:function(value){
+               $j('#mv_time_'+this.id).html( value );
+       },
+       setSliderValue:function(value){
+               if(this.cur_clip.embed){
+               //js_log('calling original embed slider with val: '+value);
+               this.cur_clip.embed.pe_setSliderValue( value );
+               //call seq playline update here
+               }
+       },      
+       getPlayHeadPos: function(prec_done){
+               var     _this = this;
+               if($j('#mv_seeker_'+this.id).length==0){
+                       //js_log('no playhead so we can\'t get playhead pos' );
+                       return 0;
+               }
+               var track_len = $j('#mv_seeker_'+this.id).css('width').replace(/px/, '');
+               //assume the duration is static and present at .duration during playback
+               var clip_perc = this.cur_clip.embed.duration / this.getDuration();
+               var perc_offset =time_offset = 0;
+               for(var i in this.default_track.clips){
+                       var clip = this.default_track.clips[i];
+                       if(this.cur_clip.id ==clip.id)break;
+                       perc_offset+=(clip.embed.duration /  _this.getDuration());
+                       time_offset+=clip.embed.duration;
+               }                
+               //run any update time line hooks:               
+               if(this.update_tl_hook){        
+                       var cur_time_ms = time_offset + Math.round(this.cur_clip.embed.duration*prec_done);
+                       if(typeof update_tl_hook =='function'){
+                               this.update_tl_hook(cur_time_ms);
+                       }else{
+                               //string type passed use eval: 
+                               eval(this.update_tl_hook+'('+cur_time_ms+');');
+                       }
+               }
+               
+               //handle offset hack @@todo fix so this is not needed:
+               if(perc_offset > .66)
+                       perc_offset+=( 8/track_len );
+               //js_log('perc:'+ perc_offset +' c:'+ clip_perc + '*' + prec_done + ' v:'+(clip_perc*prec_done));
+               return perc_offset + ( clip_perc * prec_done );
+       },
+       //attempts to load the embed object with the playlist
+       loadEmbedPlaylist: function(){
+               //js_log('load playlist');
+       },
+       /** mannages the loading of future clips
+        * called regurally while we are playing clips
+        * 
+        * load works like so: 
+        * if the current clip is full loaded 
+        *               load clips untill buffredEndTime < playlist_buffer_time load next
+        * 
+        * this won't work so well with time range loading for smil (need to work on that)   
+        */
+       loadFutureClips:function(){             
+               /*if( this.cur_clip.embed.bufferedPercent == 1){
+                       //set the buffer to the currentTime - duration 
+                       var curBuffredTime = this.cur_clip.getDuration() - this.cur_clip.embed.currentTime;             
+                       
+                       if(curBuffredTime < 0)
+                               curBuffredTime = 0;
+                               
+                       js_log( "curBuffredTime:: " + curBuffredTime );                 
+                       if( curBuffredTime <  this.playlist_buffer_time ){
+                               js_log(" we only have " + curBuffredTime + ' buffed but we need: ' +  this.playlist_buffer_time);
+                                               
+                               for(var inx = this.cur_clip.order + 1; inx < this.default_track.clips.length; inx++ ){                                  
+                                       var cClip = this.default_track.getClip( inx );                                  
+                               
+                                       //check if the clip is already loaded (add its duration)  
+                                       if( cClip.embed.bufferedPercent == 1){
+                                               curBuffredTime += cClip.embed.getDuration();
+                                       }                                                               
+                                       //check if we still have to load a resource:            
+                                       if( curBuffredTime < this.playlist_buffer_time ){
+                                               //issue the load request                                
+                                               if( cClip.embed.networkState==0 ){
+                                                       cClip.embed.load();
+                                               }
+                                               break; //check back next time
+                                       }                                                                                                                                                                
+                               }               
+                       }       
+               }*/
+       },
+       //called to play the next clip if done call onClipDone 
+       playNext: function(){
+               //advance the playhead to the next clip                 
+               var next_clip = this.getNextClip();
+               
+               if( !next_clip ){
+                       js_log('play next with no next clip... must be done:');
+                       this.onClipDone();
+                       return ;
+               }                                                                       
+               //@@todo where the plugin supports pre_loading future clips and manage that in javascript
+               //stop current clip
+               this.cur_clip.embed.stop();
+               
+               this.updateCurrentClip(next_clip);
+                               
+               this.cur_clip.embed.play();                                     
+       },
+       onClipDone:function(){
+               js_log("pl onClipDone");                
+               this.cur_clip.embed.stop();
+       },
+       updateCurrentClip:function( new_clip ){                         
+               js_log('f:updateCurrentClip:'+new_clip.id);
+               //make sure we are not switching to the current
+               if( this.cur_clip.id == new_clip.id )
+                       return js_log('trying to updateCurrentClip to same clip');
+                       
+               //keep the active play clip in sync (stop the other clip) 
+               if( this.cur_clip ){
+                       if( !this.cur_clip.embed.isStoped() )
+                                this.cur_clip.embed.stop();
+                       this.activeClipList.remove(this.cur_clip )
+               }
+                                               
+               this.activeClipList.add( new_clip );    
+                               
+               //do swap:              
+               $j('#clipDesc_'+this.cur_clip.id).hide();                       
+               this.cur_clip=new_clip;                                 
+               $j('#clipDesc_'+this.cur_clip.id).show();
+               //update the playhead: 
+               this.setSliderValue( this.cur_clip.dur_offset / this.getDuration() );                    
+       },
+       playPrev: function(){
+               //advance the playhead to the previous clip                     
+               var prev_clip = this.getPrevClip();
+               if(!prev_clip){
+                       js_log("tried to play PrevClip with no prev Clip.. setting prev_clip to start clip");
+                       prev_clip = this.start_clip; 
+               }
+               //@@todo we could do something fancy like use playlist for sets of clips where supported. 
+               // or in cases where the player nativly supports the playlist format we can just pass it in (ie m3u or xspf)
+               if(this.cur_clip.embed.supports['playlist_swap_loader']){
+                       //where the plugin supports pre_loading future clips and manage that in javascript
+                       //pause current clip
+                       this.cur_clip.embed.pause();
+                       //do swap:
+                       this.updateCurrentClip(prev_clip);                      
+                       this.cur_clip.embed.play();                     
+               }else{                  
+                       js_log('do prev hard embed swap');                                                                              
+                       this.switchPlayingClip(prev_clip);
+               }               
+       },
+       switchPlayingClip:function(new_clip){
+               //swap out the existing embed code for next clip embed code
+               $j('#mv_ebct_'+this.id).empty();
+               new_clip.embed.width=this.width;
+               new_clip.embed.height=this.height;
+               //js_log('set embed to: '+ new_clip.embed.getEmbedObj());
+               $j('#mv_ebct_'+this.id).html( new_clip.embed.getEmbedObj() );
+               this.cur_clip=new_clip;
+               //run js code: 
+               this.cur_clip.embed.pe_postEmbedJS();
+       },
+       //playlist play
+       play: function(){
+               var _this=this;
+               //js_log('pl play');
+               //hide the playlist play button: 
+               $j('#big_play_link_'+this.id).hide();                           
+               
+               //un-pause if paused:
+               if(this.paused)
+                       this.paused=false;              
+               
+               //update the control:            
+               this.start_clip = this.cur_clip;                
+               this.start_clip_src= this.cur_clip.src;
+                
+               if(this.cur_clip.embed.supports['playlist_swap_loader'] ){
+                       //set the cur_clip to active
+                       this.activeClipList.add(this.cur_clip);
+                       
+                       //navtive support:
+                       // * pre-loads clips
+                       // * mv_playlist smil extension, manages transitions animations overlays etc.                    
+                       //js_log('clip obj supports playlist swap_loader (ie playlist controlled playback)');                                                   
+                       //@@todo pre-load each clip:
+                       //play all active clips (playlist_swap_loader can have more than one clip active)                
+                       $j.each(this.activeClipList.getClipList(), function(inx, clip){ 
+                               clip.embed.play();
+                       }); 
+               }else if(this.cur_clip.embed.supports['playlist_driver']){                              
+                       //js_log('playlist_driver');
+                       //embedObject is feed the playlist info directly and manages next/prev
+                       this.cur_clip.embed.playMovieAt( this.cur_clip.order );
+               }else{
+                       //not much playlist support just play the first clip:
+                       //js_log('basic play');
+                       //play cur_clip                 
+                       this.cur_clip.embed.play();             
+               }               
+               //start up the playlist monitor 
+               this.monitor();         
+       },      
+       toggleMute:function(){
+               this.cur_clip.embed.toggleMute();
+       },      
+       pause:function(){               
+               //js_log('f:pause: playlist');
+               var ct = new Date();
+               this.pauseTime = this.currentTime;
+               this.paused=true;
+               //js_log('pause time: '+ this.pauseTime + ' call embed pause:');
+               
+               //pause all the active clips:
+               $j.each(this.activeClipList.getClipList(), function(inx, clip){ 
+                       clip.embed.pause();             
+               });
+       },
+       fullscreen:function(){
+               this.cur_clip.embed.fullscreen();
+       },
+       //playlist stops playback for the current clip (and resets state for start clips)
+       stop:function(){
+               var _this = this;
+               /*js_log("pl stop:"+ this.start_clip.id + ' c:'+this.cur_clip.id);
+               //if start clip 
+               if(this.start_clip.id!=this.cur_clip.id){
+                       //restore clipDesc visibility & hide desc for start clip: 
+                       $j('#clipDesc_'+this.start_clip.id).html('');
+                       this.start_clip.getDetail();
+                       $j('#clipDesc_'+this.start_clip.id).css({display:'none'});
+                       this.start_clip.setBaseEmbedDim(this.start_clip.embed);
+                       //equivalent of base stop
+                       $j('#'+this.start_clip.embed.id).html(this.start_clip.embed.getThumbnailHTML());
+                       this.start_clip.embed.thumbnail_disp=true;
+               }
+               //empty the play-back container
+               $j('#mv_ebct_'+this.id).empty();*/                      
+               
+               //stop all the clips: monitor: 
+               window.clearInterval( this.smil_monitorTimerId );
+               /*for (var i=0;i<this.clips.length;i++){
+                       var clip = this.clips[i];
+                       if(clip){
+                               clip.embed.stop();
+                               $j('#clipDesc_'+clip.id).hide();
+                       }
+               }*/
+               //stop, hide and remove all active clips:
+               $j.each(this.activeClipList.getClipList(), function(inx, clip){
+                       if(clip){
+                               clip.embed.stop();
+                               $j('#clipDesc_'+clip.id).hide();
+                               _this.activeClipList.remove(clip);
+                       }
+               });             
+               //set the current clip to the first clip: 
+               if(this.start_clip){
+                       this.cur_clip = this.start_clip;                
+                       //display the first clip thumb: 
+                       this.cur_clip.embed.stop();
+                       //make sure the current clip is vissable:
+                       $j('#clipDesc_'+this.cur_clip.id).show();
+               }
+               //reset the currentTime: 
+               this.currentTime = 0;
+               //FIXME still some issues with "stoping" and reseting the playlist      
+       },      
+       doSeek:function(v){
+               js_log('pl:doSeek:' + v + ' sts:' + this.seek_time_sec );
+               var _this = this;
+               var prevClip=null;                                              
+               
+               //jump to the clip in the current percent. 
+               var perc_offset=0;
+               var next_perc_offset=0;
+               for(var i in _this.default_track.clips){
+                       var clip = _this.default_track.clips[i];                
+                       next_perc_offset+=( clip.getDuration() /  _this.getDuration()) ;
+                       //js_log('on ' + clip.getDuration() +' next_perc_offset:'+ next_perc_offset);
+                       if( next_perc_offset > v ){     
+                               //pass along the relative percentage to embed object:                            
+                               //js_log('seek:'+ v +' - '+perc_offset + ') /  (' + next_perc_offset +' - '+ perc_offset);
+                               var relative_perc =  (v -perc_offset) /  (next_perc_offset - perc_offset);        
+                               //update the current clip:                                                               
+                               _this.updateCurrentClip( clip );
+                               
+                               //update the clip relative seek_time_sec
+                               _this.cur_clip.embed.doSeek( relative_perc );                                                           
+                               this.play();
+                               return '';
+                       }
+                       perc_offset = next_perc_offset;
+               }        
+       },
+       setCurrentTime: function(pos, callback){
+               js_log('pl:setCurrentTime:' + pos + ' sts:' + this.seek_time_sec );
+               var _this = this;
+               var prevClip=null;
+               
+               //jump to the clip at pos 
+               var currentOffset = 0;
+               var nextTime = 0;
+               for (var i in _this.default_track.clips) {
+                       var clip = _this.default_track.clips[i];
+                       nextTime = clip.getDuration();
+                       if (currentOffset + nextTime > pos) {
+                               //update the clip relative seek_time_sec
+                               clipTime = pos - currentOffset;
+                               if (_this.cur_clip.id != clip.id) {
+                                       _this.updateCurrentClip( clip );
+                               }                                                               
+                               _this.cur_clip.embed.setCurrentTime(clipTime, callback);
+                               _this.currentTime = pos;
+                               _this.doSmilActions();                          
+                               return '';
+                       }
+                       currentOffset += nextTime;
+               }
+       },
+       //gets playlist controls large control height for sporting 
+       //next prev button and more status display
+       getControlsHTML:function(){
+               //get controls from current clip  (add some playlist specific controls:           
+               this.cur_clip.embed.supports['prev_next']=true;         
+               return ctrlBuilder.getControls(this.cur_clip.embed);
+       },      
+       //ads colors/dividers between tracks
+       colorPlayHead: function(){
+               var _this = this;
+               
+               if( !_this.mv_seeker_width)
+                       _this.mv_seeker_width = $j('#mv_play_head_'+_this.id).width();                                  
+       
+               if( !_this.track_len ) 
+                       _this.track_len = $j('#mv_play_head_'+_this.id).width();
+                       
+               //total duration:               
+               var pl_duration = _this.getDuration();
+               
+               var cur_pixle=0;                
+               //set up _this
+               
+               //js_log("do play head total dur: "+pl_duration );
+               $j.each(this.default_track.clips, function(i, clip){            
+                       //(use getSoloDuration to not include transitions and such)      
+                       var perc = ( clip.getSoloDuration() / pl_duration );
+                       var pwidth = Math.round( perc * _this.track_len);
+                       js_log('pstatus:c:'+ clip.getDuration() + ' of '+ pl_duration+' %:' + perc + ' width: '+ pwidth + ' of total: ' + _this.track_len);
+                       //var pwidth = Math.round( perc  * _this.track_len - (_this.mv_seeker_width*perc) );
+                       
+                       //add the buffer child indicator:                                                
+                       var barHtml= '<div id="cl_status_' + clip.embed.id + '" class="cl_status"  style="' +                                   
+                                       'left:'+cur_pixle +'px;'+
+                                       'width:'+pwidth + 'px;';                                        
+                       //set left or right border based on track pos 
+                       barHtml+=( i == _this.default_track.getClipCount()-1 )?
+                                'border-left:solid thin black;':
+                                'border-right:solid thin black;';                                                                                      
+                       barHtml+= 'filter:alpha(opacity=40);'+
+                                       '-moz-opacity:.40;">';  
+                       
+                       barHtml+= ctrlBuilder.getMvBufferHtml();
+                       
+                       barHtml+='</div>';
+                       
+                       //background:#DDD +clip.getColor();
+                       
+                       $j('#mv_play_head_'+_this.id).append(barHtml);
+                                                                                                                                                                                                               
+                       //js_log('offset:' + cur_pixle +' width:'+pwidth+' add clip'+ clip.id + ' is '+clip.embed.getDuration() +' = ' + perc +' of ' + _this.track_len);
+                       cur_pixle+=pwidth;                                                              
+               });                             
+       },
+       //@@todo currently not really in use
+       setUpHover:function(){
+               js_log('Setup Hover');
+               //set up hover for prev,next 
+               var th = 50;
+               var tw = th*this.pl_layout.clip_aspect;
+               var _this = this;
+               $j('#mv_prev_link_'+_this.id+',#mv_next_link_'+_this.id).hover(function() {
+                         var clip = (this.id=='mv_prev_link_'+_this.id) ? _this.getPrevClip() : _this.getNextClip();
+                         if(!clip)
+                                 return js_log('missing clip for Hover');
+                         //get the position of #mv_perv|next_link:
+                         var loc = getAbsolutePos(this.id);
+                         //js_log('Hover: x:'+loc.x + ' y:' + loc.y + ' :'+clip.img);
+                          $j("body").append('<div id="mv_Athub" style="position:absolute;' +
+                                  'top:'+loc.y+'px;left:'+loc.x+'px;width:'+tw+'px;height:'+th+'px;">'+
+                               '<img style="border:solid 2px '+clip.getColor()+';position:absolute;top:0px;left:0px;" width="'+tw+'" height="'+th+'" src="'+clip.img+'"/>'+
+                       '</div>');
+         }, function() {
+                         $j('#mv_Athub').remove();
+         });    
+       },
+       //@@todo we need to move a lot of this track logic like "cur_clip" to the track Obj
+       // and have the playlist just drive the tracks. 
+       getNextClip:function( track ){
+               if(!track)
+                       track = this.default_track;             
+               var tc = parseInt(this.cur_clip.order) + 1;
+               var cat = track;                
+               if( tc > track.getClipCount() -1 )
+                       return false; // out of range
+               
+               return   track.getClip( tc );
+       },      
+       getPrevClip:function( track ) {
+               if(!track)
+                       track = this.default_track;             
+               var tc = parseInt(this.cur_clip.order) - 1;
+               if( tc < 0 )
+                       return false;
+               return track.getClip( tc );  
+       },
+       /* 
+        * generic add Clip to ~default~ track
+        */
+       addCliptoTrack: function(clipObj, pos){
+               if( typeof clipObj['track_id'] =='undefined'){
+                       var track = this.default_track;
+               }else{
+                       var track = this.tracks[ clipObj.track_id ]
+               }
+               js_log('add clip:' + clipObj.id +' to track: at:' + pos);               
+               //set the first clip to current (maybe deprecated ) 
+               if(clipObj.order==0){
+                       if(!this.cur_clip)this.cur_clip=clipObj;
+               }               
+               track.addClip(clipObj, pos);            
+       },
+       swapClipDesc: function(req_clipID, callback){
+               //hide all but the requested
+               var _this=this;
+               js_log('r:'+req_clipID+' cur:'+_this.id);
+               if(req_clipID==_this.cur_clip.id){
+                       js_log('no swap to same clip');
+               }else{
+                       //fade out clips
+                       req_clip=null;
+                       $j.each(this.default_track.clips, function(i, clip){
+                               if(clip.id!=req_clipID){
+                                       //fade out if display!=none already
+                                       if($j('#clipDesc_'+clip.id).css('display')!='none'){
+                                               $j('#clipDesc_'+clip.id).fadeOut("slow");
+                                       }
+                               }else{
+                                       req_clip =clip;
+                               }
+                       });
+                       //fade in requested clip *and set req_clip to current
+                       $j('#clipDesc_'+req_clipID).fadeIn("slow", function(){
+                                       _this.cur_clip = req_clip;
+                                       if(callback)
+                                               callback();
+                       });             
+               }
+       },
+       //this is pretty outdated:       
+       getPLControls: function(){
+               js_log('getPL cont');
+               return   '<a id="mv_prev_link_'+this.id+'" title="Previus Clip" onclick="document.getElementById(\''+this.id+'\').playPrev();return false;" href="#">'+
+                                       getTransparentPng({id:'mv_prev_btn_'+this.id,style:'float:left',width:'27', height:'27', border:"0", 
+                                               src:mv_skin_img_path + 'vid_prev_sm.png' }) + 
+                               '</a>'+
+                               '<a id="mv_next_link_'+this.id+'"  title="Next Clip"  onclick="document.getElementById(\''+this.id+'\').playNext();return false;" href="#">'+
+                                       getTransparentPng({id:'mv_next_btn_'+this.id,style:'float:left',width:'27', height:'27', border:"0", 
+                                               src:mv_skin_img_path + 'vid_next_sm.png' }) + 
+                               '</a>';         
+       },
+       run_transition: function( clip_inx, trans_type){                
+               if(typeof this.default_track.clips[ clip_inx ][ trans_type ] == 'undefined')
+                       clearInterval( this.default_track.clips[ clip_inx ].timerId );
+               else
+                       this.default_track.clips[ clip_inx ][ trans_type ].run_transition();            
+       }
+}
+
+/* Object Stubs: 
+ * 
+ * @videoTrack ... stores clips and layer info
+ * 
+ * @clip... each clip segment is a clip object. 
+ * */
+var mvClip = function(o) {     
+       if(o)
+               this.init(o);
+       return this;
+};
+//set up the mvPlaylist object
+mvClip.prototype = {
+       id:null, //clip id
+       pp:null, // parent playlist
+       order:null, //the order/array key for the current clip
+       src:null,
+       info:null,
+       title:null,
+       mvclip:null,
+       type:null,
+       img:null,
+       duration:null,
+       loading:false,
+       isAnimating:false,                      
+       init:function(o){               
+               //init object including pointer to parent
+               for(var i in o){                        
+                       this[i]=o[i];
+               };              
+               js_log('id is: '+ this.id);
+       },
+       //setup the embed object:
+       setUpEmbedObj:function(){       
+               js_log('mvClip:setUpEmbedObj()');       
+               //init:
+               //debugger;
+               
+               
+               this.embed=null;                
+               //js_log('setup embed for clip '+ this.id + ':id is a function?'); 
+               //set up the pl_mv_embed object:
+               var init_pl_embed={id:'e_'+this.id,
+                       pc:this, //parent clip
+                       src:this.src
+               };
+
+               this.setBaseEmbedDim(init_pl_embed);
+               //always display controls for playlists: 
+               
+               //if in sequence mode hide controls / embed links                
+               //                      init_pl_embed.play_button=false;
+               init_pl_embed.controls=false;   
+               //if(this.pp.sequencer=='true'){
+               init_pl_embed.embed_link=null;  
+               init_pl_embed.linkback=null;    
+               
+               if(this.poster)init_pl_embed['thumbnail']=this.poster;
+               
+               if( this.type )init_pl_embed['type'] = this.type;
+               
+               this.embed = new PlMvEmbed( init_pl_embed );
+                               
+               //js_log('media Duration:' + this.embed.getDuration() );
+               //js_log('media element:'+ this.embed.media_element.length);
+               //js_log('type of embed:' + typeof(this.embed) + ' seq:' + this.pp.sequencer+' pb:'+ this.embed.play_button);           
+       },
+       doAdjust:function(side, delta){
+               js_log("f:doAdjust: " + side + ' , ' +  delta);
+               if(this.embed){         
+                       if(side=='start'){
+                               var start_offset =parseInt(this.embed.start_offset)+parseInt(delta*-1);                         
+                               this.embed.updateVideoTime( seconds2npt(start_offset), seconds2npt ( this.embed.start_offset + this.embed.getDuration() ) );
+                       }else if(side=='end'){
+                               var end_offset = parseInt(this.embed.start_offset) + parseInt( this.embed.getDuration() ) + parseInt(delta);
+                               this.embed.updateVideoTime( seconds2npt(this.embed.start_offset), seconds2npt(end_offset) );
+                       }
+                       //update everything: 
+                       this.pp.refresh();
+                       /*var base_src = this.src.substr(0,this.src.indexOf('?'));
+                       js_log("delta:"+ delta);
+                       if(side=='start'){
+                               //since we adjust start invert the delta: 
+                               var start_offset =parseInt(this.embed.start_offset/1000)+parseInt(delta*-1);
+                               this.src = base_src +'?t='+ seconds2npt(start_offset) +'/'+ this.embed.end_ntp;                                                 
+                       }else if(side=='end'){
+                               //put back into seconds for adjustment: 
+                               var end_offset = parseInt(this.embed.start_offset/1000) + parseInt(this.embed.duration/1000) + parseInt(delta);
+                               this.src = base_src +'?t='+ this.embed.start_ntp +'/'+ seconds2npt(end_offset);
+                       }                               
+                       this.embed.updateVideoTime( this.src );
+                       //update values
+                       this.duration = this.embed.getDuration();
+                       this.pp.pl_duration=null;
+                       //update playlist stuff:
+                       this.pp.updateTitle();*/
+               }
+       },      
+       getDuration:function(){         
+               if(!this.embed)this.setUpEmbedObj();            
+               return this.embed.getDuration();
+       },
+       setBaseEmbedDim:function(o){
+               if(!o)o=this;
+               //o.height=Math.round(pl_layout.clip_desc*this.pp.height)-2;//give it some padding:
+               //o.width=Math.round(o.height*pl_layout.clip_aspect)-2;
+               o.height=       this.pp.height;
+               o.width =       this.pp.width;  
+       },              
+       //output the detail view:
+       //@@todo
+       /*getDetail:function(){
+               //js_log('get detail:' + this.pp.title);
+               var th=Math.round( this.pl_layout.clip_desc * this.pp.height ); 
+               var tw=Math.round( th * this.pl_layout.clip_aspect );           
+               
+               var twDesc = (this.pp.width-tw)-2;
+               
+               if(this.title==null)
+                       this.title='clip ' + this.order + ' ' +this.pp.title;
+               if(this.desc==null)
+                       this.desc=this.pp.desc;
+               //update the embed html: 
+               this.embed.getHTML();
+                                       
+               $j(this.embed).css({ 'position':"absolute",'top':"0px", 'left':"0px"});
+               
+               //js_log('append child to:#clipDesc_'+this.id);
+               if($j('#clipDesc_'+this.id).get(0)){
+                       $j('#clipDesc_'+this.id).get(0).appendChild(this.embed);
+                       
+                       $j('#clipDesc_'+this.id).append(''+
+                       '<div id="pl_desc_txt_'+this.id+'" class="pl_desc" style="position:absolute;left:'+(tw+2)+'px;width:'+twDesc+'px;height:'+th+'px;overflow:auto;">'+
+                                       '<b>'+this.title+'</b><br>'+                    
+                                       this.desc + '<br>' + 
+                                       '<b>clip length:</b> '+ this.embed.getDurationNTP()+ 
+                       '</div>');              
+               }
+       },*/
+       getTitle:function(){
+               if(typeof this.title == 'string')
+                       return this.title
+                       
+               return 'untitled clip ' + this.order;
+       },
+       getClipImg:function(start_offset, size){
+               js_log('f:getClipImg ' + start_offset + ' s:'+size);    
+               if( !this.img){                 
+                       return mv_default_thumb_url; 
+               }else{
+                       if(!size && !start_offset){                     
+                               return this.img;
+                       }else{
+                               //if a metavid image (has request parameters) use size and time args
+                               if(this.img.indexOf('?')!=-1){
+                                       js_log('get with offset: '+ start_offset);
+                                       var time = seconds2npt( start_offset+ (this.embed.start_offset/1000) );
+                                       js_log("time is: " + time);
+                                       this.img = this.img.replace(/t\=[^&]*/gi, "t="+time);
+                                       if(this.img.indexOf('&size=')!=-1){
+                                               this.img = this.img.replace(/size=[^&]*/gi, "size="+size);
+                                       }else{
+                                               this.img+='&size='+size;
+                                       }
+                               }
+                               return this.img;                                
+                       }
+               }
+       },
+       getColor: function(){
+               //js_log('get color:'+ num +' : '+  num.toString().substr(num.length-1, 1) + ' : '+colors[ num.toString().substr(num.length-1, 1)] );
+               var num = this.id.substr( this.id.length-1, 1);
+               if(!isNaN(num)){
+                       num=num.charCodeAt(0);
+               }
+               if(num >= 10)num=num % 10;
+               return mv_clip_colors[num];
+       }       
+}
+/* mv_embed extensions for playlists */
+var PlMvEmbed=function(vid_init){
+       //js_log('PlMvEmbed: '+ vid_init.id);   
+       //create the div container
+       var ve = document.createElement('div');
+       //extend ve with all this 
+       this.init(vid_init);    
+       for(method in this){
+               if(method!='readyState'){                                       
+                       ve[method]= this[method];
+               }
+       }
+       js_log('ve src len:'+ ve.media_element.sources.length);
+       return ve;
+}
+//all the overwritten and new methods for playlist extension of baseEmbed
+PlMvEmbed.prototype = {        
+       init:function(vid_init){                                
+               //send embed_video a created video element: 
+               ve = document.createElement('div');
+               for(var i in vid_init){         
+                       //set the parent clip pointer:   
+                       if(i=='pc'){
+                               this['pc']=vid_init['pc'];
+                       }else{
+                               ve.setAttribute(i,vid_init[i]);
+                       }
+               }
+               var videoInterface = new embedVideo(ve);                        
+               //inherit the videoInterface
+               for( method in videoInterface ){                        
+                       if(method!='style'){
+                               if( this[ method ] ){
+                                       //parent embed method preservation:
+                                       this['pe_'+method]=videoInterface[method];      
+                               }else{
+                                       this[method]=videoInterface[method];
+                               }
+                       }                       
+                       //string -> boolean:
+                       if(this[method]=="false")this[method]=false;
+                       if(this[method]=="true")this[method]=true;
+               }                                               
+       },      
+       onClipDone:function(){
+               js_log('pl onClipDone (should go to next)');
+               //go to next in playlist: 
+               this.pc.pp.playNext();                  
+       },      
+       stop:function(){
+               js_log('pl:do stop');
+               //set up convenience pointer to parent playlist
+               var _this = this.pc.pp;                         
+                                       
+               var th=Math.round( _this.pl_layout.clip_desc * _this.height );  
+               var tw=Math.round( th * _this.pl_layout.clip_aspect );
+               //run the parent stop:
+               this.pe_stop();
+               var pl_height = (_this.sequencer=='true')?_this.height+27:_this.height;
+               
+               this.getHTML();
+                               
+       },
+       play:function(){
+               //js_log('pl eb play');         
+               var _this = this.pc.pp; 
+               //check if we are already playing
+               if( !this.thumbnail_disp ){
+                       this.pe_play(); 
+                       return '';
+               }
+               mv_lock_vid_updates=true;                                
+               this.pe_play();                 
+       },
+       //do post interface operations
+       postEmbedJS:function(){         
+               //add playlist clips (if plugin supports it) 
+               if(this.pc.pp.cur_clip.embed.playlistSupport())
+                       this.pc.pp.loadEmbedPlaylist();
+               //color playlist points (if play_head present)
+               if(this.pc.pp.disp_play_head)
+                       this.pc.pp.colorPlayHead();
+               //setup hover images (for playhead and next/prev buttons)
+               this.pc.pp.setUpHover();
+               //call the parent postEmbedJS
+                this.pe_postEmbedJS();
+                mv_lock_vid_updates=false;
+       },
+       getPlayButton:function(){
+               return this.pe_getPlayButton(this.pc.pp.id);
+       },      
+       setStatus:function(value){              
+               //status updates handled by playlist obj
+       },
+       setSliderValue:function(value){
+               //setSlider value handled by playlist obj               
+       }       
+}
+
+/* 
+ *  m3u parse
+ */
+var m3uPlaylist = {
+       doParse:function(){
+               //for each line not # add as clip 
+               var inx =0;
+               var this_pl = this;
+               //js_log('data:'+ this.data.toString());
+               $j.each(this.data.split("\n"), function(i,n){                   
+                       //js_log('on line '+i+' val:'+n+' len:'+n.length);
+                       if(n.charAt(0)!='#'){
+                               if(n.length>3){ 
+                                       //@@todo make sure its a valid url
+                                       //js_log('add url: '+i + ' '+ n);
+                                       var cur_clip = new mvClip({type:'srcClip',id:'p_'+this_pl.id+'_c_'+inx,pp:this_pl,src:n,order:inx});
+                                       //setup the embed object 
+                                       cur_clip.setUpEmbedObj();
+                                       js_log('m3uPlaylist len:'+ thisClip.embed.media_element.sources.length);        
+                                       this_pl.addCliptoTrack(cur_clip);                                       
+                                       inx++;
+                               }
+                       }
+               });
+               return true;
+       }
+}
+
+var itunesPlaylist = {
+       doParse:function(){ 
+               var properties = { title:'title', linkback:'link', 
+                                                  author:'itunes:author',desc:'description',
+                                                  date:'pubDate' };
+               var tmpElm = null;
+               for(i in properties){
+                       tmpElm = this.data.getElementsByTagName(properties[i])[0];
+                       if(tmpElm){
+                               this[i] = tmpElm.childNodes[0].nodeValue;
+                               //js_log('set '+i+' to '+this[i]);
+                       }
+               }
+               //image src is nested in itunes rss:
+               tmpElm = this.data.getElementsByTagName('image')[0];
+               if(tmpElm){
+                       imgElm = tmpElm.getElementsByTagName('url')[0];
+                               if(imgElm){
+                                       this.img = imgElm.childNodes[0].nodeValue;
+                               }
+               }
+               //get the clips: 
+               var clips = this.data.getElementsByTagName("item");
+               properties.src = 'guid';
+               for (var i=0;i<clips.length;i++){
+                       var cur_clip = new mvClip({type:'srcClip',id:'p_'+this.id+'_c_'+i,pp:this,order:i});                    
+                       for(var j in properties){
+                               tmpElm = clips[i].getElementsByTagName( properties[j] )[0];
+                               if(tmpElm!=null){
+                                       cur_clip[j] = tmpElm.childNodes[0].nodeValue;
+                                       //js_log('set clip property: ' + j+' to '+cur_clip[j]);
+                               }
+                       }
+                       //image is nested
+                       tmpElm = clips[i].getElementsByTagName('image')[0];
+                       if(tmpElm){
+                               imgElm = tmpElm.getElementsByTagName('url')[0];
+                                       if(imgElm){
+                                               cur_clip.img = imgElm.childNodes[0].nodeValue;
+                                       }
+                       }
+                       //set up the embed object now that all the values have been set
+                       cur_clip.setUpEmbedObj();
+                       
+                       //add the current clip to the clip list
+                       this.addCliptoTrack(cur_clip);
+               }
+               return true;
+       }
+}
+
+/* 
+ * parse xsfp: 
+ * http://www.xspf.org/xspf-v1.html
+ */
+var xspfPlaylist ={
+       doParse:function(){
+               //js_log('do xsfp parse: '+ this.data.innerHTML);
+               var properties = { title:'title', linkback:'info', 
+                                                  author:'creator',desc:'annotation',
+                                                  poster:'image', date:'date' };
+               var tmpElm = null;
+               //get the first instance of any of the meta tags (ok that may be the meta on the first clip)
+               //js_log('do loop on properties:' + properties);
+               for(i in properties){
+                       js_log('on property: '+i);                      
+                       tmpElm = this.data.getElementsByTagName(properties[i])[0];
+                       if(tmpElm){
+                               if(tmpElm.childNodes[0]){
+                                       this[i] = tmpElm.childNodes[0].nodeValue;
+                                       js_log('set pl property: ' + i+' to '+this[i]);
+                               }
+                       }
+               }
+               var clips = this.data.getElementsByTagName("track");
+               js_log('found clips:'+clips.length);
+               //add any clip specific properties 
+               properties.src = 'location';
+               for (var i=0;i<clips.length;i++){
+                       var cur_clip = new mvClip({id:'p_'+this.id+'_c_'+i,pp:this,order:i});                   
+                       //js_log('cur clip:'+ cur_clip.id);
+                       for(var j in properties){
+                               tmpElm = clips[i].getElementsByTagName( properties[j] )[0];
+                               if(tmpElm!=null){                               
+                                       if( tmpElm.childNodes.length!=0){
+                                               cur_clip[j] = tmpElm.childNodes[0].nodeValue;
+                                               js_log('set clip property: ' + j+' to '+cur_clip[j]);
+                                       }
+                               }
+                       }                       
+                       //add mvClip ref from info link: 
+                       if(cur_clip.linkback){
+                               //if mv linkback
+                               mvInx = 'Stream:';
+                               mvclippos = cur_clip.linkback.indexOf(mvInx);
+                               if(mvclippos!==false){
+                                       cur_clip.mvclip=cur_clip.linkback.substr( mvclippos+mvInx.length );
+                               }
+                       }                       
+                       //set up the embed object now that all the values have been set
+                       cur_clip.setUpEmbedObj();
+                       //add the current clip to the clip list
+                       this.addCliptoTrack(cur_clip);
+               }
+               //js_log('done with parse');
+               return true;
+       }
+}
+/*****************************
+ * SMIL CODE (could be put into another js file / lazy_loaded for improved basic playlist performance / modularity)
+ *****************************/
+/*playlist driver extensions to the playlist object*/
+mvPlayList.prototype.monitor = function(){     
+       //js_log('pl:monitor');                 
+       //if paused stop updates
+       if( this.paused ){
+               //clearInterval( this.smil_monitorTimerId );
+               return ;
+       }
+       //js_log("pl check: " + this.currentTime + ' > '+this.getDuration());
+       //check if we should be done:
+       if( this.currentTime >  this.getDuration() ) 
+               this.stop();
+       
+       //update the playlist current time: 
+       //check for a trsnOut from the previus clip to subtract
+       /*var prev_clip =  this.getPrevClip();
+       var transOffset = 0;
+       if( prev_clip.id != this.cur_clip.id ){
+               if( prev_clip.transOut ){
+                       transOffset = prev_clip.transOut.getDuration();
+                       js_log("should add: " + transOffset + " off:" + this.cur_clip.dur_offset+  " to " +this.cur_clip.embed.currentTime +
+                                ' = ' + ( this.cur_clip.dur_offset + this.cur_clip.embed.currentTime + transOffset) );
+               }
+       }*/
+       this.currentTime = this.cur_clip.dur_offset + this.cur_clip.embed.relativeCurrentTime();        
+               
+       //update slider: 
+       if(!this.userSlide){
+               this.setStatus(seconds2npt(this.currentTime) + '/' + seconds2npt(this.getDuration()) );                         
+               this.setSliderValue(this.currentTime / this.getDuration());
+       }
+       //pre-load any future clips:
+       this.loadFutureClips();
+       
+       
+       //status updates are handled by children clips ... playlist mostly manages smil actions
+       this.doSmilActions();   
+       
+       if( ! this.smil_monitorTimerId ){
+               if(document.getElementById(this.id)){
+                       this.smil_monitorTimerId = setInterval('$j(\'#'+this.id+'\').get(0).monitor()', 250);
+               }
+       }
+}
+//handles the rendering of overlays load of future clips (if necessary)
+//@@todo could be lazy loaded if necessary 
+mvPlayList.prototype.doSmilActions = function( single_frame ){          
+       //js_log('f:doSmilActions: ' + this.cur_clip.id + ' tid: ' + this.cur_clip.transOut );
+       var offSetTime = 0; //offset time should let us start a transition later on if we have to. 
+       var _clip = this.cur_clip;      //setup a local pointer to cur_clip
+       
+       
+       //do any smil time actions that may change the current clip
+       if( this.userSlide ){
+               //current clip set is set via updateThumbTime function                   
+       }else{
+               //assume playing and go to next: 
+               if( _clip.dur <= _clip.embed.currentTime 
+                        && _clip.order != _clip.pp.getClipCount()-1 ){
+                       //force next clip
+                       js_log('order:'  + _clip.order + ' != count:' + ( _clip.pp.getClipCount()-1 ) +
+                               ' smil dur: ' + _clip.dur + ' <= curTime: ' + _clip.embed.currentTime + ' go to next clip..');          
+                               //do a _play next:
+                               _clip.pp.playNext();                            
+               }
+       }                                               
+       //@@todo could maybe generalize transIn with trasOut into one "flow" with a few scattered if statements 
+       //update/setup all transitions (will render current transition state)   
+       var in_range=false;
+       //pretty similar actions per transition types so group into a loop:
+       var tran_types = {'transIn':true,'transOut':true};
+       for(var tid in tran_types ){                            
+               eval('var tObj =  _clip.'+tid);         
+               if(!tObj)
+                       continue;                       
+               //js_log('f:doSmilActions: ' + _clip.id + ' tid:'+tObj.id + ' tclip_id:'+ tObj.pClip.id);                                       
+               //make sue we are in range: 
+               if( tid=='transIn' )
+                       in_range = (_clip.embed.currentTime <= tObj.dur)?true:false;                    
+               
+               if( tid=='transOut' )
+                       in_range = (_clip.embed.currentTime >= (_clip.dur - tObj.dur))?true:false;
+               
+               if( in_range ){
+                       if( this.userSlide || single_frame ){                           
+                               if( tid=='transIn' )
+                                       mvTransLib.doUpdate(tObj, (_clip.embed.currentTime / tObj.dur) );
+                                       
+                               if( tid=='transOut' )
+                                       mvTransLib.doUpdate(tObj, (_clip.embed.currentTime-(_clip.dur - tObj.dur)) /tObj.dur);
+                                       
+                       }else{
+                               if( tObj.animation_state==0 ){
+                                       js_log('init/run_transition ');
+                                       tObj.run_transition();  
+                               }
+                       }
+               }else{
+                       //close up transition if done & still onDispaly
+                       if( tObj.overlay_selector_id ){
+                               js_log('close up transition :'+tObj.overlay_selector_id);
+                               mvTransLib.doCloseTransition( tObj );
+                       }
+               }
+       }                                                                                                                                                                       
+}
+
+/*
+ * mvTransLib library of transitions
+ * a single object called to initiate transition effects can easily be extended in separate js file
+ * /mvTransLib is a all static object no instances of mvTransLib/
+ * (that way a limited feature set "sequence" need not include a _lot_ of js unless necessary )
+ * 
+ * Smil Transition Effects see:  
+ * http://www.w3.org/TR/SMIL3/smil-transitions.html#TransitionEffects-TransitionAttribute
+ */                    
+var mvTransLib = {
+       /*
+        * function doTransition lookups up the transition in the  mvTransLib obj
+        *               and init the transition if its available 
+        * @param tObj transition attribute object
+        * @param offSetTime default value 0 if we need to start rendering from a given time 
+        */
+       doInitTransition:function(tObj){
+               js_log('mvTransLib:f:doInitTransition');                
+               if(!tObj.type){
+                       js_log('transition is missing type attribute');
+                       return false;
+               }
+               
+               if(!tObj.subtype){
+                       js_log('transition is missing subtype attribute');
+                       return false;
+               }
+               
+               if(!this['type'][tObj.type]){
+                       js_log('mvTransLib does not support type: '+tObj.type);
+                       return false;
+               }
+               
+               if(!this['type'][tObj.type][tObj.subtype]){
+                       js_log('mvTransLib does not support subType: '+tObj.subtype);
+                       return false;
+               }                               
+                               
+               //setup overlay_selector_id                     
+               if(tObj.subtype=='crossfade'){
+                       if(tObj.transAttrType=='transIn')                               
+                               var other_pClip = tObj.pClip.pp.getPrevClip();
+                       if(tObj.transAttrType=='transOut')
+                               var other_pClip = tObj.pClip.pp.getNextClip();
+                               
+                       if(typeof(other_pClip)=='undefined' || other_pClip === false || other_pClip.id == tObj.pClip.pp.cur_clip.id)
+                               js_log('Error: crossfade without target media asset');
+                       //if not sliding start playback: 
+                       if(!tObj.pClip.pp.userSlide){                   
+                               other_pClip.embed.play();
+                               //manualy ad the extra layer to the activeClipList
+                               tObj.pClip.pp.activeClipList.add( other_pClip );
+                       }                                               
+                       tObj.overlay_selector_id = 'clipDesc_'+other_pClip.id;                  
+               }else{
+                       tObj.overlay_selector_id =this.getOverlaySelector(tObj);                                                                                                                                
+               }                               
+                                       
+               //all good call function with  tObj param
+               js_log('should call: '+tObj.type + ' ' + tObj.subtype );
+               this['type'][tObj.type][tObj.subtype].init(tObj);                                       
+       },
+       doCloseTransition:function(tObj){
+               if(tObj.subtype=='crossfade'){
+                       //close up crossfade
+                       js_log("close up crossfade");   
+               }else{
+                       $j('#'+tObj.overlay_selector_id).remove();
+               }
+               //null selector: 
+               tObj.overlay_selector_id=null;
+       },
+       getOverlaySelector:function(tObj){      
+               var overlay_selector_id= tObj.transAttrType + tObj.pClip.id;     
+               js_log('f:getOverlaySelector: '+overlay_selector_id + ' append to: ' +'#videoPlayer_'+tObj.pClip.embed.id );
+               //make sure overlay_selector_id not already here:       
+               if( $j('#'+overlay_selector_id).length == 0  ){                                                                                                                                                                                                          
+                       $j('#videoPlayer_'+tObj.pClip.embed.id).prepend(''+
+                               '<div id="'+overlay_selector_id+'" ' +
+                                       'style="position:absolute;top:0px;left:0px;' +
+                                       'height:'+parseInt(tObj.pClip.pp.height)+'px;'+
+                                       'width:'+parseInt(tObj.pClip.pp.width)+'px;' +                                  
+                                       'z-index:2">' +
+                               '</div>');
+               }                               
+               return overlay_selector_id;     
+       },
+       doUpdate:function(tObj, percent){
+               //init the transition if nessesary:
+               if(!tObj.overlay_selector_id)
+                       this.doInitTransition(tObj);
+               
+               //@@todo we should ensure visability outside of doUpate loop                    
+               if(!$j('#'+tObj.overlay_selector_id).is(':visible'))
+                       $j('#'+tObj.overlay_selector_id).show();
+                       
+               //do update:
+               /*js_log('doing update for: '+ tObj.pClip.id + 
+                       ' type:' + tObj.transAttrType +
+                       ' t_type:'+ tObj.type +
+                       ' subypte:'+ tObj.subtype  + 
+                       ' percent:' + percent);*/                                       
+                       
+               this['type'][tObj.type][tObj.subtype].u(tObj,percent);
+       },
+       getTransitionIcon:function( type, subtype){
+               return mv_embed_path +'/skins/'+mv_skin_name+'/transition_images/'+ type+'_'+ subtype+ '.png';
+       },
+       /*
+        * mvTransLib: functional library mapping:
+        */ 
+       type:{
+               //types:
+               fade:{
+                       fadeFromColor:{ 
+                               'attr':['fadeColor'],                   
+                               'init':function(tObj){                                                                          
+                                       //js_log('f:fadeFromColor: '+tObj.overlay_selector_id +' to color: '+ tObj.fadeColor);
+                                       if(!tObj.fadeColor)
+                                               js_log('missing fadeColor');                                                    
+                                       if($j('#'+tObj.overlay_selector_id).length==0){
+                                               js_log("ERROR can't find: "+ tObj.overlay_selector_id);
+                                       }       
+                                       //set the initial state
+                                       $j('#'+tObj.overlay_selector_id).css({
+                                               'background-color':tObj.fadeColor,
+                                               'opacity':"1"
+                                       });
+                               },                      
+                               'u':function(tObj, percent){
+                                       //js_log(':fadeFromColor:update: '+ percent);
+                                       //fade from color (invert the percent)
+                                       var percent = 1- percent;
+                                       $j('#'+tObj.overlay_selector_id).css({
+                                               "opacity" : percent
+                                       });
+                               }
+                       },
+                       //corssFade
+                       crossfade:{
+                               "attr":[],
+                               "init":function(tObj){
+                                       js_log('f:crossfade: '+tObj.overlay_selector_id);
+                                       if($j('#'+tObj.overlay_selector_id).length==0)
+                                               js_log("ERROR overlay selector not found: "+tObj.overlay_selector_id);
+                                       
+                                       //set the initial state show the zero opacity animation 
+                                       $j('#'+tObj.overlay_selector_id).css({'opacity':0}).show();                                                                     
+                               },
+                               'u':function(tObj, percent){
+                                       $j('#'+tObj.overlay_selector_id).css({
+                                               "opacity" : percent
+                                       });
+                               }
+                       }                       
+               }                                                       
+       }
+}
+
+/* object to manage embedding html with smil timings 
+ *  grabs settings from parent clip 
+ */
+var transitionObj = function(element) {                
+       this.init(element);
+};
+transitionObj.prototype = {    
+       supported_attributes : new Array(
+               'id',
+               'type',
+               'subtype',
+               'fadeColor',
+               'dur'
+       ),
+       transAttrType:null, //transIn or transOut
+       overlay_selector_id:null,
+       pClip:null,
+       timerId:null,
+       animation_state:0, //can be 0=unset, 1=running, 2=done 
+       interValCount:0, //inter-intervalCount for animating between time updates
+       dur:2, //default duration of 2  
+       init:function(element){
+               //load supported attributes:     
+               var _this = this;
+               $j.each(this.supported_attributes, function(i, attr){
+                       if(element.getAttribute(attr))
+                               _this[attr]= element.getAttribute(attr);
+               });                             
+               //@@todo process duration (for now just strip s) per: 
+               //http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
+               if(_this.dur)
+                       _this.dur = smilParseTime(_this.dur);
+       },
+       /* 
+        * returns a visual representation of the transition
+        */
+       getIconSrc:function(opt){
+               //@@todo support some arguments 
+               return mvTransLib.getTransitionIcon(this.type, this.subtype);                                                                           
+       },
+       getDuration:function(){
+               return this.dur;
+       },
+       //returns the values of supported_attributes: 
+       getAttributeObj:function(){
+               var elmObj = {};
+               for(var i in this.supported_attributes){
+                       var attr = this.supported_attributes[i];
+                       if(this[attr])
+                               elmObj[ attr ] = this[attr]; 
+               }               
+               return elmObj;
+       },
+       /*
+        * the main animation loop called every MV_ANIMATION_CB_RATE or 34ms ~around 30frames per second~
+        */
+       run_transition:function(){
+               //js_log('f:run_transition:' + this.interValCount);
+                                                
+               //update the time from the video if native:   
+               if(typeof this.pClip.embed.vid !='undefined'){
+                       this.interValCount=0;
+                       this.pClip.embed.currentTime = this.pClip.embed.vid.currentTime;
+               }
+               
+               //}else{
+                       //relay on currentTime update grabs (every 250ms or so) (ie for images)
+               //      if(this.prev_curtime!=this.pClip.embed.currentTime){    
+               //              this.prev_curtime =     this.pClip.embed.currentTime;
+               //              this.interValCount=0;
+               //      }
+               //}             
+               //start_time =asigned by doSmilActions
+               //base_cur_time = pClip.embed.currentTime;
+               //dur = asigned by attribute            
+               if(this.animation_state==0){
+                       mvTransLib.doInitTransition(this);
+                       this.animation_state=1;
+               }
+               //set percentage include difrence of currentTime to prev_curTime 
+               // ie updated in-between currentTime updates) 
+               
+               if(this.transAttrType=='transIn')
+                       var percentage = ( this.pClip.embed.currentTime + 
+                                                                       ( (this.interValCount*MV_ANIMATION_CB_RATE)/1000 )
+                                                       ) / this.dur ;
+                               
+               if(this.transAttrType=='transOut')
+                       var percentage = (this.pClip.embed.currentTime  + 
+                                                                       ( (this.interValCount*MV_ANIMATION_CB_RATE)/1000 )
+                                                                       - (this.pClip.dur - this.dur)
+                                                       ) /this.dur ;                   
+               
+               /*js_log('percentage = ct:'+this.pClip.embed.currentTime + ' + ic:'+this.interValCount +' * cb:'+MV_ANIMATION_CB_RATE +
+                         ' / ' + this.dur + ' = ' + percentage );
+               */
+               
+               //js_log('cur percentage of transition: '+percentage);
+               //update state based on current time + cur_time_offset (for now just use pClip.embed.currentTime)
+               mvTransLib.doUpdate(this, percentage);
+               
+               if( percentage >= 1 ){
+                       js_log("transition done update with percentage "+percentage);
+                       this.animation_state=2;                                 
+                       clearInterval(this.timerId);    
+                       mvTransLib.doCloseTransition(this)
+                       return true;
+               }
+                                               
+               this.interValCount++;
+               //setInterval in we are still in running state and user is not using the playhead 
+               if( this.animation_state==1 ){
+                       if(!this.timerId){
+                               this.timerId = setInterval('document.getElementById(\'' + this.pClip.pp.id + '\').'+ 
+                                                       'run_transition(\'' + this.pClip.pp.cur_clip.order + '\','+
+                                                               '\''+ this.transAttrType + '\')',
+                                                MV_ANIMATION_CB_RATE);
+                       }
+               }else{
+                       clearInterval(this.timerId);
+               }
+               return true;
+       },
+       clone:function(){
+               var cObj = new this.constructor();
+               for(var i in this)
+                       cObj[i]=this[i];                                
+               return cObj;
+       }               
+}
+
+//very limited smile feature set more details soon:  
+//region="video_region" transIn="fromGreen" begin="2s"
+//http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#edef-ref
+var smilPlaylist ={
+       transitions:{},
+       doParse:function(){
+               var _this = this;
+               js_log('f:doParse smilPlaylist');
+               //@@todo get/parse meta that we are intersted in: 
+               var meta_tags = this.data.getElementsByTagName('meta');
+               var metaNames = {
+                       'title':'',
+                       'interface_url':"", 
+                       'linkback':"",
+                        'mTitle':"", 
+                        'mTalk':"", 
+                        'mTouchedTime':""
+               }; 
+               $j.each(meta_tags, function(i,meta_elm){
+                       //js_log( "on META tag: "+ $j(meta_elm).attr('name') );
+                       if( $j(meta_elm).attr('name') in metaNames){
+                               _this[ $j(meta_elm).attr('name') ] = $j(meta_elm).attr('content');
+                       }                       
+                       //special check for wikiDesc
+                       if(  $j(meta_elm).attr('name') == 'wikiDesc'){
+                               if(meta_elm.firstChild)
+                                       _this.wikiDesc  = meta_elm.firstChild.nodeValue;
+                       }                       
+               });     
+               //add transition objects: 
+               var transition_tags = this.data.getElementsByTagName('transition');     
+               $j.each(transition_tags, function( i, trans_elm ){              
+                       if( $j(trans_elm).attr("id") ){
+                               _this.transitions[ $j(trans_elm).attr("id")]= new transitionObj( trans_elm );
+                       }else{
+                               js_log('skipping transition: (missing id) ' + trans_elm );
+                       }
+               });
+               js_log('loaded transitions:' + _this.transitions.length);                       
+               //add seq (latter we will have support more than one seq tag) / more than one "track" 
+               var seq_tags = this.data.getElementsByTagName('seq');
+               $j.each(seq_tags, function(i,seq_elm){
+                       var inx = 0;
+                       //get all the clips for the given seq:
+                       $j.each(seq_elm.childNodes, function(i, mediaElement){ 
+                               //~complex~ @@todo to handlde a lot like "switch" "region" etc
+                               //js_log('process: ' + mediaElemnt.tagName); 
+                               if(typeof mediaElement.tagName!='undefined'){
+                                       if( _this.tryAddMedia( mediaElement, inx ) ){
+                                               inx++;
+                                       }
+                               }
+                       });
+               });     
+               js_log("done proc seq tags");           
+               return true;
+       },
+       tryAddMediaObj:function(mConfig, order, track_id){
+               var mediaElement = document.createElement('ref');       
+               for(var i =0; i < mv_smil_ref_supported_attributes.length;i++){         
+                       var attr =      mv_smil_ref_supported_attributes[i];
+                       if(mConfig[attr])
+                               $j(mediaElement).attr(attr, mConfig[attr]);
+               }                       
+               this.tryAddMedia(mediaElement, order, track_id);
+       },
+       tryAddMedia:function(mediaElement, order, track_id){    
+               js_log('SMIL:tryAddMedia:' + mediaElement);
+               var _this = this;               
+               //set up basic mvSMILClip send it the mediaElemnt & mvClip init: 
+               var clipObj = {};
+               var cConfig = {
+                                               "id":'p_' + _this.id + '_c_' + order,
+                                               "pp":this, //set the parent playlist object pointer
+                                               "order": order                                                                  
+                                       };              
+               var clipObj = new mvSMILClip(mediaElement, cConfig );
+                       
+               //set optional params track                                                                              
+               if( typeof track_id != 'undefined')
+                       clipObj["track_id"]     = track_id;
+                        
+               //debugger;
+               if ( clipObj ){
+                       //set up embed:                                         
+                       clipObj.setUpEmbedObj();                                                                
+                       //add clip to track: 
+                       this.addCliptoTrack( clipObj , order);          
+                       return true;
+               }       
+               //@@todo we could throw error details here once we integrate try catches everywhere :P
+               return false;
+       } 
+}
+//http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#smilMediaNS-BasicMedia
+//and added resource description elements
+//@@ supporting the "ID" attribute turns out to be kind of tricky since we use it internally 
+// (for now don't include) 
+var mv_smil_ref_supported_attributes = new Array(              
+               'src',
+               'type',
+               'region',
+               'transIn',
+               'transOut',
+               'fill',
+               'dur',
+               'title',
+               
+               'uri',                  
+               'poster'
+);
+/* extension to mvClip to support smil properties */
+var mvSMILClip=function(sClipElm, mvClipInit){
+       return this.init(sClipElm, mvClipInit);
+}
+//all the overwritten and new methods for SMIL extension of mv_embed
+mvSMILClip.prototype = {       
+       instanceOf:'mvSMILClip',        
+       params : {}, //support param as child of ref clips per SMIL spec  
+       init:function(sClipElm, mvClipInit){    
+               _this = this;                   
+               this.params     = {};           
+               //make new mvCLip with ClipInit vals  
+               var myMvClip = new mvClip( mvClipInit );
+               
+               //inherit mvClip                
+               for(var method in myMvClip){                    
+                       if(typeof this[method] != 'undefined' ){                                
+                               this['parent_'+method]=myMvClip[method];                                
+                       }else{          
+                               this[method] = myMvClip[method];
+                       }               
+               }               
+               
+               //get supported media attr init non-set         
+               for(var i =0; i < mv_smil_ref_supported_attributes.length;i++){         
+                       var attr =      mv_smil_ref_supported_attributes[i];
+                       if( $j(sClipElm).attr(attr)){
+                               _this[attr] = $j(sClipElm).attr(attr);
+                       }
+               }                               
+               this['tagName'] = sClipElm.tagName;     
+               
+               if( sClipElm.firstChild ){
+                       this['wholeText'] = sClipElm.firstChild.nodeValue;
+                       js_log("SET wholeText for: " + this['tagName'] + ' '+ this['wholeText']);
+               }
+               //debugger;
+               //mv_embed specific property: 
+               if( $j(sClipElm).attr('poster') )
+                       this['img'] = $j(sClipElm).attr('poster');
+               
+               //lookup and assign copies of transitions 
+               // (since transition needs to hold some per-instance state info)                
+               if(this.transIn && this.pp.transitions[ this.transIn ]){                        
+                       this.transIn = this.pp.transitions[ this.transIn ].clone();
+                       this.transIn.pClip = _this;
+                       this.transIn.transAttrType='transIn';            
+               }               
+               
+               if(this.transOut && this.pp.transitions[ this.transOut ]){              
+                       this.transOut = this.pp.transitions[ this.transOut ].clone();
+                       this.transOut.pClip = _this;
+                       this.transOut.transAttrType = 'transOut';               
+               }               
+               //parse duration / begin times: 
+               if( this.dur )
+                       this.dur = smilParseTime( this.dur );                                                                   
+               
+               //conform type to vido/ogg:
+               if( this.type == 'application/ogg' )
+                       this.type = 'video/ogg'; //conform to 'video/ogg' type
+                               
+               //if unset type and we have innerHTML assume text/html type             
+               if( !this.type  && this.wholeText ){                    
+                       this.type = 'text/html';
+               }                               
+               //also grab andy child param elements if present: 
+               if( sClipElm.getElementsByTagName('param')[0] ){                                        
+                       for(var i=0; i< sClipElm.getElementsByTagName('param').length; i++){
+                               this.params[ sClipElm.getElementsByTagName('param')[i].getAttribute("name") ] = 
+                                                sClipElm.getElementsByTagName('param')[i].firstChild.nodeValue;
+                       }                       
+               }                                       
+               return this;            
+       },      
+       //returns the values of supported_attributes: 
+       getAttributeObj:function(){
+               var elmObj = {};
+               for(var i=0; i < mv_smil_ref_supported_attributes.length; i++){
+                       var attr = mv_smil_ref_supported_attributes[i];
+                       if(this[attr])
+                               elmObj[ attr ] = this[attr]; 
+               }               
+               return elmObj;
+       },
+       /*
+        * getDuration
+        * @returns duration in int
+        */
+       getDuration:function(){                                 
+               //check for smil dur: 
+               if( this.dur )
+                       return this.dur;                        
+               return this.embed.getDuration();                                        
+       },
+       //gets the duration of the clip subracting transitions
+       getSoloDuration:function(){
+               var fulldur = this.getDuration();
+               //see if we need to subtract from time eating transitions (transOut)
+               if(this.transOut)
+                       fulldur -= this.transOut.getDuration();
+
+               js_log("getSoloDuration:: td: " + this.getDuration() + ' sd:' + fulldur);
+               return fulldur;
+       }
+}
+/*
+ * takes an input 
+ * @time_str input time string 
+ * returns time in seconds 
+ * 
+ * @@todo process duration (for now just srip s) per: 
+ * http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
+ * (probably have to use a Time object to fully support the smil spec
+ */
+function smilParseTime(time_str){
+       //first check for hh:mm:ss time: 
+       if(time_str.split(':').length == 3){
+               return npt2seconds(time_str);
+       }else{
+               //assume 34s secconds representation 
+               return parseInt(time_str.replace('s', ''));
+       }
+}
+//stores a list pointers to active clips (maybe this should just be a property of clips (but results in lots of seeks) 
+var activeClipList = function(){
+       return this.init();
+}
+activeClipList.prototype = {
+       init:function(){
+               this.clipList = new Array();
+       },
+       add:function( clip ){
+               //make sure the clip is not already active: 
+               for(var i =0;i < this.clipList.lenght; i++){
+                       var active_clip = this.clipList[i];
+                       if(clip.id == active_clip.id) //clip already active: 
+                               return false;
+               }
+               this.clipList.push( clip );
+               return true;
+       },
+       remove:function( clip ){
+               for(var i = 0; i < this.clipList.length; i++){
+                       var active_clip = this.clipList[i];
+                       if(clip.id == active_clip.id){
+                               this.clipList.splice(i, 1);
+                               return true;
+                       }
+               }
+               return false;
+       },
+       getClipList:function(){
+               return this.clipList;
+       }       
+}
+ var trackObj = function( iObj ){
+        return this.init( iObj );
+ }
+ var supported_track_attr =
+trackObj.prototype = {
+       //should be something like "seq" per SMIL spec
+       //http://www.w3.org/TR/SMIL3/smil-timing.html#edef-seq
+       // but we don't really support anywhere near the full concept of seq containers yet either
+       supported_attributes: new Array(
+               'title',
+               'desc',
+               'inx'           
+        ),                                     
+       disp_mode:'timeline_thumb',
+       init : function(iObj){
+               if(!iObj)
+                       iObj={};
+               //make sure clips is new: 
+               this.clips = new Array();
+                               
+               var _this = this;
+               $j.each(this.supported_attributes, function(i, attr){
+                       if(iObj[attr])
+                               _this[attr] = iObj[attr];
+               });                     
+       },
+       //returns the values of supported_attributes: 
+       getAttributeObj:function(){
+               var elmObj = {};
+               for(var i in this.supported_attributes){
+                       var attr = this.supported_attributes[i];
+                       if(this[attr])
+                               elmObj[ attr ] = this[attr]; 
+               }               
+               return elmObj;
+       },
+       addClip:function(clipObj, pos){
+               js_log('pl_Track: AddClip at:' + pos + ' clen: ' + this.clips.length);  
+               if( typeof pos == 'undefined' )
+                       pos = this.clips.length;                                
+               //get everything after pos      
+               this.clips.splice(pos, 0, clipObj);                     
+               //keep the clip order values accurate:
+               this.reOrderClips();                            
+               js_log("did add now cLen: " + this.clips.length);
+       },
+       getClip:function( inx ){
+               if( !this.clips[inx] )
+                       return false;
+               return this.clips[inx];
+       },
+       reOrderClips:function(){
+               for(var k in this.clips){
+                       this.clips[k].order=k;
+               }
+       },
+       getClipCount:function(){                
+               return this.clips.length;
+       },
+       inheritEmbedObj: function(){
+               $j.each(this.clips, function(i, clip){
+                       clip.embed.inheritEmbedObj();
+               });
+       }
+};                     
+       
+/* utility functions 
+ * (could be combined with other stuff) 
+*/
+function getAbsolutePos(objectId) {
+       // Get an object left position from the upper left viewport corner
+       o = document.getElementById(objectId);
+       oLeft = o.offsetLeft;                   // Get left position from the parent object     
+       while(o.offsetParent!=null) {   // Parse the parent hierarchy up to the document element
+               oParent = o.offsetParent        // Get parent object reference
+               oLeft += oParent.offsetLeft // Add parent left position
+               o = oParent
+       }       
+       o = document.getElementById(objectId);
+       oTop = o.offsetTop;
+       while(o.offsetParent!=null) { // Parse the parent hierarchy up to the document element
+               oParent = o.offsetParent  // Get parent object reference
+               oTop += oParent.offsetTop // Add parent top position
+               o = oParent
+       }
+       return {x:oLeft,y:oTop};
+}
+String.prototype.htmlEntities = function(){
+  var chars = new Array ('&','à','á','â','ã','ä','å','æ','ç','è','é',
+                                                'ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô',
+                                                'õ','ö','ø','ù','ú','û','ü','ý','þ','ÿ','À',
+                                                'Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë',
+                                                'Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö',
+                                                'Ø','Ù','Ú','Û','Ü','Ý','Þ','€','\"','ß','<',
+                                                '>','¢','£','¤','¥','¦','§','¨','©','ª','«',
+                                                '¬','­','®','¯','°','±','²','³','´','µ','¶',
+                                                '·','¸','¹','º','»','¼','½','¾');
+
+  var entities = new Array ('amp','agrave','aacute','acirc','atilde','auml','aring',
+                                                       'aelig','ccedil','egrave','eacute','ecirc','euml','igrave',
+                                                       'iacute','icirc','iuml','eth','ntilde','ograve','oacute',
+                                                       'ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc',
+                                                       'uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc',
+                                                       'Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute',
+                                                       'Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde',
+                                                       'Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave',
+                                                       'Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig',
+                                                       'lt','gt','cent','pound','curren','yen','brvbar','sect','uml',
+                                                       'copy','ordf','laquo','not','shy','reg','macr','deg','plusmn',
+                                                       'sup2','sup3','acute','micro','para','middot','cedil','sup1',
+                                                       'ordm','raquo','frac14','frac12','frac34');
+
+  newString = this;
+  for (var i = 0; i < chars.length; i++)
+  {
+       myRegExp = new RegExp();
+       myRegExp.compile(chars[i],'g')
+       newString = newString.replace (myRegExp, '&' + entities[i] + ';');
+  }
+  return newString;
+};
diff --git a/js2/mwEmbed/libSequencer/mvSequencer.js b/js2/mwEmbed/libSequencer/mvSequencer.js
new file mode 100644 (file)
index 0000000..c45d6c1
--- /dev/null
@@ -0,0 +1,1575 @@
+/*
+ * mvSequencer.js Created on Oct 17, 2007
+ *
+ * All Metavid Wiki code is Released under the GPL2
+ * for more info visit http://metavid.org/wiki/Code
+ * 
+ * @author Michael Dale
+ * @email mdale@wikimedia.org
+ * 
+ * further developed in open source development partnership with kaltura. 
+ * more info at http://kaltura.com & http://kaltura.org
+ * 
+ * mv_sequencer.js 
+ *      is a basic embeddeble sequencer. 
+ *  extends the playlist with drag/drop/sortable/add/remove functionality
+ *  editing of annotative content (mostly for wiki)
+ *  enables more dynamic layouts
+ *  exports back out to json or inline format
+ */
+
+loadGM({ 
+       "menu_clipedit" : "Edit Media",
+       "menu_transition" : "Transitions & Effects",    
+       "menu_cliplib" : "Add Media",   
+       "menu_resource_overview" : "Resource Overview",
+       "menu_options" : "Options",
+       
+       "loading_timeline" : "Loading TimeLine <blink>...</blink>",
+       "loading_user_rights" : "Loading user rights <blink>...</blink>",
+       
+       "no_edit_permissions" : "You don't have permissions to save changes to this sequence", 
+       
+       "edit_clip" : "Edit Clip",
+       "edit_save" : "Save Sequence Changes",
+       "saving_wait": "Save in Progress (please wait)",
+       "save_done"     :       "Save Done",
+       "edit_cancel" : "Cancel Sequence Edit",
+       "edit_cancel_confirm" : "Are you sure you want to cancel your edit. Changes will be lost",
+                       
+       "zoom_in" : "Zoom In",
+       "zoom_out" : "Zoom Out",
+       "cut_clip" : "Cut Clips",
+       "expand_track" : "Expand Track",
+       "colapse_track" : "Collapse Track",
+       "play_from_position" : "Play From Playline Position",
+       "pixle2sec" : "pixles to seconds",
+       "rmclip" : "Remove Clip",
+       "clip_in" : "clip in",
+       "clip_out" : "clip out",
+               
+       "mv_welcome_to_sequencer" : "<h3>Welcome to the sequencer demo</h3> very <b>limited</b> functionality right now. Not much documentation yet either",
+       
+       "no_selected_resource" : "<h3>No Resource selected</h3> Select a Clip to enable editing",
+       "error_edit_multiple" : "<h3>Multiple Resources Selected</h3> Select a single clip to edit it", 
+       
+       "mv_editor_options" : "Editor options",
+       "mv_editor_mode" : "Editor mode",
+       "mv_simple_editor_desc" : "simple editor (iMovie style)",
+       "mv_advanced_editor_desc" : "advanced editor (Final Cut style)",
+       "mv_other_options" : "Other Options",   
+       "mv_contextmenu_opt" : "Enable Context Menus",
+       
+       "mv_sequencer_credit_line":"Developed by <a href=\"http://kaltura.com\">Kaltura, Inc.</a>  in partnership with the <a href=\"http://wikimediafoundation.org/wiki/Home\">Wikimedia Foundation</a> ( <a href=\"#\">more info</a> )"
+});
+ //used to set default values and validate the passed init object
+var sequencerDefaultValues = {
+       
+       instance_name:'mvSeq', //for now only one instance by name mvSeq is allowed     
+       
+       target_sequence_container:null,//text value (so that its a valid property) 
+       target_form_text: null,
+       
+       //what is our save mode:
+       // can save to 'api' url or 'form'      
+       saveMode : 'api',
+       
+       video_container_id:'mv_video_container',
+       
+       video_width : 400,
+       video_height: 300,      
+       
+       sequence_tools_id:'mv_sequence_tools',
+       timeline_id:'mv_timeline',
+       plObj_id:'seq_pl',
+       plObj:'null',   
+       
+       timeline_scale:.06, //in pixel to second ratio ie 100pixles for every ~30seconds
+       timeline_duration:500, //default timeline length in seconds
+       playline_time:0,
+       track_thumb_height:60,
+       track_text_height:20,   
+               
+       //default timeline mode: "story" (i-movie like) or "time" (finalCut like) 
+       timeline_mode:'storyboard', 
+       
+       track_clipThumb_height:80, // how large are the i-movie type clips
+       
+       base_adj_duration:.5, //default time to subtract or add when adjusting clips.    
+       
+       //default clipboard is empty:
+       clipboard:new Array(),
+       //stores the clipboard edit token (if user has rights to edit their User page) 
+       clipboardEditToken:null,
+       //stores the sequence edit token (if user has rights to edit the current sequence)      
+       sequenceEditToken:null,
+       //the time the sequence was last touched (grabbed at time of startup)   
+       sequenceTouchedTime:null,               
+               
+       
+       
+       //Msg are all the language specific values ... 
+       // (@@todo overwrite by msg values preloaded in the page)       
+       //tack/clips can be pushed via json or inline playlist format
+       inline_playlist:'null', //text value so its a valid property 
+       inline_playlist_id:'null',
+       mv_pl_src:'null',
+       //the edit stack:
+       edit_stack:new Array(),
+       disp_menu_item:null,
+       //trackObj used to payload playlist Track Object (when inline not present) 
+       tracks:{}       
+}
+var mvSequencer = function(iObj) {             
+       return this.init(iObj);
+};
+//set up the mvSequencer object
+mvSequencer.prototype = {
+       //the menu_items Object contains: default html, js setup/loader functions
+       menu_items : {
+               'clipedit':{
+                       'd':0,                  
+                       'html':'',
+                       'js': function(this_seq){                               
+                               this_seq.doEditSelectedClip();
+                       },
+                       'click_js':function( this_seq ){
+                               this_seq.doEditSelectedClip();
+                       }
+               },
+               'transition':{
+                       'd':0,
+                       'html' : '<h3>' + gM('menu_transition') + '</h3>',
+                       'js':function(this_seq){                                
+                               this_seq.doEditTransitionSelectedClip();
+                       },
+                       'click_js':function(this_seq){                                                          
+                               //highlight the transition of the selected clip: 
+                               this_seq.doEditTransitionSelectedClip();
+                       }
+               },      
+               'cliplib':{
+                       'd':0,  
+                       'html': gM('loading_txt'),                      
+                       'js':function( this_seq ){                              
+                               //load the search interface with sequence tool targets           
+                               mvJsLoader.doLoad( [
+                                       'remoteSearchDriver',
+                                       'seqRemoteSearchDriver'
+                               ], function(){                                  
+                                        this_seq.mySearch = new seqRemoteSearchDriver(this_seq);
+                                        this_seq.mySearch.doInitDisplay();                                      
+                               });
+                       }
+               },      
+               'options':{
+                       'd':0,  
+                       'html' : '<h3>' + gM('menu_options') + '</h3>' +
+                               gM('mv_editor_mode') + '<br> ' +
+                               '<blockquote><input type="radio" value="simple_editor" name="opt_editor">' + 
+                                               gM('mv_simple_editor_desc') + ' </blockquote>' +
+                               '<blockquote><input type="radio" value="advanced_editor" name="opt_editor">' +
+                                               gM('mv_advanced_editor_desc') + ' </blockquote>'+
+                               gM('mv_other_options') + '<br>' + 
+                               '<blockquote><input type="checkbox" value="contextmenu_opt" name="contextmenu_opt">' + 
+                                               gM('mv_contextmenu_opt') + ' </blockquote>',            
+                       'js':function(this_seq){
+                               $j('#options_ic input[value=\'simple_editor\']').attr({
+                                       'checked':(this_seq.timeline_mode=='storyboard')?true:false                                     
+                               }).click(function(){
+                                       this_seq.doSimpleTl();
+                               });
+                               $j('#options_ic input[value=\'advanced_editor\']').attr({
+                                       'checked':( this_seq.timeline_mode=='time' )?true:false                                 
+                               }).click(function(){
+                                       this_seq.doAdvancedTl();
+                               });
+                               //set up the options for context menus
+                       }
+               }
+       },
+       
+       //set up initial key states: 
+       key_shift_down:false, 
+       key_ctrl_down:false,
+       inputFocus:false,
+       
+       init:function( iObj ){  
+               //set up pointer to this_seq for current scope:          
+               var this_seq = this;
+               //set the default values:
+               for(var i in sequencerDefaultValues){
+                       this[ i ] = sequencerDefaultValues[i];
+               }
+               for(var i in iObj){
+                       //js_log('on '+ i + ' :' + iObj[i]);
+                       if(typeof sequencerDefaultValues[i] != 'undefined'){ //make sure its a valid property
+                               this[i] = iObj[i];
+                       }
+               }
+
+               //check for sequence_container
+               if($j(this.target_sequence_container).length === 0){
+                       js_log("Error: missing target_sequence_container");
+                       return false;
+               }
+               
+               //$j(this.target_sequence_container).css('position', 'relative');
+               this['base_width']  = $j(this.target_sequence_container).width();
+               this['base_height'] = $j(this.target_sequence_container).height();                              
+               
+               //add the container divs (with basic layout ~universal~ 
+               $j(this.target_sequence_container).html(''+
+                       '<div id="' + this.video_container_id + '" style="position:absolute;right:0px;top:0px;' +
+                               'width:' + this.video_width + 'px;height:'+this.video_height+'px;border:solid thin blue;background:#FFF;font-color:black;"/>'+                  
+                       '<div id="' + this.timeline_id + '" class="ui-widget ui-widget-content ui-corner-all" style="position:absolute;' + 
+                               'left:0px;right:0px;top:'+(this.video_height+34)+'px;bottom:35px;overflow:auto;">'+
+                                       gM('loading_timeline')+ '</div>'+
+                       '<div class="seq_status" style="position:absolute;left:0px;width:300px;"></div>'+
+                       '<div class="seq_save_cancel" style="position:absolute;'+
+                               'left:5px;bottom:0px;height:25px;">'+                                   
+                                       gM('loading_user_rights') +
+                       '</div>'+
+                       '<div class="about_editor" style="position:absolute;right:5px;bottom:7px;">' +
+                               gM('mv_sequencer_credit_line') +
+                       '</div>'+
+                       '<div id="'+this.sequence_tools_id+'" style="position:absolute;' +
+                               'left:0px;right:'+(this.video_width+15)+'px;top:0px;height:'+(this.video_height+23)+'px;"/>'
+               ).css({
+                       'min-width':'850px'
+               });
+               
+               /*js_log('set: '+this.target_sequence_container + ' html to:'+ "\n"+
+                       $j(this.target_sequence_container).html()
+               );*/            
+               //first check if we got a cloned PL object:
+               //(when the editor is invoked with the plalylist already on the page) 
+               //@@NOT WORKING... (need a better "clone" function) 
+               /*if( this.plObj != 'null' ){
+                       js_log('found plObj clone');                    
+                       //extend with mvSeqPlayList object:                     
+                       this.plObj = new mvSeqPlayList(this.plObj);
+                       js_log('mvSeqPlayList added: ' + this.plObj.org_control_height );
+                       $j('#'+this.video_container_id).get(0).attachNode( this.plObj );
+                       this.plObj.getHTML();
+                       this.checkReadyPlObj();
+                       return ;
+               }*/
+                               
+               //else check for source based sequence editor (a clean page load of the editor) 
+               if( this.mv_pl_src != 'null' ) {
+                       js_log( ' pl src:: ' + this.mv_pl_src );                        
+                       var src_attr=' src="' + this.mv_pl_src+'" ';            
+               }else{
+                       js_log( ' null playlist src .. (start empty) '); 
+                       var src_attr='';
+               }                       
+               $j('#'+this.video_container_id).html('<playlist ' + src_attr +
+                       ' style="width:' + this.video_width + 'px;height:' + this.video_height + 'px;" '+
+                       ' controls="false" id="' + this.plObj_id + '" />');             
+               rewrite_by_id( this.plObj_id ); 
+               setTimeout(this.instance_name +'.checkReadyPlObj()', 25);               
+       },
+       updateSeqSaveButtons:function(){                
+               var _this = this;       
+               if( this.sequenceEditToken ){
+                       $j(this.target_sequence_container+' .seq_save_cancel').html( 
+                               $j.btnHtml( gM('edit_save'), 'seq_edit_save', 'close') + ' ' +
+                               $j.btnHtml( gM('edit_cancel'), 'seq_edit_cancel', 'close')                              
+                       );                      
+               }else{
+                       $j(this.target_sequence_container+' .seq_save_cancel').html( cancel_button + gM('no_edit_permissions') );
+               }
+               //assing bindings
+               $j(this.target_sequence_container +' .seq_edit_cancel').unbind().click(function(){
+                       var x = window.confirm( gM('edit_cancel_confirm') );
+                       if( x ){
+                               _this.closeModEditor();
+                       }else{
+                               //close request canceled. 
+                       }
+               });
+               $j(this.target_sequence_container +' .seq_edit_save').unbind().click(function(){
+                       //pop up progress dialog ~requesting edit line summary~
+                       //remove any other save dialog 
+                       $j('#seq_save_dialog').remove();
+                       $j('body').append('<div id="seq_save_dialog" title="'+ gM('edit_save') +'">' +
+                                               '<span class="mw-summary">'+
+                                                       '<label for="seq_save_summary">Edit summary: </label>' +
+                                               '</span>'+
+                                               '<input id="seq_save_summary" tabindex="1" maxlength="200" value="" size="30" name="seq_save_summary"/>'+                                                       
+                                       '</div>');
+                       //dialog: 
+                       $j('#seq_save_dialog').dialog({
+                               bgiframe: true,
+                               autoOpen: true,           
+                               modal: true,
+                               buttons:{
+                                       "Save":function(){
+                                               var saveReq = {
+                                                       'action'        : 'edit',
+                                                       'title'         : _this.plObj.mTitle,
+                                                       //the text is the sequence XML + the description
+                                                       'text'          : _this.getSeqOutputHLRDXML() + "\n" + 
+                                                                                 _this.plObj.wikiDesc,
+                                                       'token'         : _this.sequenceEditToken,
+                                                       'summary'       : $j('#seq_save_summary').val()
+                                               };              
+                                               //change to progress bar and save:      
+                                               $j('#seq_save_dialog').html('<div class="progress" /><br>' +
+                                                       gM('saving_wait')
+                                               )                                       
+                                               $j('#seq_save_dialog .progress').progressbar({
+                                                       value: 100
+                                               });
+                                               //run the Seq Save Request:                                                                     
+                                               do_api_req( {
+                                                       'data': saveReq,
+                                                       'url' : _this.getLocalApiUrl()
+                                               },function(data){                                                       
+                                                       $j('#seq_save_dialog').html( gM('save_done') );
+                                                       $j('#seq_save_dialog').dialog('option', 
+                                                               'buttons', { 
+                                                                       "Done":function(){                                                                              
+                                                                               //refresh the page?
+                                                                               window.location.reload();
+                                                                       },
+                                                                       "Do More Edits": function() { 
+                                                                               $j(this).dialog("close"); 
+                                                                       }
+                                                       });
+                                               });
+                                       },
+                                       "Cancel":function(){
+                                               $j(this).dialog('close');
+                                       }
+                               }
+                       });
+               })
+       },
+       //display a menu item (hide the rest) 
+       disp:function( item, dispCall ){
+               js_log('menu_item disp: ' + item);
+               this.disp_menu_item = item;             
+               //update the display and item state:            
+               if(this.menu_items[item]){              
+                       //update the tabs display: 
+                       if(!dispCall)
+                               $j("#seq_menu").tabs('select', this.menu_items[item].inx);
+                               
+                       this.menu_items[item].d = 1;
+                       //do any click_js actions:getInsertControl
+                       if( this.menu_items[item].click_js ) 
+                               this.menu_items[item].click_js( this );                                                                 
+               }               
+       },
+       //setup the menu items:  
+       setupMenuItems:function(){      
+               js_log('loadInitMenuItems');            
+               var this_seq = this;
+               //do all the menu_items setup:   @@we could defer this to once the menu item is requested
+               for( var i in this.menu_items ){        
+                       if(     this.menu_items[i].js ) 
+                               this.menu_items[i].js( this );
+               }                                                                               
+       },
+       renderTimeLine:function(){
+               //empty out the top level html: 
+               $j('#'+this.timeline_id).html('');
+               //add html general for timeline         
+               if( this.timeline_mode == 'time'){
+                       $j('#'+this.timeline_id).html(''+
+                               '<div id="'+this.timeline_id+'_left_cnt" class="mv_tl_left_cnt">'+
+                                       '<div id="'+this.timeline_id+'_head_control" style="position:absolute;top:0px;left:0px;right:0px;height:30px;">' +
+                                               '<a title="'+gM('play_from_position')+'" href="javascript:'+this.instance_name+'.play_jt()">'+
+                                                       '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/control_play_blue.png">'+                                                                                                
+                                               '</a>'+
+                                               '<a title="'+gM('zoom_in')+'" href="javascript:'+this.instance_name+'.zoom_in()">'+
+                                                       '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/zoom_in.png">'+                                                                                                                  
+                                               '</a>'+
+                                               '<a title="'+gM('zoom_out')+'" href="javascript:'+this.instance_name+'.zoom_out()">'+
+                                                       '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/zoom_out.png">'+                                 
+                                               '</a>'+
+                                               '<a title="'+gM('cut_clip')+'" href="javascript:'+this.instance_name+'.cut_mode()">'+
+                                                       '<img style="width:16px;height:16px;border:0" src="' + mv_embed_path + 'images/cut.png">'+              
+                                                       '</a>'+                                 
+                                       '</div>' +                      
+                               '</div>' + 
+                               '<div id="'+this.timeline_id+'_tracks" class="mv_seq_tracks">' +
+                                       '<div id="'+this.timeline_id+'_head_jump" class="mv_head_jump" style="position:absolute;top:0px;left:0px;height:20px;"></div>'+
+                                       '<div id="'+this.timeline_id+'_playline" class="mv_playline"></div>'+
+                               '</div>'
+                       );                              
+                       //add playlist hook to update timeline
+                       this.plObj.update_tl_hook = this.instance_name+'.update_tl_hook';               
+                       var this_sq = this;
+                       var top_pos=25;         
+                       //add tracks:
+                       for(var i in this.plObj.tracks){
+                               var track = this.plObj.tracks[i];
+                               //js_log("on track: "+ i + ' t:'+ $j('#'+this.timeline_id+'_left_cnt').html() );
+                               //set up track based on disp type
+                               switch(track.disp_mode){
+                                       case 'timeline_thumb':
+                                               var track_height=60;
+                                               var exc_img = 'opened';
+                                               var exc_action='close';
+                                               var exc_msg = gM('colapse_track');
+                                       break;
+                                       case 'text':
+                                               var track_height=20;
+                                               var exc_img = 'closed';
+                                               var exc_action='open';
+                                               var exc_msg = gM('expand_track');
+                                       break;
+                               }
+                               //add track name:
+                               $j('#'+this.timeline_id+'_left_cnt').append(
+                                       '<div id="track_cnt_'+i+'" style="top:'+top_pos+'px;height:'+track_height+'px;" class="track_name">'+
+                                               '<a id="mv_exc_'+i+'" title="'+exc_msg+'" href="javascript:'+this_sq.instance_name+'.exc_track('+i+',\''+exc_action+'\')">'+
+                                                       '<img id="'+this_sq.timeline_id+'_close_expand" style="width:16px;height:16px;border:0" '+ 
+                                                               ' src="'+mv_embed_path + 'images/'+exc_img+'.png">'+
+                                               '</a>'+
+                                       track.title+'</div>'
+                               );
+                               //also render the clips in the trackset container: (thumb or text view)
+                               $j('#'+this.timeline_id+'_tracks').append(
+                                       '<div id="container_track_'+i+'" style="top:'+top_pos+'px;height:'+(track_height+2)+'px;left:0px;right:0px;" class="container_track" />'
+                               );              
+                               top_pos+=track_height+20;
+                       }               
+               }
+               if( this.timeline_mode=='storyboard'){
+                       var top_pos=this.plObj.org_control_height;
+                       //debugger;
+                       for(var i in this.plObj.tracks){
+                               var track_height=this.track_clipThumb_height;
+                               var timeline_id = this.timeline_id
+                               //add in play box and container tracks
+                               $j('#'+timeline_id).append(''+
+                                       '<div id="interface_container_track_' + i + '" ' +
+                                       '       style="position:absolute;top:25px;height:'+(track_height+30)+'px;left:10px;right:0px;"' +
+                                       '>'+
+                                               '<div id="container_track_'+i+'" style="position:relative;top:0px;' +
+                                                       'height:'+(track_height+30)+'px;left:0px;right:0px;" class="container_track">' +                                                                                        
+                                               '</div>'+
+                                               '<div id="' + timeline_id + '_playline" class="mv_story_playline">' +
+                                                       '<div class="mv_playline_top"/>'+
+                                               '</div>'+
+                                       '</div>'
+                               );
+                               top_pos+=track_height+20;
+                       }
+               }
+       },
+       //once playlist is ready continue 
+       checkReadyPlObj:function(){             
+               //set up pointers from sequencer to pl obj 
+               this.plObj = $j('#'+ this.plObj_id ).get(0);
+               //& from seq obj to sequencer
+               this.plObj.pSeq = this;
+               
+               if( this.plObj )
+                       if( ! this.plObj.loading )
+                               this.plReadyInit();
+                                               
+               //else keep checking for the playlist to be ready 
+               if( this.plObj.loading ){ 
+                       if(this.plReadyTimeout==200){
+                               js_error('error playlist never ready');
+                       }else{
+                               this.plReadyTimeout++;
+                               setTimeout(this.instance_name +'.checkReadyPlObj()', 25);
+                       }
+               }               
+       },
+       getLocalApiUrl:function(){
+               return this.plObj.interface_url; 
+       },
+       plReadyInit:function(){
+               var _this = this;               
+               js_log('plReadyInit');          
+               js_log( this.plObj );                           
+               //give the playlist a pointer to its parent seq: 
+               this.plObj['seqObj'] = this;
+                                                       
+               //update playlist (if its empty right now)
+               if(this.plObj.getClipCount()==0){
+                       $j('#'+this.plObj_id).html('empty playlist');
+               }       
+               
+               //propagate the edit tokens 
+               //if on an edit page just grab from the form:           
+               this.sequenceEditToken = $j('input[wpEditToken]').val();
+               
+               if(typeof this.sequenceEditToken == 'undefined' && this.getLocalApiUrl()!=null){                                        
+                       var reqObj = {
+                               'action':'query',
+                               'prop':'info',
+                               'intoken':'edit',
+                               'titles': _this.plObj.mTitle
+                       };                      
+                       do_api_req( {
+                               'data': reqObj,
+                               'url' : _this.getLocalApiUrl()
+                               },function(data){
+                                       var cat = data;                                                 
+                                       for(var i in data.query.pages){ 
+                                               if(data.query.pages[i]['edittoken'])
+                                                       _this.sequenceEditToken = data.query.pages[i]['edittoken'];                                                             
+                                       }
+                                       _this.updateSeqSaveButtons();
+                               }
+                       );
+                       reqObj['titles']=_this.plObj.mTalk;
+                       do_api_req( {
+                               'data': reqObj,
+                               'url' : _this.getLocalApiUrl()
+                               }, function( data ){
+                                       for(var j in data.query.pages){
+                                               if(data.query.pages[j]['edittoken'])
+                                                       _this.clipboardEditToken = data.query.pages[j]['edittoken'];
+                                       }
+                               }
+                       );
+                       //also grab permissions for sending clipboard commands to the server
+                       
+                       //(calling the sequencer inline) try and get edit token via api call:                   
+                       //(somewhat fragile way to get at the api... should move to config 
+                       /*var token_url = this.plObj.interface_url.replace(/index\.php/, 'api.php');
+                       token_url += '?action=query&format=xml&prop=info&intoken=edit&titles=';                 
+                       $j.ajax({
+                               type: "GET",
+                               url: token_url + this_seq.plObj.mTitle,                         
+                               success:function(data){                                                 
+                                       var pageElm = data.getElementsByTagName('page')[0];
+                                       if( $j(pageElm).attr('edittoken') ){
+                                               this_seq.sequenceEditToken = $j(pageElm).attr('edittoken');
+                                       }
+                                       
+                               }
+                       });*/                   
+                       //also grab permissions for sending clipboard commands to the server
+                       /*$j.ajax({
+                               type:"GET",
+                               url: token_url + this_seq.plObj.mTalk,
+                               success:function(data){
+                                       var pageElm = data.getElementsByTagName('page')[0];
+                                       if( $j(pageElm).attr('edittoken') ){
+                                               this_seq.clipboardEditToken = $j(pageElm).attr('edittoken');
+                                       }                                                               
+                               } 
+                       });*/                   
+               }
+               
+               
+               //render the menu tabs::                
+               var item_containers ='';
+               var inx = 0;
+               var selected_tab = 0;           
+               var tabc ='';
+               var o='<div id="seq_menu" style="width:100%;height:100%">';
+               o+='<ul>';                      
+               for(var tab_id in this.menu_items){
+                       menu_item = this.menu_items[tab_id];
+                       menu_item.inx = inx;
+                       if(menu_item.d){
+                               selected_tab=inx;
+                               _this.disp_menu_item =tab_id;
+                       }
+                                               
+                       o+='<li>' + 
+                               '<a id="mv_menu_item_'+tab_id+'" href="#' + tab_id + '_ic">'+gM('menu_' + tab_id ) + '</a>' +
+                       '</li>';                                                
+                       
+                       tabc += '<div id="' + tab_id + '_ic" style="overflow:auto;height:272px;" >';                                                                                                    
+                               tabc += (menu_item.html) ? menu_item.html : '<h3>' + gM('menu_'+tab_id) + '</h3>';
+                       tabc +='</div>';                                
+                       inx++;
+               };
+               o+='</ul>';
+               o+=tabc;                                
+               $j('#'+this.sequence_tools_id).html( o );
+                               
+                 
+               $j("#seq_menu").tabs({
+                       selected:selected_tab,
+                       select: function(event, ui) {                                                                   
+                               _this.disp( $j(ui.tab).attr('id').replace('mv_menu_item_', ''), true );
+                       }               
+               //add sorting
+               }).find(".ui-tabs-nav").sortable({ axis : 'x' });
+                                       
+               
+               //render the timeline                                   
+               this.renderTimeLine();                  
+               this.do_refresh_timeline();
+               
+               //load init content into containers 
+               this.setupMenuItems();          
+               
+               this.doFocusBindings();         
+               
+               //set up key bidnings
+               $j(window).keydown(function(e){
+                       js_log('pushed down on:' + e.which);                    
+                       if( e.which == 16 )
+                               _this.key_shift_down = true;
+                                               
+                       if( e.which == 17)
+                               _this.key_ctrl_down = true;
+                               
+                       if( (e.which == 67 && _this.key_ctrl_down) && !_this.inputFocus)
+                               _this.copySelectedClips();
+                               
+                       if( (e.which == 88 && _this.key_ctrl_down) && !_this.inputFocus)
+                               _this.cutSelectedClips();
+                       
+                       //paste cips on v + ctrl while not focused on a text area: 
+                       if( (e.which == 86 && _this.key_ctrl_down) && !_this.inputFocus)                                
+                               _this.pasteClipBoardClips();
+                               
+               });
+               $j(window).keyup(function(e){                   
+                       js_log('key up on ' + e.which);                 
+                       //user let go of "shift" turn off multi-select
+                       if( e.which == 16 )
+                               _this.key_shift_down = false;
+                               
+                       if( e.which == 17)
+                               _this.key_ctrl_down = false;                                                    
+                       
+                       //backspace or delete key while not focused on a text area: 
+                       if( (e.which == 8 || e.which == 46) && !_this.inputFocus)                                                               
+                               _this.removeSelectedClips();                                    
+               });
+       },
+       //check all nodes for focus 
+       //@@todo it would probably be faster to search a given subnode instead of all text
+       doFocusBindings:function(){
+               var _this = this;
+               //if an input or text area has focus disable delete key binding
+               $j("input,textarea").focus(function () {
+                       js_log("inputFocus:true");
+                       _this.inputFocus = true;        
+               });
+               $j("input,textarea").blur( function () {
+                       js_log("inputFocus:blur");
+                       _this.inputFocus = false;
+               })
+       },
+       update_tl_hook:function(jh_time_ms){                    
+               //put into seconds scale: 
+               var jh_time_sec_float = jh_time_ms/1000;
+               //render playline at given time
+               //js_log('tl scale: '+this.timeline_scale);
+               $j('#'+this.timeline_id+'_playline').css('left', Math.round(jh_time_sec_float/this.timeline_scale)+'px' );
+               //js_log('at time:'+ jh_time_sec + ' px:'+ Math.round(jh_time_sec_float/this.timeline_scale));
+       },
+       /*returns a xml or json representation of the current sequence */
+       getSeqOutputJSON:function(){
+               js_log('json output:');
+       },
+       getSeqOutputHLRDXML:function(){         
+               var o='<sequence_hlrd>' +"\n";
+               o+="\t<head>\n";                
+               //get transitions 
+               for(var i in this.plObj.transitions){
+                       if( this.plObj.transitions[i] ){
+                               var tObj = this.plObj.transitions[i].getAttributeObj();
+                               o+="\t\t<transition ";
+                               for(var j in tObj){
+                                       o+=' '+j+'="' + tObj[j] + '"\n\t\t';
+                               }
+                               o+='/>'+"\n"; //transitions don't have children
+                       }
+               }
+               o+="\t</head>\n";       
+                       
+               //get clips 
+               o+="\t<body>\n";
+               //output each track: 
+               for(var i in this.plObj.tracks){
+                       var curTrack = this.plObj.tracks[i];                    
+                       o+="\t<seq";
+                               var tAttr = curTrack.getAttributeObj();
+                               for(var j in  tAttr){
+                                       o+=' '+j+'="' + tAttr[j] + '"\n\t\t\t';
+                               }
+                       o+=">\n";                       
+                       for( var k in curTrack.clips ){
+                               var curClip = curTrack.clips[k];                                
+                               o+="\t\t<ref ";
+                                       var cAttr = curClip.getAttributeObj();
+                                       var lt = '';
+                                       for(var j in  cAttr){
+                                               var val =  (j=='transIn' || j=='transOut') ? cAttr[j].id : cAttr[j];                                                                                                    
+                                               o+=lt + j+'="' + val + '"';
+                                               lt ="\n\t\t";
+                                       }                                       
+                               o+=">\n" //close the clip                               
+                               for(var pName in curClip.params){
+                                       var pVal = curClip.params[pName];
+                                       o+="\t\t\t" + '<param name="'+ pName + '">' + pVal + '</param>' + "\n";
+                               } 
+                               o+="\t\t</ref>\n\n";
+                       }
+                       o+="\n</seq>\n";
+               }
+               o+="\t</body>\n";               
+               //close the tag
+               o+='</sequence_hlrd>';          
+               
+               return o;               
+       },              
+       editClip:function(track_inx, clip_inx){
+               var cObj = this.plObj.tracks[ track_inx ].clips[ clip_inx ];
+               this.doEditClip( cObj );
+       },
+       doEditTransitionSelectedClip:function(){
+               var _this = this;
+               js_log("f:doEditTransitionSelectedClip:" + $j('.mv_selected_clip').length);                             
+               if( $j('.mv_selected_clip').length == 1){                       
+                       _this.doEditTransition( _this.getClipFromSeqID( $j('.mv_selected_clip').parent().attr('id') ) );
+               }else if( $j('.mv_selected_clip').length === 0){
+                       //no clip selected warning: 
+                       $j('#transition_ic').html( gM('no_selected_resource') );
+               }else{
+                       //multiple clip selected warning: 
+                       $j('#transition_ic').html( gM('error_edit_multiple') );
+               }
+       },
+       doEditSelectedClip:function(){  
+               js_log("f:doEditSelectedClip:"); 
+               //and only one clip selected                    
+               if( $j('.mv_selected_clip').length == 1){                       
+                       this.doEditClip( this.getClipFromSeqID( $j('.mv_selected_clip').parent().attr('id') ) );
+               }else if( $j('.mv_selected_clip').length === 0){
+                       //no clip selected warning: 
+                       $j('#clipedit_ic').html( gM('no_selected_resource') );
+               }else{
+                       //multiple clip selected warning: 
+                       $j('#clipedit_ic').html( gM('error_edit_multiple') );
+               }               
+       },
+       doEditTransition:function( cObj ){
+               js_log("sequence:doEditTransition");
+               var _this = this;               
+               mv_get_loading_img( '#transitions_ic' );
+               mvJsLoader.doLoad([                     
+                       'mvTimedEffectsEdit',
+                       '$j.fn.ColorPicker'
+               ],function(){
+                       //no idea why this works / is needed. 
+                       var localSeqRef = _this;
+                       _this.myEffectEdit = new mvTimedEffectsEdit({
+                               'rObj'           : cObj,
+                               'control_ct' : 'transition_ic',
+                               'pSeq'   : localSeqRef
+                       });
+               })
+       },
+       //updates the clip details div if edit resource is set
+       doEditClip:function( cObj){
+               var _this = this;               
+
+               //set default edit action (maybe edit_action can be sent via by context click)
+               var edit_action = 'fileopts'; 
+               
+               mv_get_loading_img( '#clipedit_ic' );
+               //load the clipEdit library if not already loaded:
+               mvJsLoader.doLoad( [
+                       'mvClipEdit'
+               ], function(){
+                       _this.myClipEditor = {};
+                       //setup the cliploader
+                       _this.myClipEditor = new mvClipEdit({
+                               'rObj'                  : cObj,
+                               'control_ct'    : 'clipedit_ic',
+                               'clip_disp_ct'  : cObj.id,      
+                               'edit_action'   : edit_action,
+                               'p_seqObj'              : _this,
+                               'profile'               : 'sequence'
+                       }); 
+               });
+       },
+       //save new clip segment
+       saveClipEdit:function(){
+               //saves the clip updates
+       }, 
+       closeModEditor:function(){
+               //unset the sequencer
+               _global['mvSeq'] = null;                
+               $j(this.target_sequence_container + ',.ui-widget-overlay').remove();
+       },
+       pasteClipBoardClips:function(){
+               js_log('f:pasteClipBoardClips');
+               //@@todo query the server for updated clipboard         
+               //paste before the "current clip"       
+               this.addClips( this.clipboard, this.plObj.cur_clip.order );             
+       },
+       copySelectedClips:function(){
+               var this_seq = this;
+               //set all the selected clips
+               this.clipboard = new Array();
+               $j('.mv_selected_clip').each(function(){
+                       //add each clip to the clip board:                                              
+                       var cur_clip = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
+                       this_seq.clipboard.push( cur_clip.getAttributeObj() );                                                                   
+               });
+               //upload clipboard to the server (if possible) 
+               if( parseUri(  document.URL ).host != parseUri( this_seq.plObj.interface_url ).host ){
+                       js_log('error: presently we can\'t copy clips across domains'); 
+               }else{                                  
+                       //@@we need a api entry point to store a "clipboard"
+                       if( this_seq.clipboardEditToken && this_seq.plObj.interface_url ){                                                      
+                               var req_url = this_seq.plObj.interface_url.replace(/api.php/, 'index.php') + '?action=ajax&rs=mv_seqtool_clipboard&rsargs[]=copy';
+                               $j.ajax({
+                                       type: "POST",
+                                       url:req_url,
+                                       data: $j.param( { 
+                                               "clipboard_data": $j.toJSON( this_seq.clipboard ),
+                                               "clipboardEditToken": this_seq.clipboardEditToken 
+                                       }),
+                                       success:function(data){         
+                                               //callback( data );
+                                               js_log('did clipboard push ' + $j.toJSON( this_seq.clipboard ) );
+                                       }
+                               });
+                       }else{
+                               js_log('error: no clipboardEditToken to uplaod clipboard to server');   
+                       }
+               }       
+       },
+       cutSelectedClips:function(){
+               this.copySelectedClips();               
+               this.removeSelectedClips();
+       },      
+       removeSelectedClips:function(){
+               var remove_clip_ary=new Array();        
+               //remove selected clips from display
+               $j('.container_track .mv_selected_clip').each(function(){                                       
+                       //grab the track index from the id (assumes track_#_clip_#                                       
+                       remove_clip_ary.push ( $j(this).parent().attr('id').replace('track_','').replace('clip_','').split('_') );                                                                                                                                                              
+               });             
+               if(remove_clip_ary.length !=0 )
+                       this.removeClips(remove_clip_ary);
+                       
+               //doEdit selected clips (updated selected resource)     
+               //@@todo refresh menu of current                
+               this.doEditSelectedClip();              
+       },
+       addClip:function( clip, before_clip_pos, track_inx){
+               this.addClips([clip],  before_clip_pos, track_inx)
+       },
+       //add a single or set of clips
+       //to a given position and track_inx 
+       addClips:function( clipSet, before_clip_pos, track_inx){
+               this_seq = this;        
+               
+               if(!track_inx)
+                       track_inx = this.plObj.default_track.inx;
+                       
+               if(!before_clip_pos)    
+                       before_clip_pos= this.plObj.default_track.getClipCount();
+                       
+               js_log("seq: add clip: at: "+ before_clip_pos + ' in track: ' + track_inx);                     
+               var cur_pos = before_clip_pos;          
+                        
+               $j.each(clipSet, function(inx, clipInitDom){
+                       var mediaElement = document.createElement('ref');
+                       for(var i in clipInitDom){
+                               js_log("set: " + i + ' to ' + clipInitDom[i]);
+                               if(i!='id')
+                                       $j(mediaElement).attr(i, clipInitDom[i]);
+                       }                                               
+                       if( this_seq.plObj.tryAddMedia( mediaElement, cur_pos, track_inx ) )    
+                               cur_pos++;
+               });              
+               //debugger; 
+               this.do_refresh_timeline();
+       },
+       removeClips:function( remove_clip_ary ){                                        
+               var this_seq = this;
+               var jselect = coma ='';
+               js_log('clip count before removal : ' + this_seq.plObj.default_track.clips.length + ' should remove ' + remove_clip_ary.length );               
+               var afected_tracks = new Array();
+               //add order to track_clip before we start removing:             
+               $j.each( remove_clip_ary, function(inx, track_clip){            
+                       remove_clip_ary[inx]['order'] = this_seq.plObj.tracks[ track_clip[0] ].clips[ track_clip[1] ].order;
+               });             
+               $j.each( remove_clip_ary, function(inx, track_clip){
+                       var track_inx = track_clip[0];
+                       var clip_inx = track_clip[1];   
+                       var clip_rm_order = track_clip['order'];                                                                                                         
+                       js_log('remove t:' + track_inx + ' c:'+ clip_inx + ' id:' +' #track_'+track_inx+'_clip_'+clip_inx + ' order:' + clip_rm_order);
+                       //remove the clips from the base tracks
+                       for(var i in this_seq.plObj.tracks[ track_inx ].clips){
+                               cur_clip = this_seq.plObj.tracks[ track_inx ].clips[i]
+                               if(cur_clip.order == clip_rm_order){
+                                       this_seq.plObj.tracks[ track_clip[0] ].clips.splice( i, 1);
+                               }
+                       }
+                       //add track to affected track list: 
+                       afected_tracks[ track_inx ]=true;
+                       jselect += coma + '#track_' +track_inx + '_clip_' + clip_inx;
+                       coma=',';
+               });
+               //update/ reorder:
+               $j.each(afected_tracks, function(track_inx, affected){
+                       this_seq.plObj.tracks[track_inx].reOrderClips();                                
+               });
+               
+               js_log('clip count after removal : ' + this_seq.plObj.default_track.clips.length);
+               //animate the removal (@@todo should be able to call the resulting fadeOut only once without a flag) 
+               var done_with_refresh=false;
+               $j(jselect).fadeOut("slow", function(){                 
+                       if( !done_with_refresh )                                                
+                               this_seq.do_refresh_timeline();
+                       done_with_refresh=true;
+               }).empty(); //empty to remove any persistent bindings                                             
+       },
+       doEdit:function( editObj ){
+               //add the current editObj to the edit stack (should allow for "undo")
+               this.edit_stack.push( editObj );
+               //make the adjustments
+               this.makeAdjustment( editObj );         
+       },
+       /*
+       * takes adjust ment object with options: 
+       * track_inx, clip_inx, start, end delta
+       */
+       makeAdjustment:function(e){     
+               switch(e.type){
+                       case 'resize_start':                            
+                               this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust('start', e.delta);
+                       break;
+                       case 'resize_end':
+                                this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust('end', e.delta);
+                       break;
+               }
+               js_log('re render: '+e.track_inx);
+               //refresh the playlist after adjustment
+               this.do_refresh_timeline();
+       },
+       //@@todo set up key bindings for undo
+       undoEdit:function(){
+               var editObj = this.edit_stack.pop();
+               //invert the delta
+               
+       },
+       exc_track:function(inx,req){    
+               this_seq = this;                        
+               if(req=='close'){
+                       $j('#mv_exc_'+inx).attr('href', 'javascript:'+this.instance_name+'.exc_track('+inx+',\'open\')');
+                       $j('#mv_exc_'+inx + ' > img').attr('src',mv_embed_path + 'images/closed.png');
+                       $j('#track_cnt_'+inx+',#container_track_'+inx).animate({height:this.track_text_height}, "slow",'',
+                               function(){
+                                       this_seq.plObj.tracks[inx].disp_mode='text';
+                                       this_seq.render_tracks( inx );
+                               });
+               }else if(req=='open'){
+                       $j('#mv_exc_'+inx).attr('href', 'javascript:'+this.instance_name+'.exc_track('+inx+',\'close\')');
+                       $j('#mv_exc_'+inx + ' > img').attr('src',mv_embed_path + 'images/opened.png');
+                       $j('#track_cnt_'+inx+',#container_track_'+inx).animate({height:this.track_thumb_height}, "slow",'',
+                               function(){
+                                       this_seq.plObj.tracks[inx].disp_mode='timeline_thumb';
+                                       this_seq.render_tracks(inx);
+                               });
+                       
+               }
+       },
+       //adds tracks 
+       add_track:function(inx, track){
+       
+       },
+       //toggle cut mode (change icon to cut)
+       cut_mode:function(){
+               js_log('do cut mode');
+               //add cut layer ontop of clips
+       },
+       doAdvancedTl:function(){
+               this.timeline_mode='time';
+               this.renderTimeLine();
+               this.do_refresh_timeline();                             
+               return false;
+       },
+       doSimpleTl:function(){          
+               this.timeline_mode='storyboard';
+               this.renderTimeLine();
+               this.do_refresh_timeline();     
+               return false;
+       },
+       //renders updates the timeline based on the current scale
+       render_tracks:function( track_inx ){            
+               js_log("f::render track: "+track_inx);
+               var this_seq = this;
+               //inject the tracks into the timeline (if not already there)
+               for(var track_id in this.plObj.tracks){ 
+                       if( track_inx==track_id || typeof track_inx=='undefined' ){
+                               //empty out the track container: 
+                               //$j('#container_track_'+track_id).empty();
+                               var track_html=droppable_html='';               
+                               //set up per track vars:
+                               var track = this.plObj.tracks[track_id];
+                               var cur_clip_time=0;
+                       
+                               //set up some constants for timeline_mode == storyboard:         
+                               if(this.timeline_mode == 'storyboard'){                 
+                                       var frame_width = Math.round( this.track_clipThumb_height * 1.3333333 );
+                                       var container_width = frame_width+60;
+                               }
+                               
+                               //for each clip: 
+                               for(var j in track.clips){
+                                       clip = track.clips[j];                                  
+                                       //var img = clip.getClipImg('icon');
+                                       if( this.timeline_mode == 'storyboard' ){                                                                                               
+                                               clip.left_px = j*container_width;
+                                               clip.width_px = container_width;
+                                               var base_id = 'track_'+track_id+'_clip_'+j;
+                                               track_html += '<span id="'+base_id+'" '+
+                                                                               'class="mv_storyboard_container mv_clip_drag" '+  
+                                                                               'style="'+                                                                              
+                                                                               'left:'+clip.left_px+'px;'+                                                                     
+                                                                               'height:' + (this.track_clipThumb_height+30) + 'px;' +                                                                                                                                                          
+                                                                               'width:'+(container_width)+'px;" >';                                                                                                                            
+                                               track_html += clip.embed.renderTimelineThumbnail({
+                                                                               'width' : frame_width,
+                                                                               'thumb_class' : 'mv_clip_thumb',
+                                                                               'height':this.track_clipThumb_height,
+                                                                               'time':0
+                                                                       });                     
+                                               //render out edit button
+                                               /*track_html+='<div class="clip_edit_button clip_edit_base clip_control"/>';*/
+                                               
+                                               //check if the clip has transitions                                             
+                                               var imgHtml = '';                                       
+                                               var imsrc = '';
+                                               var cat = clip;                                                 
+                                               if(clip.transIn || clip.transOut){
+                                                       if( clip.transIn && clip.transIn.getIconSrc )
+                                                               imsrc = clip.transIn.getIconSrc();
+                                                       //@@todo put transOut somewhere else
+                                                       if( clip.transOut && clip.transOut.getIconSrc )
+                                                               imsrc = clip.transOut.getIconSrc();                             
+                                                       if(imsrc != '')
+                                                               imgHtml = '<img style="width:32px;height:32px" src="' + imsrc + '" />';                                                 
+                                               }                                                       
+                                               //render out transition edit box 
+                                               track_html +=   '<div id="tb_' + base_id + '"  class="clip_trans_box">' + 
+                                                                                       imgHtml +
+                                                                               '</div>'
+                                               
+                                               //render out adjustment text
+                                               /*track_html+='<div id="' + base_id + '_adj' + '" class="mv_adj_text" style="top:'+ (this.track_clipThumb_height+10 )+'px;">'+
+                                                                               '<span class="mv_adjust_click" onClick="'+this.instance_name+'.adjClipDur(' + track_id + ',' + j + ',\'-\')" /> - </span>'+
+                                                                                 ( (clip.getDuration() > 60 )? seconds2npt(clip.getDuration()): clip.getDuration() )  +
+                                                                               '<span class="mv_adjust_click" onClick="'+this.instance_name+'.adjClipDur(' + track_id + ',' + j + ',\'+\')" /> + </span>'+ 
+                                                                       '</div>';                                                                                                                                                                               
+                                               */                                              
+                                               track_html+='</span>';
+                                                                                                       
+                                       }                                                                                                               
+                                       //do timeline_mode rendering:
+                                       if(this.timeline_mode == 'time'){               
+                                               clip.left_px = Math.round( cur_clip_time/this.timeline_scale);                                                                                                                  
+                                               clip.width_px = Math.round( Math.round( clip.getDuration() )/this.timeline_scale);
+                                               clip.height_px = 60;
+                                               js_log('at time:' + cur_clip_time + ' left: ' +clip.left_px + ' clip dur: ' +  Math.round( clip.getDuration() ) + ' clip width:' + clip.width_px);
+                                                                                                                               
+                                               //for every clip_width pixle output image 
+                                               if(track.disp_mode=='timeline_thumb'){
+                                                       track_html+='<span id="track_'+track_id+'_clip_'+j+'" '+
+                                                                                       'class="mv_tl_clip mv_clip_drag" '+ 
+                                                                                       'style="'+
+                                                                                               'left:' + clip.left_px + 'px;'+
+                                                                                               'width:'+ clip.width_px + 'px;'+
+                                                                                               'height:'+ clip.height_px + 'px" >';    
+                                                       track_html+= this.render_clip_frames( clip );                                                                                                                                                           
+                                               }else if(track.disp_mode=='text'){
+                                                       //'+left_px+
+                                                       track_html+='<span id="track_'+track_id+'_clip_'+j+'" style="left:'+clip.left_px+'px;'+
+                                                               'width:'+clip.width_px+'px;background:'+clip.getColor()+
+                                                                       '" class="mv_time_clip_text mv_clip_drag">'+clip.title; 
+                                               }                                                                                                                                                                                                                                                                                                                                               
+                                               //add in per clip controls
+                                               track_html+='<div title="'+gM('clip_in')+' '+clip.embed.start_ntp+'" class="ui-resizable-w ui-resizable-handle" style="width: 16px; height: 16px; left: 0px; top: 2px;background:url(\''+mv_embed_path+'images/application_side_contract.png\');" ></div>'+"\n";
+                                               track_html+='<div title="'+gM('clip_out')+' '+clip.embed.end_ntp+'" class="ui-resizable-e ui-resizable-handle" style="width: 16px; height: 16px; right: 0px; top: 2px;background:url(\''+mv_embed_path+'images/application_side_expand.png\');" ></div>'+"\n";
+                                               track_html+='<div title="'+gM('rmclip')+'" onClick="'+this.instance_name + '.removeClips(new Array([' + track_id + ',' + j + ']))" style="position:absolute;cursor:pointer;width: 16px; height: 16px; left: 0px; bottom:2px;background:url(\''+mv_embed_path+'images/delete.png\');"></div>'+"\n";
+                                               track_html+='<span style="display:none;" class="mv_clip_stats"></span>';        
+                                                                                                                                                                                                                                       
+                                               track_html+='</span>';  
+                                               //droppable_html+='<div id="dropBefore_'+i+'_c_'+j+'" class="mv_droppable" style="height:'+this.track_thumb_height+'px;left:'+clip.left_px+'px;width:'+Math.round(clip.width_px/2)+'px"></div>';
+                                               //droppable_html+='<div id="dropAfter_'+i+'_c_'+j+'" class="mv_droppable" style="height:'+this.track_thumb_height+'px;left:'+(clip.left_px+Math.round(clip.width_px/2))+'px;width:'+(clip.width_px/2)+'px"></div>';
+                                               cur_clip_time+=Math.round( clip.getDuration() ); //increment cur_clip_time      
+                                       }                               
+                                       
+                               }       
+                               
+                               //js_log("new htmL for track i: "+track_id + ' html:'+track_html);
+                               $j('#container_track_'+track_id).html( track_html );                                                            
+                               
+                               //apply transition click action
+                               $j('.clip_trans_box').click(function(){
+                                       if($j(this).hasClass('mv_selected_transition')){
+                                               $j(this).removeClass('mv_selected_transition');
+                                               this_seq.deselectClip( $j(this).siblings('.mv_clip_thumb').get(0) );
+                                       }else{
+                                               //deselect others 
+                                               $j('.clip_trans_box').removeClass('mv_selected_transition');
+                                               $j(this).addClass("mv_selected_transition");
+                                               $j(this).siblings('.mv_clip_thumb').addClass("mv_selected_clip");       
+                                               var sClipObj = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
+                                               //jump to the current clip
+                                               this_seq.plObj.updateCurrentClip( sClipObj  );          
+                                               //display the transition edit tab:                                              
+                                               this_seq.disp( 'transition' );                                                          
+                                       }
+                               });
+                               
+                               //apply edit button mouse over effect:
+                               $j('.clip_edit_button').hover(function(){
+                                       $j(this).removeClass("clip_edit_base").addClass("clip_edit_over");
+                               },function(){
+                                       $j(this).removeClass("clip_edit_over").addClass("clip_edit_base");
+                               }).click(function(){                            
+                                       //deselect everything else: 
+                                       $j('.mv_selected_clip').each(function(inx, selected_clip){
+                                               this_seq.deselectClip( this );
+                                       });
+                                       
+                                       var sClipObj = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );
+                                       this_seq.plObj.updateCurrentClip( sClipObj  );
+                                       //get the clip (siblings with mv_clip_thumb class) 
+                                       var cur_clip_elm =  $j(this).siblings('.mv_clip_thumb');
+                                       //select the clip (add mv_selected_clip if not already selected) 
+                                       if( ! $j( cur_clip_elm ).hasClass("mv_selected_clip") ){                                                                                                                                                                        
+                                               $j( cur_clip_elm ).addClass('mv_selected_clip');                                                
+                                               $j('#' + $j( cur_clip_elm ).parent().attr("id") + '_adj').fadeIn("fast");                                                                                               
+                                       }
+                                       //display the edit tab:
+                                       this_seq.disp( 'clipedit' );
+                                       //display edit dialog: 
+                                       this_seq.doEditClip( sClipObj );                                
+                               });                                                             
+                               
+                               //apply onClick edit controls: 
+                               $j('.mv_clip_thumb').click(function(){                                                          
+                                       var cur_clip_click = this;
+                                       //if not in multi select mode remove all existing selections 
+                                       //(except for the current click which is handled down below)
+                                       js_log(' ks: ' + this_seq.key_shift_down + '  ctrl_down:' +this_seq.key_ctrl_down);
+                                       if( ! this_seq.key_shift_down && ! this_seq.key_ctrl_down){                                                                                     
+                                               $j('.mv_selected_clip').each(function(inx, selected_clip){                                                      
+                                                       if( $j(this).parent().attr('id') != $j(cur_clip_click).parent().attr('id') 
+                                                               || ( $j('.mv_selected_clip').length > 1 ) ){
+                                                                       this_seq.deselectClip( this );                                                                  
+                                                       }
+                                               });     
+                                       }                                               
+                                                                                                                               
+                                       //jump to clip time 
+                                       var sClipObj = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );                                                                                                
+                                       this_seq.plObj.updateCurrentClip( sClipObj  );                                  
+                                       if( $j(this).hasClass("mv_selected_clip") ){
+                                               $j(this).removeClass("mv_selected_clip");
+                                               $j('#' + $j(this).parent().attr("id") + '_adj').fadeOut("fast");
+                                       }else{                                                                                                                  
+                                               $j(this).addClass('mv_selected_clip');                                          
+                                               $j('#' + $j(this).parent().attr("id") + '_adj').fadeIn("fast");                                                                                         
+                                       }       
+                                       //if shift select is down select the in-between clips 
+                                       if( this_seq.key_shift_down ){
+                                               //get the min max of current selection (within the current track)
+                                               var max_order = 0;
+                                               var min_order = 999999999;
+                                               $j('.mv_selected_clip').each(function(){
+                                                       var cur_clip = this_seq.getClipFromSeqID( $j(this).parent().attr('id') );                                                       
+                                                       //get min max
+                                                       if(cur_clip.order < min_order)
+                                                               min_order = cur_clip.order;
+                                                       if(cur_clip.order > max_order)
+                                                               max_order = cur_clip.order;
+                                               });
+                                               //select all non-selected between max or min
+                                               js_log('sOrder: ' + sClipObj.order + ' min:' + min_order + ' max:'+ max_order);                 
+                                               if( sClipObj.order <= min_order ){                                                      
+                                                       for( var i = sClipObj.order; i <= max_order; i++ ){                                                                                     
+                                                               $j('#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass('mv_selected_clip');    
+                                                       }                                                                                                        
+                                               }
+                                               if( sClipObj.order >= max_order ){
+                                                       for( var i =min_order; i <= max_order; i++ ){                                                                                   
+                                                               $j('#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass('mv_selected_clip');    
+                                                       }                                       
+                                               }
+                                       }                                                                       
+                                       this_seq.doEditSelectedClip();                                                                  
+                               });                                                                                             
+                               //add in control for time based display                                                                                  
+                               //debugger;                     
+                               if(this.timeline_mode == 'time'){                       
+                                       $j('.ui-resizable-handle').mousedown( function(){
+                                               js_log('hid: ' +  $j(this).attr('class'));
+                                               this_seq.resize_mode = ($j(this).attr('class').indexOf('ui-resizable-e')!=-1)?
+                                                                               'resize_end':'resize_start';
+                                       });
+                               }                       
+                               var insert_key='na';
+                               // drag hooks:
+                               //@@todo support multiple clips                                 
+                               for(var j in track.clips){                      
+                                       $j('#track_'+track_id+'_clip_'+j).draggable({            
+                                               axis:'x', 
+                                               containment:'#container_track_'+track_id,
+                                               opacity:50,
+                                               handle: ":not(.clip_control)",
+                                               scroll:true,
+                                               drag:function(e, ui){
+                                                       //debugger;
+                                                       insert_key = this_seq.clipDragUpdate(ui, this);                                                 
+                                               },
+                                               start:function(e,ui){
+                                                       js_log('start drag:' + this.id);
+                                                       //make sure we are ontop
+                                                       $j(this).css({top:'0px',zindex:10});            
+                                               },
+                                               stop:function(e, ui){
+                                                       $j(this).css({top:'0px',zindex:0});
+                                                       
+                                                       var id_parts = this.id.split('_');                                              
+                                                       var track_inx = id_parts[1];
+                                                       var clip_inx = id_parts[3];
+                                                       var clips = this_seq.plObj.tracks[track_inx].clips;     
+                                                       var cur_drag_clip = clips[clip_inx];    
+                                                                                                               
+                                                       if(insert_key!='na' && insert_key!='end' ){                                             
+                                                               cur_drag_clip.order=insert_key-.5;                                                      
+                                                       }else if (insert_key=='end'){
+                                                               cur_drag_clip.order=clips.length;
+                                                       }                                                       
+                                                       //reorder array based on new order
+                                                       clips.sort(sort_func);
+                                                       function sort_func(a, b){                                                               
+                                                               return a.order - b.order;
+                                                       }                                                       
+                                                       //assign keys back to order:
+                                                       this_seq.plObj.tracks[track_inx].reOrderClips();                                                                                                                                                                                                                        
+                                                       //redraw:                                                                                                                                                                         
+                                                       this_seq.do_refresh_timeline();
+                                               }
+                                       });
+                                       //add in resize hook if in time mode: 
+                                       if(this.timeline_mode == 'time'){       
+                                               $j('#track_'+track_id+'_clip_'+j).resizable({           
+                                                       minWidth:10,
+                                                       maxWidth:6000,
+                                                       start: function(e,ui) {                                                                 
+                                                               //set border to red
+                                                               $j(this).css({'border':'solid thin red'});
+                                                               //fade In Time stats (end or start based on handle)                                                      
+                                                               //dragging east (adjusting end time)     
+                                                               js_log( 'append to: '+ this.id);                                                                                                
+                                                               $j('#' + this.id + ' > .mv_clip_stats').fadeIn("fast");
+                                                       },
+                                                       stop: function(e,ui) {
+                                                               js_log('stop resize');
+                                                               //restore border
+                                                               $j(this).css('border', 'solid thin white');
+                                                               //remove stats
+                                                               var clip_drag = this;
+                                                               $j('#'+this.id+' > .mv_clip_stats').fadeOut("fast",function(){
+                                                                       var id_parts = clip_drag.id.split('_');         
+                                                                       var track_inx = id_parts[1];
+                                                                       var clip_inx = id_parts[3];
+                                                                       //update clip 
+                                                                       this_seq.doEdit({
+                                                                               type:this_seq.resize_mode,
+                                                                               delta:this_seq.edit_delta,
+                                                                               track_inx:track_inx,
+                                                                               clip_inx:clip_inx})
+                                                                       });                                                     
+                                                       },
+                                                       resize: function(e,ui) {                                                                                                
+                                                               //update time stats & render images: 
+                                                               this_seq.update_clip_resize(this);
+                                                       }
+                                               });
+                                       }
+                               }                       
+                               $j('#container_track_'+track_id).width(Math.round(      this.timeline_duration / this.timeline_scale));
+                       }
+                       //debugger;
+               }
+       },
+       clipDragUpdate:function( ui, clipElm){
+               var this_seq = this; 
+               
+               var insert_key='na';
+               //animate re-arrange by left position: 
+               //js_log('left: '+ui.position.left);
+               //locate clip (based on clip duration not animate)       
+               var id_parts = clipElm.id.split('_');                                           
+               var track_inx = id_parts[1];
+               var clip_inx = id_parts[3];
+               var clips = this_seq.plObj.tracks[track_inx].clips;
+               var cur_drag_clip = clips[clip_inx];            
+               var return_org = true;
+               $j(clipElm).css('zindex',10);
+               //find out where we are inserting and set left border to solid red thick
+               for(var k in clips){
+                       if(     ui.position.left > clips[k].left_px &&
+                               ui.position.left < (clips[k].left_px + clips[k].width_px)){
+                               if(clip_inx!=k){
+                                       //also make sure we are not where we started
+                                       if(k-1!=clip_inx){
+                                               $j('#track_'+track_inx+'_clip_'+k).css('border-left', 'solid thick red');                                                                       
+                                               insert_key=k;
+                                       }else{
+                                               insert_key='na';
+                                       }
+                               }else{
+                                       insert_key='na';
+                               }
+                       }else{
+                               $j('#track_'+track_inx+'_clip_'+k).css('border-left', 'solid thin white');
+                       }
+               }       
+               //if greater than the last k insert after       
+               if(ui.position.left > (clips[k].left_px + clips[k].width_px) &&
+                       k!=clip_inx ){
+                               $j('#track_'+track_inx+'_clip_'+k).css('border-right', 'solid thick red');
+                               insert_key='end';
+               }else{
+                       $j('#track_'+track_inx+'_clip_'+k).css('border-right', 'solid thin white');
+               }
+               return insert_key;
+       },
+       deselectClip:function( clipElm ){
+               $j(clipElm).removeClass("mv_selected_clip");
+               //make sure the transition sibling is removed:
+               $j(clipElm).siblings('.clip_trans_box').removeClass( 'mv_selected_transition' );
+               $j('#' + $j(clipElm).parent().attr("id") + '_adj').fadeOut("fast");
+       },
+       getClipFromSeqID:function( clip_seq_id ){
+               js_log('get id from: ' + clip_seq_id);
+               var ct = clip_seq_id.replace('track_','').replace('clip_','').split('_');               
+               return this.plObj.tracks[ ct[0] ].clips[ ct[1] ];
+       },
+       //renders clip frames
+       render_clip_frames:function(clip, frame_offset_count){
+               js_log('f:render_clip_frames: ' + clip.id + ' foc:' + frame_offset_count); 
+               var clip_frames_html='';                                        
+               var frame_width = Math.round(this.track_thumb_height*1.3333333);
+
+               var pint = (frame_offset_count==null)?0:frame_offset_count*frame_width;         
+               
+               //js_log("pinit: "+ pint+ ' < '+clip.width_px+' ++'+frame_width);
+               for(var p=pint;p<clip.width_px;p+=frame_width){                                                         
+                       var clip_time = (p==0)?0:Math.round(p*this.timeline_scale);
+                       js_log('rendering clip frames: p:' +p+' pts:'+ (p*this.timeline_scale)+' time:' + clip_time + ' height:'+this.track_thumb_height);
+                       clip_frames_html+=clip.embed.renderTimelineThumbnail({
+                               'width':  frame_width,
+                               'thumb_class':'mv_tl_thumb',
+                               'height': this.track_thumb_height,
+                               'size' : "icon", //set size to "icon" preset
+                               'time':   clip_time
+                       });
+               }       
+               js_log('render_clip_frames:'+clip_frames_html);
+               return clip_frames_html;
+       },
+       update_clip_resize:function(clip_element){
+               //js_log('update_clip_resize');
+               var this_seq = this;
+               var id_parts = clip_element.id.split('_');              
+               track_inx = id_parts[1];
+               clip_inx = id_parts[3];
+               //set clip:
+               var clip = this.plObj.tracks[ track_inx ].clips[ clip_inx ];            
+               var clip_desc ='';
+               //would be nice if getting the width did not flicker the border
+               //@@todo do a work around e in resize function has some screen based offset values
+               clip.width_px = $j(clip_element).width();
+               var width_dif = clip.width_px - Math.round( Math.round( clip.getDuration() )/this.timeline_scale);              
+               //var left_px = $j(clip_element).css('left');
+               
+               var new_clip_dur = Math.round( clip.width_px*this.timeline_scale );
+               var clip_dif = (new_clip_dur - clip.getDuration() );
+               var clip_dif_str = (clip_dif >0)?'+'+clip_dif:clip_dif;
+               //set the edit global delta
+               this.edit_delta = clip_dif;
+               
+               //get new length: 
+               clip_desc+='length: ' + seconds2npt(new_clip_dur) +'('+clip_dif_str+')';        
+               if(this_seq.resize_mode=='resize_end'){ 
+                       //expanding right               
+                       var new_end = seconds2npt(npt2seconds(clip.embed.end_ntp)+clip_dif);
+                       clip_desc+='<br>end time: ' + new_end;          
+                       //also shift all the other clips (after the current) 
+                       //js_log("track_inx: " + track_inx + ' clip inx:'+clip_inx);
+                       //$j('#container_track_'+track_inx+' > .mv_clip_drag :gt('+clip_inx+')').each(function(){
+                       $j('#container_track_'+track_inx+' > :gt('+clip_inx+')').each(function(){
+                               var move_id_parts = this.id.split('_'); 
+                               var move_clip = this_seq.plObj.tracks[move_id_parts[1]].clips[move_id_parts[3]];                
+                               //js_log('should move:'+ this.id);
+                               $j(this).css('left', move_clip.left_px + width_dif);
+                       });
+               }else{
+                       //expanding left (resize_start)
+                       var new_start = seconds2npt(npt2seconds(clip.embed.start_ntp)+clip_dif);
+                       clip_desc+='<br>start time: ' + new_start;                                      
+               }
+                       
+               //update clip stats:
+               $j('#'+clip_element.id+' > .mv_clip_stats').html(clip_desc);
+               var frame_width = Math.round(this.track_thumb_height*1.3333333);
+               //check if we need to append some images:
+               var frame_count = $j('#'+clip_element.id+' > img').length;
+               if(clip.width_px > (frame_count *  frame_width) ){
+                       //if dragging left append 
+                       js_log('width_px:'+clip.width_px+' framecount:'+frame_count+' Xcw='+(frame_count *  frame_width));
+                       $j('#'+clip_element.id).append(this.render_clip_frames(clip, frame_count));                                             
+               }               
+       },
+       //renders cnt_time
+       render_playheadhead_seeker:function(){           
+               //render out time stamps and time "jump" links 
+               //first get total width
+               
+               //remove the old one if its still there         
+               $j('#'+this.timeline_id +'_pl_control').remove();
+               js_log('output controls to: ' + this.target_sequence_container);
+               //render out a playlist clip wide and all the way to the right (only playhead and play button) (outside of timeline)
+               $j(this.target_sequence_container).append('<div id="'+ this.timeline_id +'_pl_control"'+
+                       ' style="position:absolute;top:' + (this.plObj.height) +'px;'+
+                       'right:1px;width:'+this.plObj.width+'px;height:'+this.plObj.org_control_height+'" '+
+                       'class="videoPlayer"><div class="ui-widget ui-corner-bottom ui-state-default controls">'+
+                                        this.plObj.getControlsHTML() +
+                                '</div>'+
+                       '</div>');              
+               //update time and render out clip dividers .. should be used to show load progress
+               this.plObj.updateBaseStatus();
+               
+               //once the controls are in the DOM add hooks: 
+               ctrlBuilder.addControlHooks(this.plObj);
+               
+               //render out the "jump" div     
+               if(this.timeline_mode=='time'){                                         
+                       /*$j('#'+this.timeline_id+'_head_jump').width(pixle_length);
+                       //output times every 50pixles 
+                       var out='';
+                       //output time-desc every 50pixles and jump links every 10 pixles
+                       var n=0;
+                       for(i=0;i<pixle_length;i+=10){
+                               out+='<div onclick="'+this.instance_name+'.jt('+i*this.timeline_scale+');"' +
+                                               ' style="z-index:2;position:absolute;left:'+i+'px;width:10px;height:20px;top:0px;"></div>';                     
+                               if(n==0)                                
+                                       out+='<span style="position:absolute;left:'+i+'px;">|'+seconds2npt(Math.round(i*this.timeline_scale))+'</span>';                                                
+                               n++;
+                               if(n==10)n=0;
+                       }*/     
+                       
+               }               
+       },
+       jt:function( jh_time ){
+               js_log('jt:' + jh_time);
+               var this_seq = this;
+               this.playline_time = jh_time;
+               js_log('time: ' + seconds2npt(jh_time) + ' ' + Math.round(jh_time/this.timeline_scale));
+               //render playline at given time
+               $j('#'+this.timeline_id+'_playline').css('left', Math.round(jh_time/this.timeline_scale)+'px' );                 
+               cur_pl_time=0;
+               //update the thumb with the requested time:              
+               this.plObj.updateThumbTime( jh_time );          
+       },
+       //adjusts the current scale
+       zoom_in:function(){
+               this.timeline_scale = this.timeline_scale*.75;
+               this.do_refresh_timeline();
+               js_log('zoomed in:'+this.timeline_scale);
+       },      
+       zoom_out:function(){            
+               this.timeline_scale = this.timeline_scale*(1+(1/3));
+               this.do_refresh_timeline();
+               js_log('zoom out: '+this.timeline_scale);
+       },
+       do_refresh_timeline:function( preserve_selection ){
+               //@@todo should "lock" interface while refreshing timeline
+               var pSelClips = [];
+               if(preserve_selection){
+                       $j('.mv_selected_clip').each(function(){                                
+                               pSelClips.push( $j(this).parent().attr('id') );
+                       });
+               }
+               //regen duration 
+               this.plObj.getDuration( true );
+               //refresh player:                
+               this.plObj.getHTML();
+               
+               this.render_playheadhead_seeker();
+               this.render_tracks();
+               this.jt(this.playline_time);
+                               
+               if(preserve_selection){
+                       for(var i=0;i < pSelClips.length; i++){
+                               $j('#' + pSelClips[i] + ' .mv_clip_thumb').addClass('mv_selected_clip');                                
+                       }
+               }
+       }
+               
+}
+/* extension to mvPlayList to support sequencer features properties */
+var mvSeqPlayList = function( element ){
+       return this.init( element );
+}
+mvSeqPlayList.prototype = {
+       init:function(element){
+               var myPlObj = new mvPlayList(element);
+               //inherit mvClip                
+               for(var method in myPlObj){                     
+                       if(typeof this[method] != 'undefined' ){                                
+                               this['parent_'+method]=myPlObj[method];                         
+                       }else{          
+                               this[method] = myPlObj[method];
+                       }               
+               }               
+               this.org_control_height = this.pl_layout.control_height;                
+               //do specific mods:(controls and title are managed by the sequencer)  
+               this.pl_layout.title_bar_height=0;
+               this.pl_layout.control_height=0;                                
+       },      
+       setSliderValue:function( perc ){
+               //get the track_clipThumb_height from parent mvSequencer        
+               var frame_width = Math.round( this.pSeq.track_clipThumb_height * 1.3333333 );
+               var container_width = frame_width+60;
+               
+               var perc_clip = this.cur_clip.embed.currentTime / this.cur_clip.getDuration();
+               
+               var left_px = parseInt( (this.cur_clip.order * container_width) + (frame_width*perc_clip) ) + 'px';     
+               js_log("set " + perc + ' of cur_clip: ' + this.cur_clip.order + ' lp:'+left_px);
+                                       
+                               
+               //update the timeline playhead and                       
+               $j('#'+ this.seqObj.timeline_id + '_playline').css('left', left_px);
+                       
+               //pass update request to parent:
+               this.parent_setSliderValue( perc );
+       },
+       getControlsHTML:function(){                             
+               //get controls from current clip add some playlist specific controls:             
+               this.cur_clip.embed.supports['prev_next'] = true;       
+               this.cur_clip.embed.supports['options']   = false;
+               return ctrlBuilder.getControls( this.cur_clip.embed );
+       },      
+       //override renderDisplay
+       renderDisplay:function(){
+               js_log('mvSequence:renderDisplay');
+               //setup layout for title and dc_ clip container  
+               $j(this).html('<div id="dc_'+this.id+'" style="width:'+this.width+'px;' +
+                               'height:'+(this.height)+'px;position:relative;" />');                   
+                               
+               this.setupClipDisplay();
+       }
+};
diff --git a/js2/mwEmbed/libSequencer/mvTimedEffectsEdit.js b/js2/mwEmbed/libSequencer/mvTimedEffectsEdit.js
new file mode 100644 (file)
index 0000000..f4c7c91
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+* mvTimedEffectsEdit
+* 
+* for now just simple single stack transition control
+*  
+*/
+
+//add our local msgs
+loadGM({ 
+       "transition_in"         : "Transition In",
+       "transition_out"        : "Transition Out",
+       "effects"                       : "Effects Stack",
+       "remove_transition"     : "Remove Transition",
+       "edit_transin"          : "Edit Transition Into Clip",
+       "edit_transout"         : "Edit Transition Out of Clip"
+});
+
+
+var default_timed_effect_values = {
+       'rObj': null,            // the resource object
+       'clip_disp_ct':null, //target clip disp
+       'control_ct':null,       //control container
+               
+       'parent_ct': null,       //parent container
+       'pSeq': null,    //parent sequence Object
+       
+       'edit_action': null, //the requested edit action                                                
+}
+var mvTimedEffectsEdit =function(iObj) {               
+       return this.init(iObj);
+};
+//set up the mvSequencer object
+mvTimedEffectsEdit.prototype = {
+       //the menu_items Object contains: default html, js setup/loader functions
+       menu_items : {
+               'transin':{
+                       'title':gM('transition_in'),
+                       'clip_attr':'transIn',
+                       'doEdit':function(_this){
+                               _this.doTransitionDisplayEdit('transin');
+                       }                                               
+               },
+               'transout':{
+                       'title':gM('transition_out'),
+                       'clip_attr':'transOut',
+                       'doEdit':function(_this){
+                               _this.doTransitionDisplayEdit('transout');      
+                       }                               
+               },
+               'effects':{
+                       'title':gM('effects'),
+                       'clip_attr':'Effects',
+                       'doEdit':function(_this){
+                               //display       
+                               _this.doEditEffectDisplayEdit();
+                       }       
+               }
+       },
+       init:function(iObj){
+               //init object:          
+               for(var i in default_timed_effect_values){                      
+                       if( iObj[i] ){   
+                               this[i] = iObj[i];
+                       }
+               }                                               
+               this.doEditMenu();
+       },      
+       doEditMenu:function(){
+               js_log('mvTimedEffects : doEditMenu::');
+               var _this = this;
+               //add in subMenus if set
+               //check for submenu and add to item container
+               
+               //update the default edit display (if we have a target)
+               var tTarget = 'transin';
+               if(this.rObj.transOut)
+                       tTarget = 'transout';
+               if(this.rObj.effects)
+                       tTarget = 'effects';            
+                       
+               var o='';               
+               var tabc ='';                                   
+               o+= '<div id="mv_submenu_timedeffect">';
+               o+='<ul>';                
+               var inx =0;             
+               var selected_tab=0;
+               $j.each(this.menu_items, function(sInx, mItem){                         
+                       if( sInx == tTarget){
+                               selected_tab = inx;
+                       }       
+                       //check if the given editType is valid for our given media type         
+                       o+=     '<li>'+ 
+                                       '<a id="mv_te_'+sInx+'" href="#te_' + sInx + '">' + mItem.title + '</a>'+
+                               '</li>';                                                                                                                        
+                       tabc += '<div id="te_' + sInx + '" style="overflow:auto;" ></div>';
+                       inx++;                                                                                                                                                                                                  
+               });
+               o+= '</ul>' + tabc;
+               o+= '</div>';
+               //add sub menu container with menu html:                        
+               $j('#'+this.control_ct).html( o ) ;             
+               js_log('should have set: #'+this.control_ct + ' to: ' + o);                                                             
+               //set up bindins:        
+               $j('#mv_submenu_timedeffect').tabs({
+                       selected: selected_tab,
+                       select: function(event, ui) {                                                                   
+                               _this.doDisplayEdit( $j(ui.tab).attr('id').replace('mv_te_', '') );
+                       }                               
+               }).addClass('ui-tabs-vertical ui-helper-clearfix');                     
+               //close left: 
+               $j("#mv_submenu_clipedit li").removeClass('ui-corner-top').addClass('ui-corner-left');
+               _this.doDisplayEdit(tTarget);                                                                                           
+       },
+       doDisplayEdit:function( tab_id ){
+               //@@todo fix the double display of doDisplayEdit                
+               js_log("doDisplayEdit::");
+               if( !this.menu_items[ tab_id ] ){
+                       js_log('error: doDisplayEdit missing item:' + tab_id);          
+               }else{
+                       //use the menu_item config to map to function display
+                       this.menu_items[tab_id].doEdit(this);
+               }                                       
+       },
+       doEditEffectDisplayEdit:function(){
+               var _this = this;
+               var appendTarget = '#te_effects';
+               js_log('type:' + _this.rObj['type']);
+               $j(appendTarget).html(gM('loading_txt'));
+               //@@todo integrate into core and loading system:  
+               loadExternalJs(mv_embed_path + 'libClipEdit/pixastic-editor/editor.js?' + getMvUniqueReqId() );
+               loadExternalJs(mv_embed_path + 'libClipEdit/pixastic-editor/pixastic.all.js?' + getMvUniqueReqId() );
+               loadExternalJs(mv_embed_path + 'libClipEdit/pixastic-editor/ui.js?' + getMvUniqueReqId() );
+               loadExternalJs(mv_embed_path + 'libClipEdit/pixastic-editor/uidata.js?' + getMvUniqueReqId() );
+               loadExternalCss(mv_embed_path + 'libClipEdit/pixastic-editor/pixastic.all.js?' + getMvUniqueReqId() );          
+                
+               var isPixasticReady = function(){
+                       if(typeof PixasticEditor != 'undefined'){
+                               $j(appendTarget).html('<a href="#" class="run_effect_demo">Run Pixastic Editor Demo</a> (not yet fully integrated/ super alpha)<br> best to view <a href="http://www.pixastic.com/editor-test/">stand alone</a>');
+                               $j(appendTarget + ' .run_effect_demo').click(function(){
+                                       var cat = _this;
+                                       var imgElm = $j( '.clip_container:visible  img').get(0);                                        
+                                       PixasticEditor.load(imgElm);                            
+                               });
+                       }else{
+                               setTimeout(isPixasticReady, 100)                
+                       }
+               }
+               isPixasticReady();                      
+       },
+       doTransitionDisplayEdit:function(target_item){
+               var _this = this;
+               js_log("doTransitionDisplayEdit: "+ target_item);
+               var apendTarget = '#te_' + target_item;
+               //check if we have a transition of type clip_attr
+               if(!this.rObj[ this.menu_items[ target_item ].clip_attr ]){
+                       //empty append the transition list:
+                       this.getTransitionListControl( apendTarget );
+                       return ;
+               }
+               var cTran = this.rObj[ this.menu_items[ target_item ].clip_attr ];
+               var o='<h3>' + gM('edit_'+target_item ) + '</h3>';
+               o+='Type: ' +
+                       '<select class="te_select_type">';
+               for(var typeKey in mvTransLib.type){                    
+                       var selAttr = (cTran.type == typeKey)?' selected':'';
+                       o+='<option     value="'+typeKey+'"'+ selAttr +'>'+typeKey+'</option>';
+               }
+               o+='</select><br>';             
+               o+='<span class="te_subtype_container"></span>';                                                                                
+               
+               //add html and select bindings
+               $j(apendTarget).html(o).children('.te_select_type')
+                       .change(function(){
+                               var selectedType = $j(this).val();
+                               //update subtype listing:                                                                               
+                               _this.getSubTypeControl(target_item, selectedType, apendTarget + ' .te_subtype_container' );
+                       });
+               //add subtype control
+               _this.getSubTypeControl( target_item, cTran.type, apendTarget + ' .te_subtype_container' );
+               
+               //add remove transition button:
+               $j(apendTarget).append( '<br><br>' + $j.btnHtml(gM('remove_transition'), 'te_remove_transition', 'close'  ) )
+                       .children('.te_remove_transition')
+                       .click(function(){                                                              
+                               //remove the transtion from the playlist
+                               _this.pSeq.plObj.transitions[cTran.id] = null;
+                               //remove the transtion from the clip:
+                               _this.rObj[ _this.menu_items[ target_item ].clip_attr ] = null;                         
+                               //update the interface: 
+                               _this.doTransitionDisplayEdit( target_item );
+                               //update the sequence
+                               _this.pSeq.do_refresh_timeline();
+                       });             
+       },      
+       getSubTypeControl:function(target_item, transition_type, htmlTarget){
+               var _this = this;                                               
+               var cTran = this.rObj[ this.menu_items[ target_item ].clip_attr ];      
+               var o='Sub Type:<select class="te_subtype_select">';
+               for(var subTypeKey in mvTransLib.type[ transition_type ]){
+                       var selAttr = (cTran.subtype == subTypeKey) ? ' selected' : '';
+                       o+='<option     value="'+subTypeKey+'"'+ selAttr +'>'+subTypeKey+'</option>';
+               }
+               o+='</select><br>';
+               $j(htmlTarget).html(o)
+                       .children('.te_subtype_select')
+                       .change(function(){
+                               //update the property
+                               cTran.subtype = $j(this).val(); 
+                               //re-gen timeline / playlist
+                               _this.pSeq.do_refresh_timeline();
+                               //(re-select self?) 
+                               _this.getSubTypeControl(target_item, transition_type, htmlTarget);
+               });     
+               var o='';
+               //check for extra properties control: 
+               for(var i=0; i < mvTransLib.type[ transition_type ][ cTran.subtype ].attr.length; i++){
+                       var tAttr =mvTransLib.type[ transition_type ][ cTran.subtype ].attr[i]
+                       switch(tAttr){
+                               case 'fadeColor':
+                                       var cColor = (cTran['fadeColor'])?cTran['fadeColor']:'';
+                                       $j(htmlTarget).append('Select Color: <div class="colorSelector"><div class="colorIndicator" style="background-color: '+cColor+'"></div></div>');                        
+                                       js_log('cs target: '+htmlTarget +' .colorSelector' );
+                               
+                               
+                                       $j(htmlTarget + ' .colorSelector').ColorPicker({                                                
+                                               color: cColor,
+                                               onShow: function (colpkr) {
+                                                       //make sure its ontop:
+                                                       $j(colpkr).css("zIndex", "12");                                                         
+                                                       $j(colpkr).fadeIn(500);
+                                                       return false;
+                                               },
+                                               onHide: function (colpkr) {
+                                                       $j(colpkr).fadeOut(500);                                                                                                
+                                                       _this.pSeq.plObj.setCurrentTime(0, function(){
+                                                               js_log("render ready");
+                                                       });     
+                                                       return false;
+                                               },
+                                               onChange: function (hsb, hex, rgb) {
+                                                       $j(htmlTarget + ' .colorIndicator').css('backgroundColor', '#' + hex);
+                                                       //update the transition 
+                                                       cTran['fadeColor'] =  '#' + hex;                                                                                                                                                                                                                        
+                                               }
+                                       })
+                               break;
+                       }
+               }
+               //and finally add effect timeline scrubber (for timed effects this also stores keyframes)
+                               
+       },
+       getTransitionListControl:function(target_out){
+               js_log("getTransitionListControl");
+               var o= '<h3>Add a Transition:</h3>';
+               for(var type in mvTransLib['type']){
+                       js_log('on tran type: ' + i);                   
+                       var base_trans_name = i;
+                       var tLibSet = mvTransLib['type'][ type ];
+                       for(var subtype in tLibSet){                    
+                               o+='<img style="float:left;padding:10px;" '+
+                                       'src="' + mvTransLib.getTransitionIcon(type, subtype)+ '">';            
+                       }
+               }       
+               $j(target_out).html(o);
+       }               
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/libTimedText/mvTextInterface.js b/js2/mwEmbed/libTimedText/mvTextInterface.js
new file mode 100644 (file)
index 0000000..6d67536
--- /dev/null
@@ -0,0 +1,520 @@
+
+loadGM({
+    
+    "select_transcript_set" : "Select Layers",
+       "auto_scroll" : "auto scroll",
+       "close" : "close",
+       "improve_transcript" : "Improve"
+       
+})
+// text interface object (for inline display captions) 
+var mvTextInterface = function( parentEmbed ){
+       return this.init( parentEmbed );
+}
+mvTextInterface.prototype = {
+       text_lookahead_time:0,
+       body_ready:false,
+       default_time_range: "source", //by default just use the source don't get a time-range
+       transcript_set:null,
+       autoscroll:true,
+       add_to_end_on_this_pass:false,
+       scrollTimerId:0,        
+       init:function( parentEmbed ){
+                  //init a new availableTracks obj:
+               this.availableTracks={};        
+               //set the parent embed object:
+               this.pe=parentEmbed;
+               //parse roe if not already done:
+               this.getTimedTextTracks();              
+       },
+       //@@todo separate out data loader & data display
+       getTimedTextTracks:function(){
+               js_log("load timed text from roe: "+ this.pe.roe);
+               var _this = this;
+               //if roe not yet loaded do load it: 
+               if(this.pe.roe){
+                       if(!this.pe.media_element.addedROEData){
+                               js_log("load roe data!");
+                               $j('#mv_txt_load_'+_this.pe.id).show(); //show the loading icon
+                               do_request( _this.pe.roe, function(data)
+                               {                                                
+                                       //continue                       
+                                       _this.pe.media_element.addROE(data);                                                                                                                                                                            
+                                       _this.getParseTimedText_rowReady();                                        
+                               });
+                       }else{
+                               js_log('row data ready (no roe request)');
+                               _this.getParseTimedText_rowReady();
+                       }                                               
+               }else{                  
+                       if( this.pe.media_element.timedTextSources() ){
+                               _this.getParseTimedText_rowReady();
+                       }else{
+                               js_log('no roe data or timed text sources');
+                       }
+               }               
+       },
+       getParseTimedText_rowReady: function (){
+               var _this = this;               
+               //create timedTextObj           
+               var default_found=false;
+               js_log("mv_txt_load_:SHOW mv_txt_load_");
+               $j('#mv_txt_load_'+_this.pe.id).show(); //show the loading icon
+               
+               $j.each( this.pe.media_element.sources, function(inx, source){
+                       
+                       if( typeof source.id == 'undefined' || source.id == null ){
+                               source.id = 'tt_' + inx;                        
+                       }
+                       var tObj = new timedTextObj( source );                  
+                       //make sure its a valid timed text format (we have not loaded or parsed yet) : ( 
+                       if( tObj.lib != null ){
+                               js_log('adding Track: ' + source.id + ' to ' + _this.pe.id); 
+                               _this.availableTracks[ source.id ] = tObj;                      
+                               //js_log( 'is : ' + source.id + ' default: ' + source.default );                                                                                                        
+                               //display if requested:                 
+                               if( source['default'] == "true" ){
+                                       //we did set at least one track by default tag
+                                       default_found=true;                                                                                     
+                                       js_log('do load timed text: ' + source.id );
+                                       _this.loadAndDisplay( source.id );      
+                               }else{
+                                       //don't load the track and don't display                                                                                                                
+                               }
+                       }
+               });
+               
+               //no default clip found take the first_id
+               if(!default_found){
+                       $j.each( _this.availableTracks, function(inx, sourceTrack){                             
+                               _this.loadAndDisplay( sourceTrack.id );                         
+                               default_found=true;
+                               //retun after loading first available
+                               return false;
+                       });
+               }
+               
+               //if nothing found anywhere update the loading icon to say no tracks found
+               if(!default_found)
+                       $j('#mv_txt_load_'+_this.pe.id).html( gM('no_text_tracks_found') );
+               
+               
+       },
+       loadAndDisplay: function ( track_id){
+               var _this = this;
+               $j('#mv_txt_load_'+_this.pe.id).show();//show the loading icon
+               _this.availableTracks[ track_id ].load(_this.default_time_range, function(){
+                       $j('#mv_txt_load_'+_this.pe.id).hide();
+                       _this.addTrack( track_id );
+               });     
+       },
+       addTrack: function( track_id ){
+               js_log('f:displayTrack:'+ track_id);
+               var _this = this;
+               //set the display flag to true:
+               _this.availableTracks[ track_id ].display=true;
+               //setup the layout:
+               this.setup_layout();
+               js_log("SHOULD ADD: "+ track_id + ' count:' +  _this.availableTracks[ track_id ].textNodes.length);
+               
+               //a flag to avoid checking all clips if we know we are adding to the end: 
+               _this.add_to_end_on_this_pass = false;
+               
+               //run clip adding on a timed interval to not lock the browser on large srt file merges (should use worker threads)
+               var i =0;
+               var track_id = track_id;
+               var addNextClip = function(){                                           
+                       var text_clip = _this.availableTracks[ track_id ].textNodes[i];         
+                       _this.add_merge_text_clip(text_clip);
+                       i++;    
+                       if(i < _this.availableTracks[ track_id ].textNodes.length){                                             
+                               setTimeout(addNextClip, 1);                             
+                       }
+               }
+               addNextClip();
+       },      
+       add_merge_text_clip: function( text_clip ){             
+               var _this = this;
+               //make sure the clip does not already exist:
+               if($j('#tc_'+text_clip.id).length==0){
+                       var inserted = false;
+                       var text_clip_start_time = npt2seconds( text_clip.start );
+                       
+                       var insertHTML = '<div id="tc_'+text_clip.id+'" ' +
+                               'start_sec="' + text_clip_start_time + '" ' + 
+                               'start="'+text_clip.start+'" end="'+text_clip.end+'" class="mvtt tt_'+text_clip.type_id+'">' +
+                                       '<div class="mvttseek" style="top:0px;left:0px;right:0px;height:20px;font-size:small">'+                                                
+                                               text_clip.start + ' to ' +text_clip.end+
+                                       '</div>'+
+                                       text_clip.body +
+                       '</div>';                       
+                       //js_log("ADDING CLIP: "  + text_clip_start_time + ' html: ' + insertHTML);
+                       if(!_this.add_to_end_on_this_pass){
+                               $j('#mmbody_'+this.pe.id +' .mvtt').each(function(){
+                                       if(!inserted){
+                                               //js_log( npt2seconds($j(this).attr('start')) + ' > ' + text_clip_start_time);
+                                               if( $j(this).attr('start_sec') > text_clip_start_time){
+                                                       inserted=true;
+                                                       $j(this).before(insertHTML);
+                                               }
+                                       }else{
+                                               _this.add_to_end = true;
+                                       }
+                               });             
+                       }
+                       //js_log('should just add to end: '+insertHTML);
+                       if(!inserted){
+                               $j('#mmbody_'+this.pe.id ).append(insertHTML);
+                       }
+                       
+                       //apply the mouse over transcript seek/click functions:
+                       $j(".mvttseek").click( function() {
+                               _this.pe.doSeek( $j(this).parent().attr("start_sec") / _this.pe.getDuration() );
+                       });
+                       $j(".mvttseek").hoverIntent({
+                               interval:200, //polling interval
+                               timeout:200, //delay before onMouseOut
+                               over:function () {
+                                         js_log('mvttseek: over');
+                                         $j(this).parent().addClass('tt_highlight');
+                                       //do section highlight
+                                       _this.pe.highlightPlaySection( {
+                                               'start' : $j(this).parent().attr("start"),
+                                               'end'   : $j(this).parent().attr("end")
+                                       });
+                               }, 
+                               out:function () {       
+                                         js_log('mvttseek: out');                
+                                         $j(this).parent().removeClass('tt_highlight');        
+                                         //de highlight section  
+                                       _this.pe.hideHighlight();
+                               }
+                         }
+                       );
+               }
+       },
+       setup_layout:function(){                                                        
+               //check if we have already loaded the menu/body: 
+               if($j('#tt_mmenu_'+this.pe.id).length==0){
+                       $j('#metaBox_'+this.pe.id).html(                        
+                               this.getMenu() +
+                               this.getBody() 
+                       );
+                       this.doMenuBindings();
+               }                                               
+       },
+       show:function(){
+               //setup layout if not already done:
+               this.setup_layout();
+               //display the interface if not already displayed:  
+               $j('#metaBox_'+this.pe.id).fadeIn("fast");              
+               //start the autoscroll timer:
+               if( this.autoscroll )
+                       this.setAutoScroll();
+       },
+       close:function(){
+               //the meta box:
+               $j('#metaBox_'+this.pe.id).fadeOut('fast');
+               //the icon link:
+               $j('#metaButton_'+this.pe.id).fadeIn('fast');
+       },
+       getBody:function(){
+               return '<div id="mmbody_'+this.pe.id+'" ' +
+                               'style="position:absolute;top:30px;left:0px;' +
+                               'right:0px;bottom:0px;' +
+                               'height:'+(this.pe.height-30)+
+                               'px;overflow:auto;"><span style="display:none;" id="mv_txt_load_' + this.pe.id + '">'+
+                                       gM('loading_txt')+'</span>' +
+                               '</div>';
+       },
+       getTsSelect:function(){
+               var _this = this;
+               js_log('getTsSelect');          
+               var selHTML = '<div id="mvtsel_' + this.pe.id + '" style="position:absolute;background:#FFF;top:30px;left:0px;right:0px;bottom:0px;overflow:auto;">';
+               selHTML+='<b>' + gM('select_transcript_set') + '</b><ul>';
+               //debugger;
+               for(var i in _this.availableTracks){ //for in loop ok on object                 
+                       var checked = ( _this.availableTracks[i].display ) ? 'checked' : '';
+                       selHTML+='<li><input name="'+i+'" class="mvTsSelect" type="checkbox" ' + checked + '>'+
+                               _this.availableTracks[i].getTitle() + '</li>';
+               }
+               selHTML+='</ul>' +
+                                       '<a href="#" onClick="document.getElementById(\'' + this.pe.id + '\').textInterface.applyTsSelect();return false;">'+gM('close')+'</a>'+
+                               '</div>';               
+               $j('#metaBox_'+_this.pe.id).append( selHTML );
+       },
+       applyTsSelect:function(){
+               var _this = this;                               
+               //update availableTracks                
+               $j('#mvtsel_'+this.pe.id+' .mvTsSelect').each(function(){
+                       if(this.checked){
+                               var track_id = this.name;
+                               //if not yet loaded now would be a good time
+                               if(! _this.availableTracks[ track_id ].loaded ){
+                                       _this.loadAndDisplay( track_id);
+                               }else{
+                                       _this.availableTracks[this.name].display=true;
+                                       //display the named class: 
+                                       $j('#mmbody_'+_this.pe.id +' .tt_'+this.name ).fadeIn("fast");
+                               }
+                       }else{
+                               if(_this.availableTracks[this.name].display){
+                                       _this.availableTracks[this.name].display=false;
+                                       //hide unchecked
+                                       $j('#mmbody_'+_this.pe.id +' .tt_'+this.name ).fadeOut("fast");
+                               }
+                       }
+               });             
+               $j('#mvtsel_'+_this.pe.id).fadeOut("fast").remove();
+       },
+       monitor:function(){
+               _this = this;
+               //grab the time from the video object
+               var cur_time = this.pe.currentTime ;
+               if( cur_time!=0 ){
+                       var search_for_range = true;
+                       //check if the current transcript is already where we want: 
+                       if($j('#mmbody_'+this.pe.id +' .tt_scroll_highlight').length != 0){
+                               var curhl = $j('#mmbody_'+this.pe.id +' .tt_scroll_highlight').get(0);
+                               if(npt2seconds($j(curhl).attr('start') ) < cur_time &&
+                                  npt2seconds($j(curhl).attr('end') ) > cur_time){
+                                       /*js_log('in range of current hl: ' + 
+                                               npt2seconds($j(curhl).attr('start')) +  ' to ' +  npt2seconds($j(curhl).attr('end')));
+                                       */
+                                       search_for_range = false;                                       
+                               }else{
+                                       search_for_range = true;
+                                       //remove the highlight from all: 
+                                       $j('#mmbody_'+this.pe.id +' .tt_scroll_highlight').removeClass('tt_scroll_highlight');
+                               }
+                       };                      
+                       /*js_log('search_for_range:'+search_for_range +  ' for: '+ cur_time);*/
+                       if( search_for_range ){                         
+                               //search for current time: add tt_scroll_highlight to clip              
+                               // optimize:
+                               //  should do binnary search not iterative 
+                               //  avoid jquery function calls do native loops 
+                               $j('#mmbody_'+this.pe.id +' .mvtt').each(function(){
+                                       if(npt2seconds($j(this).attr('start') ) < cur_time &&
+                                          npt2seconds($j(this).attr('end') ) > cur_time){                                                                                                                                              
+                                               _this.prevTimeScroll=cur_time;
+                                               $j('#mmbody_'+_this.pe.id).animate({
+                                                       scrollTop: $j(this).get(0).offsetTop                                            
+                                               }, 'slow');
+                                               $j(this).addClass('tt_scroll_highlight');
+                                               //js_log('should add class to: ' + $j(this).attr('id'));
+                                               //done with loop
+                                               return false;
+                                       }
+                               });
+                       }
+               }
+       },
+       setAutoScroll:function( timer ){
+               var _this = this;
+               this.autoscroll = ( typeof timer=='undefined' )?this.autoscroll:timer;           
+               if(this.autoscroll){
+                       //start the timer if its not already running
+                       if(!this.scrollTimerId){                                                                
+                               this.scrollTimerId = setInterval('$j(\'#'+_this.pe.id+'\').get(0).textInterface.monitor()', 500);
+                       }
+                       //jump to the current position:
+                       var cur_time = parseInt (this.pe.currentTime );
+                       js_log('cur time: '+ cur_time);
+
+                       _this = this;
+                       var scroll_to_id='';
+                       $j('#mmbody_'+this.pe.id +' .mvtt').each(function(){
+                               if(cur_time > npt2seconds($j(this).attr('start'))  ){
+                                       _this.prevTimeScroll=cur_time;
+                                       if( $j(this).attr('id') )       
+                                               scroll_to_id = $j(this).attr('id');     
+                               }
+                       });
+                       if(scroll_to_id != '')
+                               $j( '#mmbody_' + _this.pe.id ).animate( { scrollTop: $j('#'+scroll_to_id).position().top } , 'slow' );
+               }else{
+                       //stop the timer
+                       clearInterval(this.scrollTimerId);
+                       this.scrollTimerId=0;
+               }
+       },
+       getMenu:function(){
+               var out='';
+               //add in loading icon:
+               var as_checked = (this.autoscroll)?'checked':'';
+               out+= '<div id="tt_mmenu_'+this.pe.id+'" class="ui-widget-header" style="font-size:.6em;position:absolute;top:0;height:30px;left:0px;right:0px;">' +                   
+                               $j.btnHtml(gM('select_transcript_set'), 'tt-select', 'shuffle');                                                                
+               if(this.pe.media_element.linkback){
+                       out+=' ' + $j.btnHtml(gM('improve_transcript'), 'tt-improve', 'document', {href:this.pe.media_element.linkback, target:'_new'});                        
+               }
+               out+='<input onClick="document.getElementById(\''+this.pe.id+'\').textInterface.setAutoScroll(this.checked);return false;" ' +
+                               'type="checkbox" '+as_checked +'>'+gM('auto_scroll') + ' ' + 
+              $j.btnHtml(gM('close'), 'tt-close', 'circle-close');                             
+               out+='</div>';          
+               return out;
+       },
+       doMenuBindings:function(){
+           var _this = this;
+           var mt = '#tt_mmenu_'+ _this.pe.id;
+           $j(mt + ' .tt-close').unbind().btnBind().click(function(){
+              $j( '#' + _this.pe.id).get(0).closeTextInterface();  
+              return false;
+           });
+           $j(mt + ' .tt-select').unbind().btnBind().click(function(){
+              $j( '#' +  _this.pe.id).get(0).textInterface.getTsSelect();
+              return false;
+           });
+           //use hard-coded link: 
+           $j(mt + ' .tt-improve').btnBind();
+       }
+}
+
+/* text format objects
+*  @@todo allow loading from external lib set 
+*/ 
+var timedTextObj = function( source ){ 
+       //@@todo in the future we could support timed text in oggs if they can be accessed via javascript
+       //we should be able to do a HEAD request to see if we can read transcripts from the file.   
+       switch( source.mime_type ){
+               case 'text/cmml':
+                       this.lib = 'CMML';
+               break;
+               case 'text/srt':
+               case 'text/x-srt':
+                       this.lib = 'SRT';
+               break;          
+               default:                        
+                       js_log( source.mime_type + ' is not suported timed text fromat');
+                       return ;
+               break;
+       }       
+       //extend with the per-mime type lib:    
+       eval('var tObj = timedText' + this.lib + ';');
+       for( var i in tObj ){
+               this[ i ] = tObj[i];
+       }
+       return this.init( source );
+}
+
+//base timedText object 
+timedTextObj.prototype = {
+       loaded: false,
+       lib:null,
+       display: false,
+       textNodes:new Array(),
+       init: function( source ){                       
+               //copy source properties        
+               this.source = source;
+               this.id = source.id;
+       },
+       getTitle:function(){
+               return this.source.title;
+       },
+       getSRC:function(){              
+               return this.source.src;
+       }
+}
+
+// Specific Timed Text formats:
+
+timedTextCMML = {
+       load: function( range, callback ){
+               var _this = this;
+               js_log('textCMML: loading track: '+ this.src);
+               
+               //:: Load transcript range ::  
+               
+               var pcurl =  parseUri( _this.getSRC() );
+               //check for urls without time keys: 
+               if( typeof pcurl.queryKey['t'] == 'undefined'){
+                       //in which case just get the full time req: 
+                       do_request( this.getSRC(), function(data){                                                                                                      
+                               _this.doParse( data );          
+                               _this.loaded=true;      
+                               callback();
+                       });
+                       return ;
+               }
+               var req_time = pcurl.queryKey['t'].split('/');
+               req_time[0]=npt2seconds(req_time[0]);
+               req_time[1]=npt2seconds(req_time[1]);
+               if(req_time[1]-req_time[0]> _this.request_length){
+                       //longer than 5 min will only issue a (request 5 min)
+                       req_time[1] = req_time[0]+_this.request_length;
+               }
+               //set up request url:
+               url = pcurl.protocol + '://' + pcurl.authority + pcurl.path +'?';
+               $j.each(pcurl.queryKey, function(key, val){                                             
+                       if( key != 't'){
+                               url+=key+'='+val+'&';
+                       }else{
+                               url+= 't=' + seconds2npt(req_time[0]) + '/' + seconds2npt(req_time[1]) + '&';
+                       }
+               });                                                     
+               do_request( url, function(data){                        
+                       js_log("load track clip count:" + data.getElementsByTagName('clip').length );                                           
+                       _this.doParse( data );          
+                       _this.loaded=true;      
+                       callback();
+               });
+       },
+       doParse: function(data){
+               var _this = this;
+               $j.each(data.getElementsByTagName('clip'), function(inx, clip){
+                       //js_log(' on clip ' + clip.id);
+                       var text_clip = {
+                               start: $j(clip).attr('start').replace('npt:', ''),
+                               end: $j(clip).attr('end').replace('npt:', ''),
+                               type_id: _this.id,
+                               id: $j(clip).attr('id')
+                       }
+                       $j.each( clip.getElementsByTagName('body'), function(binx, bn ){
+                               if(bn.textContent){
+                                       text_clip.body = bn.textContent;
+                               }else if(bn.text){
+                                       text_clip.body = bn.text;
+                               }
+                       });                     
+                       _this.textNodes.push( text_clip );
+               });     
+       }
+}
+timedTextSRT = {
+       load: function( range, callback ){
+               var _this = this;
+               js_log('textSRT: loading : '+ _this.getSRC() );
+               do_request( _this.getSRC() , function(data){                    
+                       _this.doParse( data );
+                       _this.loaded=true;      
+                       callback();
+               });
+       },
+       doParse:function( data ){
+               //split up the transcript chunks:               
+               //strip any \r's                                                
+               var tc = data.split(/[\r]?\n[\r]?\n/);                                  
+               //pushing can take time 
+               for(var s=0; s < tc.length ; s++) {                     
+                       var st = tc[s].split('\n');
+                       if(st.length >=2) {
+                               var n = st[0];                   
+                               var i = st[1].split(' --> ')[0].replace(/^\s+|\s+$/g,"");                       
+                               var o = st[1].split(' --> ')[1].replace(/^\s+|\s+$/g,"");
+                               var t = st[2];
+                               if(st.length > 2) {
+                                       for(j=3; j<st.length;j++)
+                                               t += '\n'+st[j];
+                               }                         
+                               var text_clip = {
+                                       "start": i,
+                                       "end": o,
+                                       "type_id": this.id,
+                                       "id": this.id + '_' + n,
+                                       "body": t
+                               }
+                               this.textNodes.push( text_clip );
+                        }
+               }                       
+       }       
+};
diff --git a/js2/mwEmbed/mv_embed.js b/js2/mwEmbed/mv_embed.js
new file mode 100644 (file)
index 0000000..c770e31
--- /dev/null
@@ -0,0 +1,1338 @@
+/*
+ * ~mv_embed version 1.0~
+ * for details see: http://metavid.org/wiki/index.php/Mv_embed
+ *
+ * All Metavid Wiki code is Released under the GPL2
+ * for more info visit http://metavid.org/wiki/Code
+ *
+ * @url http://metavid.org
+ *
+ * parseUri:
+ * http://stevenlevithan.com/demo/parseuri/js/
+ *
+ * config values you can manually set the location of the mv_embed folder here
+ * (in cases where media will be hosted in a different place than the embedding page)
+ *
+ */
+//fix multiple instances of mv_embed (ie include twice from two different servers) 
+var MV_DO_INIT=true;
+if( MV_EMBED_VERSION ){        
+       MV_DO_INIT=false;       
+}
+//used to grab fresh copies of scripts. (should be changed on commit)  
+var MV_EMBED_VERSION = '1.0r17';
+
+/*
+ * Configuration variables (can be set from some precceding script) 
+ */
+//the name of the player skin (default is mvpcf)
+if(!mv_skin_name)
+       var mv_skin_name = 'mvpcf';
+       
+if(!mwjQueryUiSkin)
+       var mwjQueryUiSkin = 'redmond';
+
+//whether or not to load java from an iframe.
+//note: this is necessary for remote embedding because of java security model)
+if(!mv_java_iframe)
+       var mv_java_iframe = true;
+
+//media_server mv_embed_path (the path on media servers to mv_embed for java iframe with leading and trailing slashes)
+if(!mv_media_iframe_path)
+       var mv_media_iframe_path = '/mv_embed/';
+
+//the default height/width of the video (if no style or width attribute provided)
+if(!mv_default_video_size)     
+       var mv_default_video_size = '400x300'; 
+       
+//for when useing mv_embed with script-loader in root mediawiki path
+var mediaWiki_mvEmbed_path = 'js2/mwEmbed/';
+
+var global_player_list = new Array(); //the global player list per page
+var global_req_cb = new Array(); //the global request callback array
+var _global = this; //global obj
+var mv_init_done=false;
+var global_cb_count =0;
+
+/*parseUri class parses URIs:*/
+var parseUri=function(d){var o=parseUri.options,value=o.parser[o.strictMode?"strict":"loose"].exec(d);for(var i=0,uri={};i<14;i++){uri[o.key[i]]=value[i]||""}uri[o.q.name]={};uri[o.key[12]].replace(o.q.parser,function(a,b,c){if(b)uri[o.q.name][b]=c});return uri};parseUri.options={strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};
+
+
+//get mv_embed location if it has not been set
+if( !mv_embed_path ){
+       var mv_embed_path = getMvEmbedPath();
+}
+jQueryUiVN = 'jquery.ui-1.7.1'; 
+
+
+//setup the skin path: 
+var mv_jquery_skin_path = mv_embed_path + 'jquery/' + jQueryUiVN + '/themes/' + mwjQueryUiSkin + '/';
+var mv_skin_img_path = mv_embed_path + 'skins/' + mv_skin_name + '/images/';
+var mv_default_thumb_url = mv_skin_img_path + 'vid_default_thumb.jpg';
+
+
+//init the global Msg if not already
+if(!gMsg){var gMsg={};}
+//laguage loader:
+function loadGM( msgSet ){
+       for(var i in msgSet){
+               gMsg[ i ] = msgSet[i];
+       }
+}
+
+//all default msg in [English] should be overwritten by the CMS language msg system.
+loadGM({ 
+       "loading_txt":"loading <blink>...</blink>",     
+       "loading_title"  : "Loading...",                                        
+       
+       "size-gigabytes" : "$1 GB",
+       "size-megabytes" : "$1 MB",
+       "size-kilobytes" : "$1 K",
+       "size-bytes" : "$1 B"
+       
+});
+
+/** 
+ * AutoLoader paths (this should mirror the file: jsAutoloadLocalClasses.php ) 
+ * any file _not_ listed here won't be auto-loadable 
+ * @path the path to the file (or set of files) with ending slash
+ * @gClasses the set of classes 
+ *             if an array $j.className become jquery.className.js
+ *             if an asssociative objec then key => value paris are used
+ */
+if(typeof mvClassPaths == 'undefined')
+       mvClassPaths = {};
+       
+function lcPaths( path, gClasses , opt){       
+       if(!opt)
+               opt = {};
+       if(typeof opt['j_replace'] == 'undefined')
+               opt['j_replace'] = 'jquery.';   
+       if(!path)
+               path = '';      
+       if(gClasses.length){
+               //do array loop: 
+               for(var i=0; i<gClasses.length; i++){
+                       if(typeof gClasses[i] != 'undefined'){
+                               //setup normal replacement of j with jquery                     
+                               var jsName = ( gClasses[i].substr(0,3) == '$j.' ) ? opt['j_replace'] + gClasses[i].substr(3) : gClasses[i];                                                     
+                               mvClassPaths[ gClasses[i] ] = path + jsName + '.js';
+                       }
+               }               
+       }else{
+               //do object loop: 
+               for(var i in gClasses){                 
+                       //assume object with key:path:
+                       mvClassPaths[i] = path + gClasses[ i ];
+               }
+       }
+       var cat = mvClassPaths; 
+}
+function mvGetClassPath(k){            
+       if( mvClassPaths[k] ){
+               //js_log('got classpath:' + k +  ' : '+ mvClassPaths[k]);
+               return mvClassPaths[k];
+       }else{
+               return js_error('could not find path for requested class ' + k );
+       }
+}
+if(typeof mvCssPaths == 'undefined')
+       mvCssPaths = {};
+       
+function lcCssPath(cssSet){
+       for(var i in cssSet){
+               mvCssPaths[i]= mv_embed_path + cssSet[i];
+       }
+}
+//core and (non-standard named files relative to class the init):
+lcPaths('',{
+       'mv_embed'                      : 'mv_embed.js',
+       'window.jQuery'         : 'jquery/jquery-1.3.2.js',     
+       '$j.fn.pngFix'          : 'jquery/plugins/jquery.pngFix.js',
+       '$j.fn.autocomplete': 'jquery/plugins/jquery.autocomplete.js',
+       '$j.fn.hoverIntent'     : 'jquery/plugins/jquery.hoverIntent.js',
+       '$j.fn.datePicker'      : 'jquery/plugins/jquery.datePicker.js',
+       '$j.ui'                         : 'jquery/jquery.ui-1.7.1/ui/ui.core.js',       
+       '$j.fn.ColorPicker'     : 'libClipEdit/colorpicker/js/colorpicker.js',
+       '$j.Jcrop'                      : 'libClipEdit/Jcrop/js/jquery.Jcrop.js'
+});    
+//query plugins
+lcPaths( 'jquery/plugins/', [
+       '$j.secureEvalJSON',    
+       '$j.cookie',
+       '$j.contextMenu',                               
+]);
+//jquery ui
+lcPaths('jquery/jquery.ui-1.7.1/ui/', [        
+       '$j.effects.blind',
+       '$j.effects.drop',
+       '$j.effects.pulsate',
+       '$j.effects.transfer',
+       '$j.ui.droppable',
+       '$j.ui.slider',
+       '$j.effects.bounce',
+       '$j.effects.explode',
+       '$j.effects.scale',
+       '$j.ui.datepicker',
+       '$j.ui.progressbar',
+       '$j.ui.sortable',
+       '$j.effects.clip',
+       '$j.effects.fold',
+       '$j.effects.shake',
+       '$j.ui.dialog',
+       '$j.ui.resizable',
+       '$j.ui.tabs',
+       '$j.effects.core',
+       '$j.effects.highlight',
+       '$j.effects.slide',
+       '$j.ui.accordion',
+       '$j.ui.draggable',
+       '$j.ui.selectable',
+], 
+{'j_replace':''});
+//add mediaLibs
+lcPaths('libAddMedia/', [
+       'mvFirefogg',
+       'mvAdvFirefogg',
+    'mvBaseUploadInterface',
+       'remoteSearchDriver',
+       'seqRemoteSearchDriver',
+]);
+//search libs: 
+lcPaths('libAddMedia/searchLibs/', [
+       'baseRemoteSearch',
+       'mediaWikiSearch',
+       'metavidSearch',
+       'archiveOrgSearch',
+       'baseRemoteSearch'
+]);                    
+//libclip edit
+lcPaths( 'libClipEdit/', [
+       'mvClipEdit'    
+])     
+//libEmbedObj (we could load all these clasess in embedVideo):
+lcPaths( 'libEmbedVideo/', [
+       'embedVideo',
+       'flashEmbed',
+       'genericEmbed',
+       'htmlEmbed',
+       'javaEmbed',
+       'nativeEmbed',
+       'quicktimeEmbed',
+       'vlcEmbed'
+])
+//libSequencer:        
+lcPaths( 'libSequencer/', [
+       'mvPlayList',
+       'mvSequencer',
+       'mvTimedEffectsEdit'
+])
+//libTimedText:
+lcPaths( 'libTimedText/', [
+       'mvTextInterface'
+]);
+
+//depencency mapping for css files for self contained included plugins:
+lcCssPath({
+       '$j.Jcrop'              : 'libClipEdit/Jcrop/css/jquery.Jcrop.css',
+       '$j.fn.ColorPicker': 'libClipEdit/colorpicker/css/colorpicker.css'
+})
+
+/**
+ * Language Functions:
+ * 
+ * These functions try to losely mirro the functionality of Language.php in mediaWiki
+ */ 
+function gM( key , args ) {
+       var ms ='';     
+       if ( key in gMsg ) {
+               ms = gMsg[ key ];
+               if(typeof args == 'object' || typeof args == 'array'){                           
+                        for(var v in args){
+                               //msg test replace arguments start at 1 insted of zero: 
+                                var rep = '\$'+ ( parseInt(v) + 1 );                            
+                                ms = ms.replace( rep, args[v]);
+                        }                       
+               }else if(typeof args =='string' || typeof args =='number'){
+                       ms = ms.replace(/\$1/, args);
+                }
+                return ms;
+       } else{
+               //key is missing return indication: 
+               return '&lt;' + key + '&gt;';
+       }        
+}
+/*
+ * msgSet is either a string corresponding to a single msg to load
+ * or msgSet is an array with set of msg to load
+ */
+function gMsgLoadRemote(msgSet, callback){     
+       var ammessages = '';
+       if(typeof msgSet == 'object' ){
+               for(var i in msgSet){                   
+                       ammessages +=  msgSet[i] + '|';
+               }
+       }else if(typeof msgSet == 'string'){
+               ammessages += msgSet;
+       }
+       if(ammessages == ''){
+               js_log('gMsgLoadRemote::no msg set requested');
+               return false;
+       }                       
+       do_api_req({
+               'data':{
+                       'meta':'allmessages', 
+                       'ammessages':ammessages
+               }               
+       },function(data){
+               if(data.query.allmessages){
+                       var msgs = data.query.allmessages;
+                       for(var i in msgs){
+                               var ld = {};
+                               ld[ msgs[i]['name'] ] =  msgs[i]['*'];
+                               loadGM( ld );
+                       }
+               }
+               //load the result into local msg var
+               callback();
+       });             
+}
+
+/**
+ * Format a size in bytes for output, using an appropriate
+ * unit (B, KB, MB or GB) according to the magnitude in question
+ *
+ * @param size Size to format
+ * @return string Plain text (not HTML)
+ */
+function formatSize( size ) {
+       // For small sizes no decimal places necessary
+       var round = 0;
+       var msg = '';
+       if( size > 1024 ) {
+               size = size / 1024;
+               if( size > 1024 ) {
+                       size = size / 1024;
+                       // For MB and bigger two decimal places are smarter
+                       round = 2;
+                       if( size > 1024 ) {
+                               size = size / 1024;
+                               msg = 'size-gigabytes';
+                       } else {
+                               msg = 'size-megabytes';
+                       }
+               } else {
+                       msg = 'size-kilobytes';
+               }
+       } else {
+               msg = 'size-bytes';
+       }
+       //javascript does not let you do precession points in rounding
+       var p =  Math.pow(10,round);
+       var size = Math.round( size * p  ) / p;
+       //@@todo we need a formatNum and we need to request some special packaged info to deal with that case. 
+       return  gM( msg , size );
+}
+
+//gets the loading image:
+function mv_get_loading_img( style , class_attr ){
+       var style_txt = (style)?style:'';
+       var class_attr = (class_attr)?'class="'+class_attr+'"':'class="mv_loading_img"';
+       return '<div '+class_attr+' style="' + style +'"></div>';
+}
+
+function mv_set_loading(target, load_id){
+       var id_attr = ( load_id )?' id="' + load_id + '" ':'';
+       $j(target).append('<div '+id_attr+' style="position:absolute;top:0px;left:0px;height:100%;width:100%;'+
+               'background-color:#FFF;">' +                     
+                       mv_get_loading_img('top:30px;left:30px') + 
+               '</div>');      
+}
+
+/**
+  * mvJsLoader class handles initialization and js file loads 
+  */
+var mvJsLoader = {
+        libreq : {},
+        libs : {},
+        //base lib flags:
+        onReadyEvents:new Array(),
+        doneReadyEvents:false,
+        jQueryCheckFlag:false,
+        //to keep consistency across threads: 
+        ptime:0,
+        ctime:0,        
+        load_error:false, //load error flag (false by default)
+        load_time:0,    
+        callbacks:new Array(),
+        cur_path: null,
+        missing_path : null,                           
+        doLoad:function(loadLibs, callback){            
+                this.ctime++;           
+                if( loadLibs && loadLibs.length!=0 ){ //setup this.libs:               
+                                                               
+                        //first check if we already have this lib loaded
+                        var all_libs_loaded=true;
+                        for(var i=0; i< loadLibs.length; i++){
+                                //check if the lib is already loaded: 
+                               if( ! this.checkObjPath( loadLibs[i] ) ){
+                                       all_libs_loaded=false;                                                  
+                               }               
+                        }
+                        if( all_libs_loaded ){
+                               js_log('all libs already loaded skipping... load req');
+                               callback();
+                               return ;
+                       }
+                       //do a check for any css we may need and get it:
+                       for(var i=0; i< loadLibs.length; i++){                          
+                               if( typeof mvCssPaths[ loadLibs[i] ] != 'undefined' ){
+                                       loadExternalCss(  mvCssPaths[ loadLibs[i] ]); 
+                               }
+                       }
+                                                                                                                
+                        //check if we should use the script loader to combine all the requests into one:                        
+                        if( typeof mwSlScript != 'undefined' ){
+                               var class_set = '';
+                                 var last_class = '';  
+                                 var coma = ''; 
+                                 for(var i=0; i< loadLibs.length; i++){
+                                         var curLib = loadLibs[i];
+                                         //only add if not included yet: 
+                                         if( ! this.checkObjPath( curLib ) ){
+                                                 class_set+=coma + curLib ;                              
+                                                 last_class=curLib;
+                                                 coma=',';
+                                         }
+                                 }      
+                                 var puri = parseUri( getMvEmbedURL() );       
+                                 if( (getMvEmbedURL().indexOf('://')!=-1) && puri.host != parseUri( document.URL).host){
+                                       mwSlScript =  puri.protocol + '://' + puri.authority + mwSlScript;
+                                 }
+                                 
+                                 var dbug_attr = (puri.queryKey['debug'])?'&debug=true':'';                                                      
+                                 this.libs[ last_class ] = mwSlScript + '?class=' + class_set +
+                                                                         '&urid=' + getMvUniqueReqId() + dbug_attr;
+                                                                                         
+                        }else{                                                                                                            
+                               //do many requests:
+                               for(var i=0; i< loadLibs.length; i++){
+                                    var curLib = loadLibs[i];
+                                    if(curLib){
+                                            var libLoc = mvGetClassPath(curLib);
+                                                // do a direct load of the file (pass along unique request id from request or mv_embed Version ) 
+                                                var qmark = (libLoc.indexOf('?')!==true)?'?':'&';
+                                                this.libs[curLib] =  mv_embed_path + libLoc + qmark + 'urid='+ getMvUniqueReqId();
+                                    } 
+                                }                                       
+                       }
+               }
+               if( callback ){ 
+                       this.callbacks.push(callback);
+               }               
+               if( this.checkLoading() ){
+                        if( this.load_time++ > 1000){ //time out after ~80seconds
+                                js_error( gM('error_load_lib') +  this.missing_path );
+                                this.load_error=true;
+                        }else{
+                               setTimeout( 'mvJsLoader.doLoad()', 20 );
+                        }
+               }else{
+                        //js_log('checkLoading passed run callbacks');
+                        //only do callback if we are in the same instance (weird concurency issue)                       
+                        var cb_count=0;
+                        for(var i=0; i < this.callbacks.length; i++)
+                                cb_count++;                             
+                        //js_log('REST LIBS: loading is: '+ loading + ' run callbacks: '+cb_count +' p:'+ this.ptime +' c:'+ this.ctime);
+                        //reset the libs
+                        this.libs={};                                                                                     
+                        //js_log('done loading do call: ' + this.callbacks[0] );                
+                        while( this.callbacks.length !=0 ){
+                                if( this.ptime== ( this.ctime-1) ){ //enforce thread consistency
+                                        this.callbacks.pop()();
+                                        //func = this.callbacks.pop();
+                                        //js_log(' run: '+this.ctime+ ' p: ' + this.ptime + ' ' +loading+ ' :'+ func);
+                                       //func();               
+                                }else{
+                                        //re-issue doLoad ( ptime will be set to ctime so we should catch up) 
+                                        setTimeout( 'mvJsLoader.doLoad()', 25 );
+                                        break;
+                                }
+                        }                       
+                }
+                this.ptime=this.ctime;         
+        },      
+        doLoadFullPaths:function(loadObj, callback){
+               
+        },
+        doLoadDepMode:function(loadChain, callback){
+               //firefox executes js ~in-order of it being included~ so just directly issue request:
+               if( $j.browser.firefox ){
+                       var loadSet = [];
+                       for(var i=0; i< loadChain.length;i++){
+                               for(var j=0;j<loadChain[i].length;j++){
+                                       loadSet.push(loadChain[i][j]);
+                               }
+                       }
+                       mvJsLoader.doLoad(loadSet, callback);
+               }else{
+                       //safari and IE tend to execute out of order so load with dependenciy checks
+                       mvJsLoader.doLoad(loadChain.shift(),function(){
+                               if(loadChain.length!=0){
+                                       mvJsLoader.doLoadDepMode(loadChain, callback);
+                               }else{
+                                       callback();
+                               }
+                       });      
+               }                },
+        checkLoading:function(){                 
+                 var loading=0;
+                var i=null;
+                for(var i in this.libs){ //for in loop oky on object                                                             
+                        if( !this.checkObjPath( i ) ){                          
+                                if(!this.libreq[i]){ 
+                                       loadExternalJs( this.libs[i] );
+                                }
+                                       
+                                this.libreq[i]=1;
+                                //js_log("has not yet loaded: " + i);
+                                loading=1;
+                        }
+                }               
+                return loading;
+       },
+       checkObjPath:function( libVar ){
+               if(!libVar)
+                       return false;
+               var objPath = libVar.split('.')
+               var cur_path ='';                
+               for(var p=0; p < objPath.length; p++){
+                        cur_path = (cur_path=='')?cur_path+objPath[p]:cur_path+'.'+objPath[p];
+                        eval( 'var ptest = typeof ( '+ cur_path + ' ); ');                              
+                        if( ptest == 'undefined'){                                                      
+                                 this.missing_path = cur_path;
+                                return false;
+                        }                       
+               }
+               this.cur_path = cur_path;
+               return true;
+       },
+       /**
+        * checks for jQuery and adds the $j noConflict var
+        */
+       jQueryCheck:function(callback){
+               //skip stuff if $j is already loaded:   
+               if(_global['$j'] && callback)
+                       callback();             
+               var _this = this;
+               //load jquery
+               _this.doLoad([
+                        'window.jQuery'                         
+               ],function(){
+                       _global['$j'] = jQuery.noConflict();
+                       //set up ajax to not send dynamic urls for loading scripts (we control that with the scriptLoader) 
+                       $j.ajaxSetup({            
+                                 cache: true
+                       });
+                       js_log('jquery loaded');
+                       //setup mvEmbed jquery bindigns:  
+                       mv_jqueryBindings();
+                       //run the callback                      
+                       if(callback){
+                               callback();
+                       }
+               });     
+       },
+       embedVideoCheck:function( callback ){
+               var _this = this;
+               js_log('embedVideoCheck:');
+               //issue a style sheet request get both mv_embed and jquery styles: 
+               loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css' );
+               loadExternalCss( mv_embed_path  + 'skins/'+mv_skin_name+'/styles.css');
+                                
+               //make sure we have jQuery
+               _this.jQueryCheck(function(){
+                       var depReq = [
+                               [
+                                       '$j.ui', 
+                                       'embedVideo',                                   
+                                       '$j.cookie'                                                                                                                                                             
+                               ], 
+                               [
+                                       '$j.ui.slider',                                 
+                               ]
+                       ];                              
+                       //add png fix if needed:
+                       if($j.browser.msie || $j.browser.version < 7)                                                           
+                               depReq[0].push( '$j.fn.pngFix' );
+                                                                               
+                       _this.doLoadDepMode(depReq,function(){                                                                                           
+                               embedTypes.init();                                                                              
+                               callback();     
+                       });
+               });
+       },      
+       addLoadEvent:function(fn){
+                this.onReadyEvents.push(fn);
+       },      
+       //checks the jQuery flag (this way when remote embeding we don't load jQuery 
+       // unless mwAddOnloadHook was used or there is video on the page
+       runQuededFunctions:function(){                  
+               var _this = this; 
+               this.doneReadyEvents=true;                      
+               if(this.jQueryCheckFlag){
+                       this.jQueryCheck(function(){                            
+                               _this.runReadyEvents();
+                       });
+               }else{   
+                       this.runReadyEvents();  
+               }
+       },
+       runReadyEvents:function(){
+               js_log("runReadyEvents");
+               while( this.onReadyEvents.length ){
+                       this.onReadyEvents.shift()();
+               }
+       }
+       
+}
+//load an external JS (similar to jquery .require plugin)
+//but checks for object availability rather than load state
+
+/*********** INITIALIZATION CODE *************
+ * this will get called when DOM is ready
+ *********************************************/
+/* jQuery .ready does not work when jQuery is loaded dynamically
+ * for an example of the problem see:1.1.3 working:http://pastie.caboo.se/92588
+ * and >= 1.1.4 not working: http://pastie.caboo.se/92595
+ * $j(document).ready( function(){ */
+function mwdomReady(force){
+       js_log('f:mwdomReady:');        
+       if( !force && mv_init_done  ){
+               js_log("mv_init_done already done do nothing...");
+               return false;
+       }
+       mv_init_done=true;                      
+       //handle the execution of Queded function with jQuery "ready"   
+       
+       //check if this page does have video or playlist
+       if(document.getElementsByTagName("video").length!=0 ||
+          document.getElementsByTagName("audio").length!=0 ||
+          document.getElementsByTagName("playlist").length!=0){
+               js_log('we have things to rewrite');                                    
+               //load libs and proccess:                                        
+               mvJsLoader.embedVideoCheck(function(){
+                       //run any queded global events:
+                       mv_video_embed( function(){             
+                               mvJsLoader.runQuededFunctions();
+                       });                                     
+               });             
+       }else{
+               //if we already have jQuery make sure its loaded into its proper context $j             
+               //run any queded global events:                 
+               mvJsLoader.runQuededFunctions();                                
+       }
+}
+//mwAddOnloadHook: ensure jQuery and the DOM are ready:  
+function mwAddOnloadHook( func ) {                              
+       //make sure the skin/style sheets are avaliable always: 
+       loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css' );
+       loadExternalCss( mv_embed_path  + 'skins/'+mv_skin_name+'/styles.css');
+                                
+       //if we have already run the dom ready just run the function directly: 
+       if( mvJsLoader.doneReadyEvents ){
+               //make sure jQuery is there: 
+               mvJsLoader.jQueryCheck(function(){
+                       func();
+               });     
+       }else{
+               //if using mwAddOnloadHook we need to get jQuery into place (if its not already included)
+               mvJsLoader.jQueryCheckFlag = true;
+               mvJsLoader.addLoadEvent( func );
+       };              
+}
+/*
+ * this function allows for targeted rewriting 
+ */
+function rewrite_by_id( vid_id, ready_callback ){
+       js_log('f:rewrite_by_id: ' + vid_id);   
+       //force a recheck of the dom for playlist or video element:      
+       mvJsLoader.embedVideoCheck(function(){
+                mv_video_embed(ready_callback, vid_id ); 
+       });
+}
+//depricated in favor of updates to oggHanlder
+function rewrite_for_oggHanlder( vidIdList ){          
+       for(var i = 0; i < vidIdList.length ; i++){             
+               var vidId = vidIdList[i];
+               js_log('looking at vid: ' + i +' ' + vidId);            
+               //grab the thumbnail and src video
+               var pimg = $j('#'+vidId + ' img');
+               var poster_attr = 'poster = "' + pimg.attr('src') + '" ';
+               var pwidth = pimg.attr('width');
+               var pheight = pimg.attr('height');                              
+               
+               var type_attr = '';
+               //check for audio
+               if( pwidth=='22' && pheight=='22'){             
+                       pwidth='400';
+                       pheight='300';
+                       type_attr = 'type="audio/ogg"';
+                       poster_attr = '';
+               }
+               
+               //parsed values:                 
+               var src = '';
+               var duration = ''; 
+               
+               var re = new RegExp( /videoUrl(&quot;:?\s*)*([^&]*)/ );
+               src  = re.exec( $j('#'+vidId).html() )[2];
+               
+               var re = new RegExp( /length(&quot;:?\s*)*([^&]*)/ );
+               duration = re.exec( $j('#'+vidId).html() )[2];
+               
+               var re = new RegExp( /offset(&quot;:?\s*)*([^&]*)/ );
+               offset = re.exec( $j('#'+vidId).html() )[2];            
+               var offset_attr = (offset)? 'startOffset="'+ offset + '"': '';
+               
+               if( src ){
+                       //replace the top div with mv_embed based player: 
+                       var vid_html = '<video id="vid_' + i +'" '+ 
+                                        'src="' + src + '" ' +
+                                        poster_attr + ' ' + 
+                                        type_attr + ' ' + 
+                                        offset_attr + ' ' + 
+                                        'duration="' + duration + '" ' + 
+                                        'style="width:' + pwidth + 'px;height:' + 
+                                                pheight + 'px;"></video>';
+                       //js_log("video html: " + vid_html);                    
+                        $j('#'+vidId).html( vid_html );
+               }               
+               
+               //rewrite that video id: 
+               rewrite_by_id('vid_' + i);
+       }
+}
+
+
+/*********** INITIALIZATION CODE *************
+ * set DOM ready callback to init_mv_embed
+ *********************************************/
+// for Mozilla browsers
+if (document.addEventListener ) {
+       document.addEventListener("DOMContentLoaded", function(){mwdomReady()}, false);
+}else{ 
+       //backup "onload" method in case on DOMContentLoaded does not exist
+       window.onload = function(){ mwdomReady() };
+}
+/*
+ * should depreciate and use jquery.ui.dialog instead
+ */
+function mv_write_modal(content, speed){
+       $j('#modalbox,#mv_overlay').remove();
+       $j('body').append('<div id="modalbox" style="background:#DDD;border:3px solid #666666;font-size:115%;'+
+                               'top:30px;left:20px;right:20px;bottom:30px;position:fixed;z-index:100;">'+                      
+                               content +                       
+                       '</div>'+               
+                       '<div id="mv_overlay" style="background:#000;cursor:wait;height:100%;left:0;position:fixed;'+
+                               'top:0;width:100%;z-index:5;filter:alpha(opacity=60);-moz-opacity: 0.6;'+
+                               'opacity: 0.6;"/>');
+       $j('#modalbox,#mv_overlay').show( speed );      
+}
+function mv_remove_modal(speed){
+       $j('#modalbox,#mv_overlay').remove( speed);
+}
+
+/*
+ * stores all the mwEmbed jQuery specific bindings 
+ * (setup after jQuery is avaliable)
+ * lets you call rewrites in a jquery "way"
+ *  
+ * @@ eventually we should refactor mwCode over to jQuery style plugins
+ *       and mv_embed.js will just hanndle dependency mapping and loading. 
+ *       
+ */  
+function mv_jqueryBindings(){
+       js_log('mv_jqueryBindings');    
+       (function($) {
+               
+               $.fn.addMediaWiz = function( iObj, callback ){                  
+                       //first set the cursor for the button to "loading" 
+                       $j(this.selector).css('cursor','wait').attr('title', gM('loading_title'));
+                                                                       
+                       iObj['target_invocation'] = this.selector;
+                       
+                       //load the mv_embed_base skin:                                                                                   
+                       loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css' );                  
+                       loadExternalCss( mv_embed_path  + 'skins/'+mv_skin_name+'/styles.css' );                                                                                                                                                                                                
+                       //load all the req libs: 
+                       mvJsLoader.jQueryCheck(function(){                              
+                               //load with staged dependeinces (for ie and safari that don't execute in order) 
+                               mvJsLoader.doLoadDepMode([
+                                       [       'remoteSearchDriver',
+                                               '$j.cookie',
+                                               '$j.ui'
+                                       ],[             
+                                               '$j.ui.resizable',
+                                               '$j.ui.draggable',
+                                               '$j.ui.dialog',
+                                               '$j.ui.tabs',
+                                               '$j.ui.sortable'
+                                       ]
+                               ], function(){
+                                       iObj['instance_name']= 'rsdMVRS';
+                                       _global['rsdMVRS'] = new remoteSearchDriver( iObj );       
+                                       if( callback ){
+                                          callback( _global['rsdMVRS'] );
+                                       }
+                               });                     
+                       });
+               }
+               $.fn.sequencer = function( iObj, callback){
+                       //debugger;
+                       iObj['target_sequence_container'] = this.selector;
+               //issue a request to get the css file (if not already included):        
+               loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css');
+               loadExternalCss( mv_embed_path+'skins/'+mv_skin_name+'/mv_sequence.css');       
+               //make sure we have the required mv_embed libs (they are not loaded when no video element is on the page)       
+               mvJsLoader.embedVideoCheck(function(){                                          
+                       //load playlist object and then jquery ui stuff:
+                       mvJsLoader.doLoadDepMode([
+                               [
+                                       'mvPlayList',
+                                       '$j.ui',  
+                                       '$j.contextMenu',
+                                       '$j.secureEvalJSON',
+                                       'mvSequencer'           
+                               ],
+                               [
+                                       '$j.ui.accordion',
+                                       '$j.ui.dialog',
+                                       '$j.ui.droppable',
+                                       '$j.ui.draggable',    
+                                       '$j.ui.progressbar',                                    
+                                       '$j.ui.sortable',
+                                       '$j.ui.resizable',
+                                       '$j.ui.slider',                                 
+                                       '$j.ui.tabs'
+                               ]
+                       ], function(){                                                  
+                               js_log('calling new mvSequencer');                                              
+                               //init the sequence object (it will take over from there) no more than one mvSeq obj for now: 
+                               if(!_global['mvSeq']){
+                                       _global['mvSeq'] = new mvSequencer(iObj);
+                               }else{
+                                       js_log('mvSeq already init');
+                               }
+                       });
+               });
+               }
+               /*
+                * the firefogg jquery function:
+                * @@note this firefogg envocation could be made to work more like real jquery plugins
+                */                      
+               $.fn.firefogg = function( iObj, callback ) {
+                       if(!iObj)
+                               iObj={};
+                       //add base theme css:
+                       loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css');
+                       loadExternalCss( mv_embed_path  + 'skins/'+mv_skin_name+'/styles.css' );
+                                               
+                       //check if we already have firefogg loaded (the call just updates properties for that element) 
+                       var sElm = $j(this.selector).get(0);                                                                    
+                       if(sElm['firefogg']){                           
+                               if(sElm['firefogg']=='loading'){
+                                       js_log("Error: called firefogg operations on Firefogg selector that is not done loading");
+                                       return false;
+                               }
+                               //update properties: 
+                               for(var i in iObj){
+                                       js_log("firefogg::updated: "+ i + ' to '+ iObj[i]);
+                                       sElm['firefogg'][i] = iObj[i];
+                               }
+                               return sElm['firefogg'];
+                       }else{
+                               //avoid concurency
+                               sElm['firefogg'] = 'loading';
+                       }
+                       //add the selector: 
+                       iObj['selector'] = this.selector;
+                                       
+                       var loadSet = [
+                               [                               
+                                       'mvBaseUploadInterface',
+                                       'mvFirefogg',
+                                       '$j.ui'                                                                         
+                               ],
+                               [
+                                       '$j.ui.progressbar',
+                                       '$j.ui.dialog'
+                               ]
+                       ];      
+                       if( iObj.encoder_interface ){
+                               loadSet.push([
+                                       'mvAdvFirefogg',
+                                       '$j.cookie',                      
+                                       '$j.ui.accordion',
+                                       '$j.ui.slider',    
+                                       '$j.ui.datepicker'
+                               ]);
+                       }               
+                       //make sure we have everything loaded that we need: 
+                       mvJsLoader.doLoadDepMode( loadSet, function(){                                                                          
+                                       js_log('firefogg libs loaded. target select:' + iObj.selector);
+                                       //select interface provicer based on if we want to include the encoder interface or not: 
+                                       if(iObj.encoder_interface){
+                                               var myFogg = new mvAdvFirefogg( iObj );
+                                       }else{
+                                               var myFogg = new mvFirefogg( iObj );
+                                       }                                                          
+                                       if(myFogg){
+                                               myFogg.doRewrite( callback );
+                                               var selectorElement = $j( iObj.selector ).get(0);       
+                                               selectorElement['firefogg']=myFogg;
+                                       }
+                       });             
+               }
+               
+               $.fn.baseUploadInterface = function(iObj){
+                       mvJsLoader.doLoad([
+                                 'mvBaseUploadInterface',
+                                 '$j.ui',
+                                 '$j.ui.progressbar',
+                                 '$j.ui.dialog'        
+                       ],function(){                           
+                               myUp = new mvBaseUploadInterface( iObj );
+                               myUp.setupForm();
+                       });
+               }                               
+                               
+               //shortcut to a themed button:
+               $.btnHtml = function(msg, className, iconId, opt){
+                  if(!opt)
+                     opt = {};
+                  var href = (opt.href)?opt.href:'#';
+                  var target_attr = (opt.target)?' target="' + opt.target + '" ':''; 
+                  var style_attr = (opt.style)?' style="'+opt.style +'" ':'';    
+                  return '<a href="' + href + '" ' + target_attr + style_attr +' class="ui-state-default ui-corner-all ui-icon_link ' +
+                                  className + '"><span class="ui-icon ui-icon-' + iconId + '" />' + 
+                                  msg + '</a>';                                                  
+               }                  
+               //shortcut to bind hover state:         
+               $.fn.btnBind = function(){                      
+                       $j(this).hover(
+                               function(){
+                                       $j(this).addClass('ui-state-hover');
+                               },
+                               function(){
+                                       $j(this).removeClass('ui-state-hover');
+                               }
+                       )
+                       return this;
+               }
+               
+       })(jQuery);
+}  
+/*
+* utility functions:
+*/
+//simple url re-writer for rewriting urls (could probably be refactored into an inline regular expresion) 
+function getURLParamReplace( url, opt ){       
+       var pSrc = parseUri( url );     
+       if(pSrc.protocol != '' ){
+               var new_url = pSrc.protocol +'://'+ pSrc.authority + pSrc.path +'?';                               
+       }else{
+               var new_url = pSrc.path +'?';     
+       }       
+       var amp = '';
+       for(var key in pSrc.queryKey){
+               var val = pSrc.queryKey[ key ];
+               //do override if requested 
+               if( opt[ key ] )
+                       val = opt[ key ];
+               new_url+= amp + key + '=' + val;                                        
+               amp = '&';              
+       };      
+       //add any vars that did were not originally there: 
+       for(var i in opt){
+               if(!pSrc.queryKey[i]){
+                 new_url+=amp + i + '=' + opt[i];
+                 amp = '&'; 
+               }
+       }                
+       return new_url;
+}
+/**
+ * seconds2npt given a float seconds returns npt format response:
+ * @param float seconds
+ * @param boolean if we should show ms or not. 
+ */
+function seconds2npt(sec, show_ms){
+       if( isNaN( sec ) ){
+               js_log("warning: trying to get npt time on NaN:" + sec);
+               return '0:0:0';
+       }               
+       var hours = Math.floor(sec/ 3600);
+       var minutes = Math.floor((sec/60) % 60);        
+       var seconds = sec % 60;
+       //round the second amount requested significant digits
+       if(show_ms){
+               seconds = Math.round( seconds * 1000 ) / 1000;
+       }else{
+               seconds = Math.round( seconds );
+       }
+       if(seconds <10 )
+               seconds = '0'+  seconds;
+       if(minutes < 10 )
+               minutes = '0' + minutes;        
+       
+       return hours+":"+minutes+":"+seconds;
+}
+/* 
+ * takes hh:mm:ss,ms or  hh:mm:ss.ms input returns number of seconds 
+ */
+function npt2seconds( npt_str ){
+       if(!npt_str){           
+               //js_log('npt2seconds:not valid ntp:'+ntp);
+               return false;
+       }
+       //strip npt: time definition if present
+       npt_str = npt_str.replace('npt:', ''); 
+       
+       times = npt_str.split(':');
+       if(times.length!=3){            
+               js_log('error: npt2seconds on ' + npt_str);                     
+               return false;
+       }
+       //sometimes the comma is used inplace of pereid for ms
+       times[2] = times[2].replace(/,\s?/,'.');
+       //return seconds float (ie take seconds float value if present):
+       return parseInt(times[0]*3600)+parseInt(times[1]*60)+parseFloat(times[2]);
+}
+
+//does a remote or local api request based on request url 
+//@param options: url, data, cbParam, callback
+function do_api_req( options, callback ){              
+       if(typeof options.data != 'object'){            
+               return js_error('Error: request paramaters must be an object');;
+       }
+       //gennerate the url if its missing:
+       if( typeof options.url == 'undefined' ){
+               if(!wgServer || ! wgScriptPath){                        
+                       return js_error('Error: no api url for api request');;
+               }               
+               if (wgServer && wgScript)
+                       options.url = wgServer + wgScript;
+               //update to api.php (if index.php was in the wgScript path): 
+                options.url =  options.url.replace(/index.php/, 'api.php');            
+       }                       
+       if( typeof options.data == 'undefined' )
+               options.data = {};      
+       
+       //force format to json (if not already set)               
+       options.data['format'] = 'json';
+       
+       //if action not set assume query
+       if(!options.data['action'])
+               options.data['action']='query';
+       
+       js_log('do api req: ' + options.url +'?' +  jQuery.param(options.data) );                       
+       //build request string:                  
+       if( parseUri( document.URL ).host == parseUri( options.url ).host ){
+               //local request do api request directly         
+               $j.ajax({
+                       type: "POST",
+                       url: options.url,
+                       data: options.data,
+                       dataType:'json', //api requests _should_ always return JSON data: 
+                       async: false,
+                       success:function(data){                                         
+                               callback(  data );
+                       },
+                       error:function(e){
+                               js_error( ' error' + e +' in getting: ' + options.url); 
+                       }
+               });
+       }else{                  
+               //set the callback param if not already set: 
+               if( typeof options.jsonCB == 'undefined')
+                       options.jsonCB = 'callback';
+                                               
+               var req_url = options.url;              
+               var paramAnd = (req_url.indexOf('?')==-1)?'?':'&';              
+               //put all the values into the GET req:   
+               for(var i in options.data){
+                       req_url += paramAnd + encodeURIComponent( i ) + '=' + encodeURIComponent( options.data[i] );            
+                       paramAnd ='&';
+               }
+               var fname = 'mycpfn_' + ( global_cb_count++ );
+               _global[ fname ]  =  callback;                          
+               req_url += '&' + options.jsonCB + '=' + fname;                                                          
+               loadExternalJs( req_url );                              
+       }       
+}
+//grab wiki form error for wiki html page proccessing (should be depricated)
+function grabWikiFormError ( result_page ){
+               var res = {};
+               sp = result_page.indexOf('<span class="error">');
+               if(sp!=-1){
+                       se = result_page.indexOf('</span>', sp);
+                       res.error_txt = result_page.substr(sp, (sp-se)) + '</span>';
+               }else{
+                       //look for warning: 
+                       sp = result_page.indexOf('<ul class="warning">')
+                       if(sp != -1){
+                               se = result_page.indexOf('</ul>', sp);
+                               res.error_txt = result_page.substr(sp, (se-sp)) + '</ul>';
+                               //try and add the ignore form item: 
+                               sfp = result_page.indexOf('<form method="post"');
+                               if(sfp!=-1){
+                                       sfe = result_page.indexOf('</form>', sfp);
+                                       res.form_txt = result_page.substr(sfp, ( sfe - sfp )) + '</form>';
+                               }
+                       }else{
+                               //one more error type check: 
+                               sp = result_page.indexOf('class="mw-warning-with-logexcerpt">')
+                               if(sp!=-1){
+                                       se = result_page.indexOf('</div>', sp);
+                                       res.error_txt = result_page.substr(sp, ( se - sp )) + '</div>';
+                               }
+                       }
+               }       
+               return res;             
+}
+//do a "normal" request 
+function do_request(req_url, callback){                
+       js_log('do_request::req_url:' + req_url + ' != ' +  parseUri( req_url).host);    
+       //if we are doing a request to the same domain or relative link do a normal GET: 
+       if( parseUri(document.URL).host == parseUri(req_url).host ||
+               req_url.indexOf('://') == -1 ){ //relative url
+               //do a direct request:
+               $j.ajax({
+                       type: "GET",
+                       url:req_url,
+                          async: false,
+                       success:function(data){         
+                               callback( data );
+                       }
+               });
+       }else{                                          
+               //get data via DOM injection with callback
+               global_req_cb.push(callback);
+               //prepend json_ to feed_format if not already requesting json format
+               if( req_url.indexOf("feed_format=")!=-1 &&  req_url.indexOf("feed_format=json")==-1)
+                       req_url = req_url.replace(/feed_format=/, 'feed_format=json_');                                                                                                 
+               loadExternalJs(req_url+'&cb=mv_jsdata_cb&cb_inx='+(global_req_cb.length-1));                    
+       }
+}
+
+function mv_jsdata_cb(response){
+       js_log('f:mv_jsdata_cb:'+ response['cb_inx']);
+       //run the callback from the global req cb object:
+       if( !global_req_cb[response['cb_inx']] ){
+               js_log('missing req cb index');
+               return false;
+       }
+       if( !response['pay_load'] ){
+               js_log("missing pay load");
+               return false;
+       }
+       //switch on content type:
+       switch(response['content-type']){
+               case 'text/plain':
+               break;
+               case 'text/xml':
+                       if(typeof response['pay_load'] == 'string'){
+                               //js_log('load string:'+"\n"+ response['pay_load']);
+                               //debugger;
+                               //attempt to parse as xml for IE
+                               if( $j.browser.msie ){
+                                       var xmldata=new ActiveXObject("Microsoft.XMLDOM");
+                                       xmldata.async="false";
+                                       xmldata.loadXML(response['pay_load']);
+                               }else{ //for others (firefox, safari etc)       
+                                       try{
+                                               var xmldata = (new DOMParser()).parseFromString(response['pay_load'], "text/xml");              
+                                       }catch(e) {
+                                                         js_log('XML parse ERROR: ' + e.message);
+                                         }                                       
+                               }
+                               //@@todo hanndle xml parser errors
+                               if(xmldata)response['pay_load']=xmldata;
+                       }
+               break
+               default:
+                       js_log('bad response type' + response['content-type']);
+                       return false;
+               break;
+       }
+       global_req_cb[response['cb_inx']]( response['pay_load'] );
+}
+//load external js via dom injection
+function loadExternalJs( url ){
+         js_log('load js: '+ url);
+       //if(window['$j']) //use jquery call:   
+          /*$j.ajax({
+                       type: "GET",
+                       url: url,
+                       dataType: 'script',
+                       cache: true
+               });*/
+  //  else{
+               var e = document.createElement("script");
+               e.setAttribute('src', url);
+               e.setAttribute('type',"text/javascript");
+               //e.setAttribute('defer', true);
+               document.getElementsByTagName("head")[0].appendChild(e);
+   // }
+}
+
+function styleSheetPresent(url){
+       style_elements = document.getElementsByTagName('link');
+       if( style_elements.length > 0) {
+               for(i = 0; i < style_elements.length; i++) {
+                       if(style_elements[i].href == url)
+                               return true;
+               }
+       }
+       return false;
+}
+function loadExternalCss(url){
+       //if could have script loader group thes css request 
+       //but debatable it may hurt more than it helps with caching and all
+       if(typeof url =='object'){
+               for(var i in url){                      
+                       loadExternalCss ( url[i] );
+               }
+               return ;
+       }
+       
+       if( url.indexOf('?') == -1 ){
+               url+='?'+getMvUniqueReqId();
+       }
+       if(!styleSheetPresent(url) ){           
+          js_log('load css: ' + url);
+          var e = document.createElement("link");
+          e.href = url;
+          e.type = "text/css";
+          e.rel = 'stylesheet';
+          document.getElementsByTagName("head")[0].appendChild(e);
+       }
+}
+function getMvEmbedURL(){      
+       if( _global['mv_embed_url'] ) 
+               return _global['mv_embed_url'];                         
+       var js_elements = document.getElementsByTagName("script");                      
+       for(var i=0; i < js_elements.length; i++){                                      
+               //check for normal mv_embed.js and or script loader
+               var src = js_elements[i].getAttribute("src");           
+               if( src ){                      
+                       if( src.indexOf('mv_embed.js') !=-1 || (  
+                               ( src.indexOf('mwScriptLoader.php') != -1 || src.indexOf('jsScriptLoader.php') != -1 )
+                                       && src.indexOf('mv_embed') != -1) ){ //(check for class=mv_embed script_loader call)                                                                                            
+                               _global['mv_embed_url'] = src;
+                               return  src;            
+                       }
+               }
+       }
+       js_error('Error: getMvEmbedURL failed to get Embed Path');
+       return false;
+}
+//gets a unique request id to ensure fresh javascript 
+function getMvUniqueReqId(){
+       if( _global['urid'] ) 
+               return _global['urid'];         
+       var mv_embed_url = getMvEmbedURL();             
+       //if we have a uri retun that: 
+       var urid = parseUri( mv_embed_url).queryKey['urid']
+       if( urid ){
+               _global['urid'] = urid;
+               return urid;
+       }
+       //if in debug mode get a fresh unique request key: 
+       if(  parseUri( mv_embed_url ).queryKey['debug'] == 'true'){
+               var d = new Date();
+               var urid = d.getTime();
+               _global['urid'] = urid;
+               return urid;
+       }
+       //else just return the mv_embed version;
+       return MV_EMBED_VERSION;
+}
+/*
+ * sets the global mv_embed path based on the scripts location
+ */
+function getMvEmbedPath(){             
+       var mv_embed_url = getMvEmbedURL();                             
+       if( mv_embed_url.indexOf('mv_embed.js') !== -1 ){
+               mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('mv_embed.js'));
+       }else if(mv_embed_url.indexOf('mwScriptLoader.php')!==-1){
+               //script load is in the root of mediaWiki so include the default mv_embed extention path (if using the script loader)
+               mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('mwScriptLoader.php'))  + mediaWiki_mvEmbed_path ;
+       }else{
+               mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('jsScriptLoader.php'));
+       }               
+       //absolute the url (if relative) (if we don't have mv_embed path)
+       if( mv_embed_path.indexOf('://') == -1){        
+               var pURL = parseUri( document.URL );
+               if(mv_embed_path.charAt(0)=='/'){
+                       mv_embed_path = pURL.protocol + '://' + pURL.authority + mv_embed_path;
+               }else{
+                       //relative:
+                       if(mv_embed_path==''){
+                               mv_embed_path = pURL.protocol + '://' + pURL.authority + pURL.directory + mv_embed_path;
+                       }
+               }               
+       }       
+       return mv_embed_path;
+}
+
+if (typeof DOMParser == "undefined") {
+   DOMParser = function () {}
+   DOMParser.prototype.parseFromString = function (str, contentType) {
+         if (typeof ActiveXObject != "undefined") {
+                var d = new ActiveXObject("MSXML.DomDocument");
+                d.loadXML(str);
+                return d;
+         } else if (typeof XMLHttpRequest != "undefined") {
+                var req = new XMLHttpRequest;
+                req.open("GET", "data:" + (contentType || "application/xml") +
+                                                ";charset=utf-8," + encodeURIComponent(str), false);
+                if (req.overrideMimeType) {
+                       req.overrideMimeType(contentType);
+                }
+                req.send(null);
+                return req.responseXML;
+         }
+   }
+}
+/*
+* utility functions:
+*/
+function js_log(string){
+  if( window.console ){
+          window.console.log(string);          
+  }else{
+        /*
+         * IE and non-firebug debug:
+         */
+        /*var log_elm = document.getElementById('mv_js_log');
+        if(!log_elm){
+                document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML + 
+                                        '<div style="position:absolute;z-index:500;top:0px;left:0px;right:0px;height:10px;">'+
+                                                '<textarea id="mv_js_log" cols="120" rows="5"></textarea>'+
+                                        '</div>';
+                                 
+                var log_elm = document.getElementById('mv_js_log');
+        }       
+        if(log_elm){
+                log_elm.value+=string+"\n";
+        }*/
+  }
+  return false;
+}
+
+function js_error(string){
+       alert(string);
+       return false;
+}
diff --git a/js2/mwEmbed/php/cortado_iframe.php b/js2/mwEmbed/php/cortado_iframe.php
new file mode 100644 (file)
index 0000000..2b65b30
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+/*
+cortado_embed.php
+all file checks and conditions should be checked prior to loading this page.
+this page serves as a wrapper for the cortado java applet
+
+@@this may be depreciated in favor of a central hosted java applet
+*/
+
+cortado_iframe();
+
+function cortado_iframe() {
+       if(!function_exists('filter_input')){
+               die('your version of php lacks <b>filter_input()</b> function</br>');
+       }
+       //load the http GETS:
+       // set the parent domain if provided
+       $parent_domain = isset( $_GET['parent_domain'] ) ? $_GET['parent_domain'] : false;
+
+       //default to null media in not provided:
+       $media_url = isset( $_GET['media_url'] ) ? $_GET['media_url'] : false;
+       if( strval($media_url) === ''){
+               error_out('not valid or missing media url');
+       }
+       //default duration to 30 seconds if not provided. (ideally cortado would read this from the video file)
+       //$duration = (isset($_GET['duration']))?$_GET['duration']:0;
+       $duration = filter_input(INPUT_GET, 'duration', FILTER_SANITIZE_NUMBER_INT);
+       if( is_null($duration) || $duration===false){
+               $duration=0;
+       }
+
+       //id (set to random if none provided)
+       //$id = (isset($_GET['id']))?$_GET['id']:'vid_'.rand('10000000');
+       $id = isset($_GET['id']) ? $_GET['id'] : false;
+       if( is_null($id) || $id===false){
+               $id = 'vid_'.rand(0,10000000);
+       }
+
+       $width = filter_input(INPUT_GET, 'width', FILTER_SANITIZE_NUMBER_INT);
+       if( is_null($width) || $width===false){
+               $width=320;
+       }
+       $height = filter_input(INPUT_GET, 'height', FILTER_SANITIZE_NUMBER_INT);
+       //default to video:
+       $stream_type = (isset($_GET['stream_type']))?$_GET['stream_type']:'video';
+       if($stream_type=='video'){
+               $audio=$video='true';   
+               if(is_null($height) || $height===false)
+                       $height = 240;
+       } else { // if($stream_type=='audio')
+               $audio='true';
+               $video='false';
+               if(is_null($height) || $height===false)
+                       $height = 20;   
+       }
+
+       //everything good output page: 
+       output_page(array(
+               'id' => $id,
+               'media_url' => $media_url,
+               'audio' => $audio,
+               'video' => $video,
+               'duration' => $duration,
+               'width' => $width,
+               'height' => $height,
+               'parent_domain' => $parent_domain
+       ));
+}
+
+/**
+ * JS escape function copied from MediaWiki's Xml::escapeJsString()
+ */
+function escapeJsString( $string ) {
+       // See ECMA 262 section 7.8.4 for string literal format
+       $pairs = array(
+               "\\" => "\\\\",
+               "\"" => "\\\"",
+               '\'' => '\\\'',
+               "\n" => "\\n",
+               "\r" => "\\r",
+
+               # To avoid closing the element or CDATA section
+               "<" => "\\x3c",
+               ">" => "\\x3e",
+
+               # To avoid any complaints about bad entity refs
+               "&" => "\\x26",
+
+               # Work around https://bugzilla.mozilla.org/show_bug.cgi?id=274152
+               # Encode certain Unicode formatting chars so affected
+               # versions of Gecko don't misinterpret our strings;
+               # this is a common problem with Farsi text.
+               "\xe2\x80\x8c" => "\\u200c", // ZERO WIDTH NON-JOINER
+               "\xe2\x80\x8d" => "\\u200d", // ZERO WIDTH JOINER
+       );
+       return strtr( $string, $pairs );
+}
+
+function error_out($error=''){
+       output_page(array('error' => $error));
+       exit();
+}
+function output_page($params){
+       extract( $params );
+?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+       <html xmlns="http://www.w3.org/1999/xhtml">
+       <head>
+       <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+       <title>cortado_embed</title>    
+       <script type="text/javascript">
+               <? //set the parent domain: 
+                       if( $parent_domain ){?>
+                       try{
+                               document.domain = '<?php echo  htmlspecialchars( $parent_domain )?>';
+                       }catch (e){
+                               if( window.console )
+                                       console.log('could not set domain to <?php echo  htmlspecialchars( $parent_domain )?>');
+                       }
+               <?
+                } ?>   
+                var jPlayer = null;
+                function setGlobalJplayer(){
+                       jPlayer = document.getElementById('<?php echo  htmlspecialchars( $id ) ?>');
+                }                                                      
+       </script>
+       <style type="text/css">
+       <!--
+       body {
+               margin-left: 0px;
+               margin-top: 0px;
+               margin-right: 0px;
+               margin-bottom: 0px;
+       }
+       -->
+       </style></head>
+       <body onload="setGlobalJplayer()" >
+       <?php 
+               $appid = ( preg_match("/MSIE/i", getenv("HTTP_USER_AGENT")) ) ? '' : 'classid="java:com.fluendo.player.Cortado.class"';
+               if (empty($error)){ ?>
+                       <div id="jPlayer"></div>                        
+                       <OBJECT id="<?php echo  htmlspecialchars( $id ) ?>" 
+                 code="com.fluendo.player.Cortado.class" 
+                 <?php echo $appid ?>
+                 archive="binPlayers/cortado/cortado-wmf-r46643.jar" 
+                 width="<?php echo  htmlspecialchars( $width )?>" 
+                 height="<?php echo htmlspecialchars( $height )?>" >
+                       <param name="url" value="<?php echo  htmlspecialchars( $media_url )?>" />
+                       <param name="local" value="false"/>
+                       <param name="keepaspect" value="true" />
+                       <param name="video" value="<?php echo  htmlspecialchars( $video )?>" />
+                       <param name="audio" value="<?php echo  htmlspecialchars( $audio )?>" />
+                       <param name="seekable" value="false" />
+                       <? if($duration!=0){
+                               ?>
+                               <param name="duration" value="<?php echo  htmlspecialchars( $duration )?>" />
+                               <?
+                        } ?>
+                       <param name="showStatus" value="hide" />
+                       <param name="autoPlay" value="true" />
+                       <param name="BufferSize" value="8192" />
+                       <param name="BufferHigh" value="30" />
+                       <param name="BufferLow" value="5" />
+       </OBJECT>
+       <? }else{ ?>
+               <b>Error:</b> <?php echo  htmlspecialchars( $error )?>  
+       <?
+       }
+       ?>
+       </body>
+       </html>
+<?
+}
+/* 
+javascript envoked version:
+       function doPlayer(){
+                       jPlayer = document.createElement('OBJECT');
+                       jPlayer.setAttribute('classid', 'java:com.fluendo.player.Cortado.class');
+                       jPlayer.type = 'application/x-java-applet';
+                       jPlayer.setAttribute('archive', this.CortadoLocation);
+                       jPlayer.id = '<?php echo  htmlspecialchars( $id ) ?>';
+                       jPlayer.width = '<?php echo  htmlspecialchars( $width )?>';
+                       jPlayer.height = '<?php echo  htmlspecialchars( $height )?>';
+               
+                       var params = {
+                         'code': 'com.fluendo.player.Cortado',
+                         'archive': 'cortado-wmf-r46643.jar',
+                         'url': '<?php echo  htmlspecialchars( $media_url )?>',
+                         'local': 'false',
+                         'keepAspect': 'true',
+                         'video': '<?php echo  htmlspecialchars( $video )?>',
+                         'audio': '<?php echo  htmlspecialchars( $audio )?>',
+                         'seekable': 'false',
+                         'showStatus': 'hide',
+                         'autoPlay': 'true',
+                         'bufferSize': '8192',
+                         'BufferHigh':'30',
+                         'BufferLow' : '5',
+                                <? if($duration!=0){
+                                       ?>
+                                       'duration':'<?php echo  htmlspecialchars( $duration )?>',
+                                       <?
+                                } ?>
+                         'debug': 0
+                       }
+                       for(name in params){
+                         var p = document.createElement('param');
+                         p.name = name;
+                         p.value = params[name];
+                         jPlayer.appendChild(p);
+                       }
+                       var pHolder = document.getElementById('jPlayer');
+                       if(pHolder)
+                               pHolder.appendChild( jPlayer );
+               }
+               doPlayer();             
+//then in the page: 
+<script type="text/javascript">
+                               doPlayer();
+                       </script>
+ * 
+*/
+?>
diff --git a/js2/mwEmbed/php/jsAutoloadLocalClasses.php b/js2/mwEmbed/php/jsAutoloadLocalClasses.php
new file mode 100644 (file)
index 0000000..6dd150d
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+if ( !defined( 'MEDIAWIKI' ) ) die(1);
+
+global $wgJSAutoloadLocalClasses, $wgMwEmbedDirectory;
+
+       //the basis of the loader calls:
+       $wgJSAutoloadLocalClasses['mv_embed']                   = $wgMwEmbedDirectory . 'mv_embed.js';
+
+       //core:
+       $wgJSAutoloadLocalClasses['window.jQuery']              = $wgMwEmbedDirectory . 'jquery/jquery-1.3.2.js';
+
+       $wgJSAutoloadLocalClasses['j.secureEvalJSON']   = $wgMwEmbedDirectory . 'jquery/plugins/jquery.json-1.3.js';
+
+       $wgJSAutoloadLocalClasses['j.cookie']                   = $wgMwEmbedDirectory . 'jquery/plugins/jquery.cookie.js';
+
+       $wgJSAutoloadLocalClasses['j.contextMenu']              = $wgMwEmbedDirectory . 'jquery/plugins/jquery.contextMenu.js';
+       $wgJSAutoloadLocalClasses['j.fn.pngFix']                = $wgMwEmbedDirectory . 'jquery/plugins/jquery.pngFix.js';
+
+       $wgJSAutoloadLocalClasses['j.fn.autocomplete']  = $wgMwEmbedDirectory . 'jquery/plugins/jquery.autocomplete.js';
+       $wgJSAutoloadLocalClasses['j.fn.hoverIntent']   = $wgMwEmbedDirectory . 'jquery/plugins/jquery.hoverIntent.js';
+       $wgJSAutoloadLocalClasses['Date.fromString']    = $wgMwEmbedDirectory . 'jquery/plugins/date.js';
+       $wgJSAutoloadLocalClasses['j.fn.datePicker']    = $wgMwEmbedDirectory . 'jquery/plugins/jquery.datePicker.js';
+
+       //jcrop
+       $wgJSAutoloadLocalClasses['j.Jcrop']                    = $wgMwEmbedDirectory . 'libClipEdit/Jcrop/js/jquery.Jcrop.js';
+
+    //color picker
+       $wgJSAutoloadLocalClasses['j.fn.ColorPicker']   = $wgMwEmbedDirectory . 'libClipEdit/colorpicker/js/colorpicker.js';
+
+       //jquery.ui
+       $wgJSAutoloadLocalClasses['j.ui']                               = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.core.js';
+
+       $wgJSAutoloadLocalClasses['j.effects.blind']    = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.blind.js';
+       $wgJSAutoloadLocalClasses['j.effects.drop']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.drop.js';
+       $wgJSAutoloadLocalClasses['j.effects.pulsate']  = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.pulsate.js';
+       $wgJSAutoloadLocalClasses['j.effects.transfer'] = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.transfer.js';
+       $wgJSAutoloadLocalClasses['j.ui.droppable']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.droppable.js';
+       $wgJSAutoloadLocalClasses['j.ui.slider']                = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.slider.js';
+       $wgJSAutoloadLocalClasses['j.effects.bounce']   = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.bounce.js';
+       $wgJSAutoloadLocalClasses['j.effects.explode']  = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.explode.js';
+       $wgJSAutoloadLocalClasses['j.effects.scale']    = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.scale.js';
+       $wgJSAutoloadLocalClasses['j.ui.datepicker']    = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.datepicker.js';
+       $wgJSAutoloadLocalClasses['j.ui.progressbar']   = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.progressbar.js';
+       $wgJSAutoloadLocalClasses['j.ui.sortable']              = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.sortable.js';
+       $wgJSAutoloadLocalClasses['j.effects.clip']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.clip.js';
+       $wgJSAutoloadLocalClasses['j.effects.fold']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.fold.js';
+       $wgJSAutoloadLocalClasses['j.effects.shake']    = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.shake.js';
+       $wgJSAutoloadLocalClasses['j.ui.dialog']                = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.dialog.js';
+       $wgJSAutoloadLocalClasses['j.ui.resizable']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.resizable.js';
+       $wgJSAutoloadLocalClasses['j.ui.tabs']                  = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.tabs.js';
+       $wgJSAutoloadLocalClasses['j.effects.core']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.core.js';
+       $wgJSAutoloadLocalClasses['j.effects.highlight']= $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.highlight.js';
+       $wgJSAutoloadLocalClasses['j.effects.slide']    = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/effects.slide.js';
+       $wgJSAutoloadLocalClasses['j.ui.accordion']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.accordion.js';
+       $wgJSAutoloadLocalClasses['j.ui.draggable']             = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.draggable.js';
+       $wgJSAutoloadLocalClasses['j.ui.selectable']    = $wgMwEmbedDirectory . 'jquery/jquery.ui-1.7.1/ui/ui.selectable.js';
+
+       //libAddMedia:
+       $wgJSAutoloadLocalClasses['mvFirefogg']                 = $wgMwEmbedDirectory . 'libAddMedia/mvFirefogg.js';
+       $wgJSAutoloadLocalClasses['mvAdvFirefogg']              = $wgMwEmbedDirectory . 'libAddMedia/mvAdvFirefogg.js';
+    $wgJSAutoloadLocalClasses['mvBaseUploadInterface'] = $wgMwEmbedDirectory . 'libAddMedia/mvBaseUploadInterface.js';
+       $wgJSAutoloadLocalClasses['remoteSearchDriver'] = $wgMwEmbedDirectory . 'libAddMedia/remoteSearchDriver.js';
+       $wgJSAutoloadLocalClasses['seqRemoteSearchDriver'] = $wgMwEmbedDirectory . 'libAddMedia/seqRemoteSearchDriver.js';
+       $wgJSAutoloadLocalClasses['baseRemoteSearch']   = $wgMwEmbedDirectory . 'libAddMedia/searchLibs/baseRemoteSearch.js';
+       $wgJSAutoloadLocalClasses['mediaWikiSearch']    = $wgMwEmbedDirectory . 'libAddMedia/searchLibs/mediaWikiSearch.js';
+       $wgJSAutoloadLocalClasses['metavidSearch']              = $wgMwEmbedDirectory . 'libAddMedia/searchLibs/metavidSearch.js';
+       $wgJSAutoloadLocalClasses['archiveOrgSearch']   = $wgMwEmbedDirectory . 'libAddMedia/searchLibs/archiveOrgSearch.js';
+       $wgJSAutoloadLocalClasses['baseRemoteSearch']   = $wgMwEmbedDirectory . 'libAddMedia/searchLibs/baseRemoteSearch.js';
+
+       //libClipEdit:
+       $wgJSAutoloadLocalClasses['mvClipEdit']                 = $wgMwEmbedDirectory . 'libClipEdit/mvClipEdit.js';
+
+       //libEmbedObj:
+       $wgJSAutoloadLocalClasses['embedVideo']                 = $wgMwEmbedDirectory . 'libEmbedVideo/embedVideo.js';
+       $wgJSAutoloadLocalClasses['flashEmbed']                 = $wgMwEmbedDirectory . 'libEmbedVideo/flashEmbed.js';
+       $wgJSAutoloadLocalClasses['genericEmbed']               = $wgMwEmbedDirectory . 'libEmbedVideo/genericEmbed.js';
+       $wgJSAutoloadLocalClasses['htmlEmbed']                  = $wgMwEmbedDirectory . 'libEmbedVideo/htmlEmbed.js';
+       $wgJSAutoloadLocalClasses['javaEmbed']                  = $wgMwEmbedDirectory . 'libEmbedVideo/javaEmbed.js';
+       $wgJSAutoloadLocalClasses['nativeEmbed']                = $wgMwEmbedDirectory . 'libEmbedVideo/nativeEmbed.js';
+       $wgJSAutoloadLocalClasses['quicktimeEmbed']     = $wgMwEmbedDirectory . 'libEmbedVideo/quicktimeEmbed.js';
+       $wgJSAutoloadLocalClasses['vlcEmbed']                   = $wgMwEmbedDirectory . 'libEmbedVideo/vlcEmbed.js';
+
+       //libSequencer:
+       $wgJSAutoloadLocalClasses['mvPlayList']                 = $wgMwEmbedDirectory . 'libSequencer/mvPlayList.js';
+       $wgJSAutoloadLocalClasses['mvSequencer']                = $wgMwEmbedDirectory . 'libSequencer/mvSequencer.js';
+       $wgJSAutoloadLocalClasses['mvSequencer']                = $wgMwEmbedDirectory . 'libSequencer/mvSequencer.js';
+
+       //libTimedText:
+       $wgJSAutoloadLocalClasses['mvTimedEffectsEdit'] = $wgMwEmbedDirectory . 'libTimedText/mvTimedEffectsEdit.js';
+?>
\ No newline at end of file
diff --git a/js2/mwEmbed/php/languages/mwEmbed.i18n.php b/js2/mwEmbed/php/languages/mwEmbed.i18n.php
new file mode 100644 (file)
index 0000000..c5c595f
--- /dev/null
@@ -0,0 +1,258 @@
+<?
+/* localization file for mwEmbed
+ * updates can be merged from javascript by running maintenance/mergeJavascriptMsg.php
+ * this file follows the "extension" conventions for language msgs in mediaWiki But should be "usable" stand-alone with the script-loader
+ *
+ * the following English language portion is automatically merged via the maintenance script.
+*/
+
+#<JAVASCRIPT EN REPLACE>
+$messages['en'] = array(
+       /*
+       * js file: /libTimedText/mvTextInterface.js
+       */
+       'select_transcript_set' => 'Select Layers',
+       'auto_scroll' => 'auto scroll',
+       'close' => 'close',
+       'improve_transcript' => 'Improve',
+
+       /*
+       * js file: /libAddMedia/mvBaseUploadInterface.js
+       */
+       'upload-transcode-in-progress' => 'Doing Transcode & Upload (do not close this window)',
+       'upload-in-progress' => 'Upload in Progress (do not close this window)',
+       'upload-transcoded-status' => 'Transcoded',
+       'uploaded-status' => 'Uploaded',
+       'wgfogg_wrong_version' => 'You have firefogg installed but its outdated, <a href="http://firefogg.org">please upgrade</a> ',
+       'upload-stats-fileprogres' => '$1 of $2',
+       'mv_upload_completed' => 'Your upload is complete',
+       'mv_upload_done' => 'Your upload <i>should be</i> accessible <a href="$1">here</a>',
+       'upload-unknown-size' => 'Unknown size',
+       'mv-cancel-confim' => 'Are you sure you want to cancel?',
+       'successfulupload' => 'Successful Upload',
+       'uploaderror' => 'Upload error',
+       'uploadwarning' => 'Upload warning',
+       'unknown-error' => 'Unknown Error',
+       'return-to-form' => 'Return to form',
+       'file-exists-duplicate' => 'This file is a duplicate of the following file',
+       'fileexists' => 'A file with this name exists already, please check <b><tt>$1</tt></b> if you are not sure if you want to change it.',
+       'fileexists-thumb' => '<center><b>Existing file</b></center>',
+       'ignorewarning' => 'Ignore warning and save file anyway',
+       'file-thumbnail-no' => 'The filename begins with <b><tt>$1</tt></b>',
+       'go-to-resource' => 'Go to Resource Page',
+       'wgfogg_waring_bad_extension' => 'You have selected a file with an unsuported extension (<a href="http://commons.wikimedia.org/wiki/Commons:Firefogg#Supported_File_Types">more information</a>).',
+       'cancel-button' => 'Cancel',
+       'ok-button' => 'OK',
+
+       /*
+       * js file: /libAddMedia/mvAdvFirefogg.js
+       */
+       'help-sticky' => 'Help (Click to Keep Help on Screen)',
+       'fogg-cg-preset' => 'Preset: <strong>$1</strong>',
+       'fogg-cg-quality' => 'Basic Quality and Resolution Control',
+       'fogg-cg-meta' => 'Meta Data for the Clip',
+       'fogg-cg-advVideo' => 'Advanced Video Encoding Controls',
+       'fogg-cg-advAudio' => 'Advanced Audio Encoding Controls',
+       'fogg-preset-custom' => 'Custom Settings',
+
+       /*
+       * js file: /libAddMedia/mediaWikiUploadHelper.OFF.js
+       */
+       'upload-enable-converter' => 'Enable video converter (to upload source video not yet converted to theora format) <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">more info</a>',
+       'upload-fogg_not_installed' => 'If you want to upload video consider installing <a href="http://firefogg.org">firefogg.org</a>, <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">more info</a>',
+       'upload-transcode-in-progress' => 'Doing Transcode & Upload (do not close this window)',
+       'upload-in-progress' => 'Upload in Progress (do not close this window)',
+       'upload-transcoded-status' => 'Transcoded',
+       'uploaded-status' => 'Uploaded',
+       'upload-select-file' => 'Select File...',
+       'wgfogg_wrong_version' => 'You have firefogg installed but its outdated, <a href="http://firefogg.org">please upgrade</a> ',
+       'wgfogg_waring_ogg_upload' => 'You have selected an ogg file for conversion to ogg (this is probably unnessesary). Maybe disable the video converter?',
+       'wgfogg_waring_bad_extension' => 'You have selected a file with an unsuported extension. <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg#Supported_File_Types">More help</a>',
+       'upload-stats-fileprogres' => '$1 of $2',
+       'mv_upload_done' => 'Your upload <i>should be</i> accessible <a href="$1">here</a>',
+       'upload-unknown-size' => 'Unknown size',
+       'successfulupload' => 'Successful upload',
+       'uploaderror' => 'Upload error',
+       'uploadwarning' => 'Upload warning',
+       'unknown-error' => 'Unknown Error',
+       'return-to-form' => 'Return to form',
+       'file-exists-duplicate' => 'This file is a duplicate of the following file',
+       'fileexists' => 'A file with this name exists already, please check <b><tt>$1</tt></b> if you are not sure if you want to change it.',
+       'fileexists-thumb' => '<center><b>Existing file</b></center>',
+       'ignorewarning' => 'Ignore warning and save file anyway',
+       'file-thumbnail-no' => 'The filename begins with <b><tt>$1</tt></b>',
+
+       /*
+       * js file: /libAddMedia/searchLibs/metavidSearch.js
+       */
+       'mv_stream_title' => '$1 $2 to $3',
+
+       /*
+       * js file: /libAddMedia/mvFirefogg.js
+       */
+       'fogg-select_file' => 'Select File',
+       'fogg-select_new_file' => 'Select New File',
+       'fogg-save_local_file' => 'Save Ogg',
+       'fogg-check_for_fogg' => 'Checking for Firefogg <blink>...</blink>',
+       'fogg-installed' => 'Firefogg is Installed',
+       'fogg-for_improved_uplods' => 'For Improved uploads: ',
+       'fogg-please_install' => '<a href="$1">Install Firefogg</a>. More <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">about firefogg</a>',
+       'fogg-use_latest_fox' => 'Please first install <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>. <i>then revisit this page to install the <b>firefogg</b> extention</i>',
+       'fogg-passthrough_mode' => 'Your selected file is already ogg or not a video file',
+       'fogg-transcoding' => 'Encoding Video to Ogg',
+       'fogg-encoding-done' => 'Encoding Done',
+
+       /*
+       * js file: /libAddMedia/remoteSearchDriver.js
+       */
+       'add_media_wizard' => 'Add Media Wizard',
+       'mv_media_search' => 'Media Search',
+       'rsd_box_layout' => 'Box layout',
+       'rsd_list_layout' => 'List Layout',
+       'rsd_results_desc' => 'Results ',
+       'rsd_results_next' => 'next ',
+       'rsd_results_prev' => 'previous ',
+       'rsd_no_results' => 'No search results for <b>$1</b>',
+       'mv_upload' => 'Upload',
+       'rsd_layout' => 'Layout:',
+       'rsd_resource_edit' => 'Edit Resource: $1',
+       'resource_description_page' => 'Resource Description Page',
+       'rsd_local_resource_title' => 'Local Resource Title',
+       'rsd_do_insert' => 'Do Insert',
+       'cc_title' => 'Creative Commons',
+       'cc_by_title' => 'Attribution',
+       'cc_nc_title' => 'Noncommercial',
+       'cc_nd_title' => 'No Derivative Works',
+       'cc_sa_title' => 'Share Alike',
+       'cc_pd_title' => 'Public Domain',
+       'unknown_license' => 'Unknown License',
+       'no_import_by_url' => 'This User or Wiki <b>can not</b> import assets from remote URLs. </p><p> Do you need to Login? </p><p> If permissions are set you may have to enable $wgAllowCopyUploads, <a href="http://www.mediawiki.org/wiki/Manual:$wgAllowCopyUploads">more info</a></p>',
+       'results_from' => 'Results from <a href="$1" target="_new" >$2</a>',
+
+       /*
+       * js file: /libSequencer/mvSequencer.js
+       */
+       'menu_clipedit' => 'Edit Media',
+       'menu_transition' => 'Transitions & Effects',
+       'menu_cliplib' => 'Add Media',
+       'menu_resource_overview' => 'Resource Overview',
+       'menu_options' => 'Options',
+       'loading_timeline' => 'Loading TimeLine <blink>...</blink>',
+       'loading_user_rights' => 'Loading user rights <blink>...</blink>',
+       'no_edit_permissions' => 'You don\'t have permissions to save changes to this sequence',
+       'edit_clip' => 'Edit Clip',
+       'edit_save' => 'Save Sequence Changes',
+       'saving_wait' => 'Save in Progress (please wait)',
+       'save_done' => 'Save Done',
+       'edit_cancel' => 'Cancel Sequence Edit',
+       'edit_cancel_confirm' => 'Are you sure you want to cancel your edit. Changes will be lost',
+       'zoom_in' => 'Zoom In',
+       'zoom_out' => 'Zoom Out',
+       'cut_clip' => 'Cut Clips',
+       'expand_track' => 'Expand Track',
+       'colapse_track' => 'Collapse Track',
+       'play_from_position' => 'Play From Playline Position',
+       'pixle2sec' => 'pixles to seconds',
+       'rmclip' => 'Remove Clip',
+       'clip_in' => 'clip in',
+       'clip_out' => 'clip out',
+       'mv_welcome_to_sequencer' => '<h3>Welcome to the sequencer demo</h3> very <b>limited</b> functionality right now. Not much documentation yet either',
+       'no_selected_resource' => '<h3>No Resource selected</h3> Select a Clip to enable editing',
+       'error_edit_multiple' => '<h3>Multiple Resources Selected</h3> Select a single clip to edit it',
+       'mv_editor_options' => 'Editor options',
+       'mv_editor_mode' => 'Editor mode',
+       'mv_simple_editor_desc' => 'simple editor (iMovie style)',
+       'mv_advanced_editor_desc' => 'advanced editor (Final Cut style)',
+       'mv_other_options' => 'Other Options',
+       'mv_contextmenu_opt' => 'Enable Context Menus',
+       'mv_sequencer_credit_line' => 'Developed by <a href="http://kaltura.com">Kaltura, Inc.</a>  in partnership with the <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> ( <a href="#">more info</a> )',
+
+       /*
+       * js file: /libSequencer/mvTimedEffectsEdit.js
+       */
+       'transition_in' => 'Transition In',
+       'transition_out' => 'Transition Out',
+       'effects' => 'Effects Stack',
+       'remove_transition' => 'Remove Transition',
+       'edit_transin' => 'Edit Transition Into Clip',
+       'edit_transout' => 'Edit Transition Out of Clip',
+
+       /*
+       * js file: /libEmbedVideo/embedVideo.js
+       */
+       'loading_plugin' => 'loading plugin<blink>...</blink>',
+       'select_playback' => 'Set Playback Preference',
+       'link_back' => 'Link Back',
+       'error_load_lib' => 'mv_embed: Unable to load required javascript libraries
+ insert script via DOM has failed, try reloading?  ',
+       'error_swap_vid' => 'Error:mv_embed was unable to swap the video tag for the mv_embed interface',
+       'add_to_end_of_sequence' => 'Add to End of Sequence',
+       'missing_video_stream' => 'The video file for this stream is missing',
+       'play_clip' => 'Play Clip',
+       'pause_clip' => 'Pause Clip',
+       'volume_control' => 'Volume Control',
+       'player_options' => 'Player Options',
+       'closed_captions' => 'Close Captions',
+       'player_fullscreen' => 'Fullscreen',
+       'next_clip_msg' => 'Play Next Clip',
+       'prev_clip_msg' => 'Play Previous Clip',
+       'current_clip_msg' => 'Continue Playing this Clip',
+       'seek_to' => 'Seek to',
+       'download_segment' => 'Download Selection:',
+       'download_full' => 'Download Full Video File:',
+       'download_right_click' => 'To download right click and select <i>save target as</i>',
+       'download_clip' => 'Download the Clip',
+       'download_text' => 'Download Text (<a style="color:white" title="cmml" href="http://wiki.xiph.org/index.php/CMML">cmml</a> xml):',
+       'clip_linkback' => 'Clip Source Page',
+       'mv_ogg-player-vlc-mozilla' => 'VLC Plugin',
+       'mv_ogg-player-videoElement' => 'Native Ogg Video Support',
+       'mv_ogg-player-vlc-activex' => 'VLC ActiveX',
+       'mv_ogg-player-oggPlugin' => 'Generic Ogg Plugin',
+       'mv_ogg-player-quicktime-mozilla' => 'Quicktime Plugin',
+       'mv_ogg-player-quicktime-activex' => 'Quicktime ActiveX',
+       'mv_ogg-player-cortado' => 'Java Cortado',
+       'mv_ogg-player-flowplayer' => 'Flowplayer',
+       'mv_ogg-player-selected' => ' (selected)',
+       'mv_ogg-player-omtkplayer' => 'OMTK Flash Vorbis',
+       'mv_generic_missing_plugin' => 'You browser does not appear to support playback type: <b>$1</b><br> visit the <a href="http://commons.wikimedia.org/wiki/Commons:Media_help">Playback Methods</a> page to download a player<br>',
+       'mv_for_best_experience' => 'For a better video playback experience we recommend <b><a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=mv_embed">Firefox 3.5</a></b>',
+       'mv_do_not_warn_again' => 'Do not warn me again.',
+
+       /*
+       * js file: /libClipEdit/mvClipEdit.js
+       */
+       'mv_crop' => 'Crop Image',
+       'mv_apply_crop' => 'Apply Crop to Image',
+       'mv_reset_crop' => 'Rest Crop',
+       'mv_insert_image_page' => 'Insert Into page',
+       'mv_insert_into_sequence' => 'Insert Into Sequence',
+       'mv_preview_insert' => 'Preview Insert',
+       'mv_cancel_image_insert' => 'Cancel Insert',
+       'sc_fileopts' => 'Clip Detail Edit',
+       'sc_inoutpoints' => 'Set In-Out points',
+       'sc_overlays' => 'Overlays',
+       'sc_audio' => 'Audio Control',
+       'sc_duration' => 'Duration',
+       'mv_template_properties' => 'Template Properties',
+       'mv_custom_title' => 'Custom Title',
+       'mv_edit_properties' => 'Edit Properties',
+       'mv_other_properties' => 'Other Properties',
+       'mv_resource_page' => 'Resource Page:',
+       'mv_set_in_out_points' => 'Set in-out points',
+       'mv_start_time' => 'Start Time',
+       'mv_end_time' => 'End Time',
+       'mv_preview_inout' => 'Preview/Play In-out points',
+
+       /*
+       * js file: /mv_embed.js
+       */
+       'loading_txt' => 'loading <blink>...</blink>',
+       'loading_title' => 'Loading...',
+       'size-gigabytes' => '$1 GB',
+       'size-megabytes' => '$1 MB',
+       'size-kilobytes' => '$1 K',
+       'size-bytes' => '$1 B',
+);
+#</JAVASCRIPT EN REPLACE>
+
+?>
\ No newline at end of file
diff --git a/js2/mwEmbed/php/maintenance/mergeJavascriptMsg.php b/js2/mwEmbed/php/maintenance/mergeJavascriptMsg.php
new file mode 100644 (file)
index 0000000..c4e6bad
--- /dev/null
@@ -0,0 +1,81 @@
+<?
+//merges in javascript with mwEmbed.i18n.php
+
+# Abort if called from a web server
+if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) {
+       print "This script must be run from the command line\n";
+       exit();
+}
+define('MEDIAWIKI',true);
+//get the scriptLoader globals:
+require_once('../../jsScriptLoader.php');
+
+$mwSTART_MSG_KEY = '#<JAVASCRIPT EN REPLACE>';
+$mwEND_MSG_KEY = '#</JAVASCRIPT EN REPLACE>';
+$mwLangFilePath = '../languages/mwEmbed.i18n.php';
+//get options (like override JS or override php
+
+
+//read in mwEmbed.i18n.php
+$rawLangFile = file_get_contents($mwLangFilePath);
+
+$startInx = strpos($rawLangFile, $mwSTART_MSG_KEY) + strlen($mwSTART_MSG_KEY);
+$endInx =  strpos($rawLangFile, $mwEND_MSG_KEY);
+if( $startInx === false || $endInx === false ){
+    print "Could not find $mwSTART_MSG_KEY or $mwEND_MSG_KEY in mwEmbed.i18n.php \n";
+       exit();
+}
+
+$preFile = substr( $rawLangFile, 0, $startInx);
+$msgSet =  substr( $rawLangFile, $startInx, $endInx-$startInx);
+$postFile = substr($rawLangFile, $endInx);
+
+//build replacement from all javascript in mwEmbed
+
+$path = realpath('../../');
+
+$curFileName = '';
+//@@todo existing msgSet should be parsed (or we just "include" the file first)
+$msgSet = '$messages[\'en\'] = array(';
+
+$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
+foreach($objects as $fname => $object){
+    if(substr($fname, -3) == '.js'){
+        $jsFileText = file_get_contents( $fname );
+        $mwPos = strpos($fname, 'mwEmbed') + 7;
+        $curFileName = substr( $fname, $mwPos );
+        if( preg_match('/loadGM\s*\(\s*{(.*)}\s*\)\s*/siU',    //@@todo fix: will break down if someone does }) in their msg text
+                                     $jsFileText,
+                                     $matches) ){
+                  $msgSet .= doJsonMerge($matches[1]);
+        }
+    }
+}
+//close up the msgSet:
+$msgSet.=");\n";
+
+function doJsonMerge($json_txt){
+    global $curFileName;
+
+    $out = "\n\t/*
+\t* js file: {$curFileName}
+\t*/\n";
+       $jmsg = json_decode( '{' . $json_txt . '}', true );
+    if( count($jmsg) != 0 ){
+               foreach($jmsg as $k=>$v){
+               $out.="\t'{$k}' => '".str_replace('\'', '\\\'', $v) ."',\n";
+               }
+               return $out;
+    }else{
+        print "could not get any json vars\n";
+        return '';
+    }
+}
+
+//rebuild and output to file
+if( file_put_contents($mwLangFilePath, trim($preFile) . "\n" . trim($msgSet) . "\n" . trim($postFile))){
+    print "updated $mwLangFilePath file\n";
+    exit();
+}
+
+?>
\ No newline at end of file
diff --git a/js2/mwEmbed/php/minify/JSMin.php b/js2/mwEmbed/php/minify/JSMin.php
new file mode 100644 (file)
index 0000000..9e1c432
--- /dev/null
@@ -0,0 +1,293 @@
+<?php
+
+if ( !defined( 'MEDIAWIKI' ) )  die( 1 );
+/**
+ * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
+ *
+ * This is pretty much a direct port of jsmin.c to PHP with just a few
+ * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
+ * outputs to stdout, this library accepts a string as input and returns another
+ * string as output.
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
+ *
+ * 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 shall be used for Good, not Evil.
+ *
+ * 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.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove <ryan@wonko.com>
+ * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
+ * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JSMin {
+  const ORD_LF    = 10;
+  const ORD_SPACE = 32;
+
+  protected $a           = '';
+  protected $b           = '';
+  protected $input       = '';
+  protected $inputIndex  = 0;
+  protected $inputLength = 0;
+  protected $lookAhead   = null;
+  protected $output      = '';
+
+  // -- Public Static Methods --------------------------------------------------
+
+  public static function minify($js) {
+    $jsmin = new JSMin($js);
+    return $jsmin->min();
+  }
+
+  // -- Public Instance Methods ------------------------------------------------
+
+  public function __construct($input) {
+    $this->input       = str_replace("\r\n", "\n", $input);
+    $this->inputLength = strlen($this->input);
+  }
+
+  // -- Protected Instance Methods ---------------------------------------------
+
+  protected function action($d) {
+    switch($d) {
+      case 1:
+        $this->output .= $this->a;
+
+      case 2:
+        $this->a = $this->b;
+
+        if ($this->a === "'" || $this->a === '"') {
+          for (;;) {
+            $this->output .= $this->a;
+            $this->a       = $this->get();
+
+            if ($this->a === $this->b) {
+              break;
+            }
+
+            if (ord($this->a) <= self::ORD_LF) {
+              throw new JSMinException('Unterminated string literal.');
+            }
+
+            if ($this->a === '\\') {
+              $this->output .= $this->a;
+              $this->a       = $this->get();
+            }
+          }
+        }
+
+      case 3:
+        $this->b = $this->next();
+
+        if ($this->b === '/' && (
+            $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+            $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+            $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+          $this->output .= $this->a . $this->b;
+
+          for (;;) {
+            $this->a = $this->get();
+
+            if ($this->a === '/') {
+              break;
+            } elseif ($this->a === '\\') {
+              $this->output .= $this->a;
+              $this->a       = $this->get();
+            } elseif (ord($this->a) <= self::ORD_LF) {
+              throw new JSMinException('Unterminated regular expression '.
+                  'literal.');
+            }
+
+            $this->output .= $this->a;
+          }
+
+          $this->b = $this->next();
+        }
+    }
+  }
+
+  protected function get() {
+    $c = $this->lookAhead;
+    $this->lookAhead = null;
+
+    if ($c === null) {
+      if ($this->inputIndex < $this->inputLength) {
+        $c = $this->input[$this->inputIndex];
+        $this->inputIndex += 1;
+      } else {
+        $c = null;
+      }
+    }
+
+    if ($c === "\r") {
+      return "\n";
+    }
+
+    if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+      return $c;
+    }
+
+    return ' ';
+  }
+
+  protected function isAlphaNum($c) {
+    return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+  }
+
+  protected function min() {
+    $this->a = "\n";
+    $this->action(3);
+
+    while ($this->a !== null) {
+      switch ($this->a) {
+        case ' ':
+          if ($this->isAlphaNum($this->b)) {
+            $this->action(1);
+          } else {
+            $this->action(2);
+          }
+          break;
+
+        case "\n":
+          switch ($this->b) {
+            case '{':
+            case '[':
+            case '(':
+            case '+':
+            case '-':
+              $this->action(1);
+              break;
+
+            case ' ':
+              $this->action(3);
+              break;
+
+            default:
+              if ($this->isAlphaNum($this->b)) {
+                $this->action(1);
+              }
+              else {
+                $this->action(2);
+              }
+          }
+          break;
+
+        default:
+          switch ($this->b) {
+            case ' ':
+              if ($this->isAlphaNum($this->a)) {
+                $this->action(1);
+                break;
+              }
+
+              $this->action(3);
+              break;
+
+            case "\n":
+              switch ($this->a) {
+                case '}':
+                case ']':
+                case ')':
+                case '+':
+                case '-':
+                case '"':
+                case "'":
+                  $this->action(1);
+                  break;
+
+                default:
+                  if ($this->isAlphaNum($this->a)) {
+                    $this->action(1);
+                  }
+                  else {
+                    $this->action(3);
+                  }
+              }
+              break;
+
+            default:
+              $this->action(1);
+              break;
+          }
+      }
+    }
+
+    return $this->output;
+  }
+
+  protected function next() {
+    $c = $this->get();
+
+    if ($c === '/') {
+      switch($this->peek()) {
+        case '/':
+          for (;;) {
+            $c = $this->get();
+
+            if (ord($c) <= self::ORD_LF) {
+              return $c;
+            }
+          }
+
+        case '*':
+          $this->get();
+
+          for (;;) {
+            switch($this->get()) {
+              case '*':
+                if ($this->peek() === '/') {
+                  $this->get();
+                  return ' ';
+                }
+                break;
+
+              case null:
+                throw new JSMinException('Unterminated comment.');
+            }
+          }
+
+        default:
+          return $c;
+      }
+    }
+
+    return $c;
+  }
+
+  protected function peek() {
+    $this->lookAhead = $this->get();
+    return $this->lookAhead;
+  }
+}
+
+// -- Exceptions ---------------------------------------------------------------
+class JSMinException extends Exception {}
+?>
\ No newline at end of file
diff --git a/js2/mwEmbed/php/mv_embed_iframe.php b/js2/mwEmbed/php/mv_embed_iframe.php
new file mode 100644 (file)
index 0000000..08bd0a7
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+/*
+mv_embed_iframe.php
+this allows for remote embedding without exposing the hosting site to remote javascript. 
+*/
+
+mv_embed_iframe();
+
+function mv_embed_iframe() {
+       if(!function_exists('filter_input')){
+               die('your version of php lacks <b>filter_input()</b> function</br>');
+       }       
+       //default to null media in not provided:        
+       $stream_name = ( isset($_GET['sn']) )? $_GET['sn'] : die('no stream name provided');
+       $time =   ( isset($_GET['t']) )? $_GET['t']: '';        
+       $width =  ( isset($_GET['width'])  )? intval( $_GET['width'] )  : '400';
+       $height = ( isset($_GET['height']) )? intval( $_GET['height'] )         : '300';                //
+       
+       $roe_url = 'http://metavid.org/wiki/Special:MvExportStream?feed_format=roe&stream_name=' . htmlspecialchars( $stream_name ) . 
+                                       '&t=' . htmlspecialchars( $time );
+       //everything good output page: 
+       output_page(array(
+               'roe_url' => $roe_url,
+               'width'         => $width,
+               'height'        => $height,
+       ));
+}
+function output_page($params){
+       extract( $params );
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+       <html xmlns="http://www.w3.org/1999/xhtml">
+       <head>
+       <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+       <title>mv_embed iframe</title>  
+       <style type="text/css"> 
+       <!--
+       body {
+               margin-left: 0px;
+               margin-top: 0px;
+               margin-right: 0px;
+               margin-bottom: 0px;
+       }
+       -->
+       </style>
+               <script type="text/javascript" src="mv_embed.js"></script>
+       </head>
+       <body>
+               <video roe="<?php echo $roe_url ?>" width="<?php echo htmlspecialchars( $width )?>"
+                          height="<?php echo htmlspecialchars( $height )?>"></video>   
+       </body>
+       </html>
+<?
+}
+
+/**
+ * JS escape function copied from MediaWiki's Xml::escapeJsString()
+ */
+function escapeJsString( $string ) {
+       // See ECMA 262 section 7.8.4 for string literal format
+       $pairs = array(
+               "\\" => "\\\\",
+               "\"" => "\\\"",
+               '\'' => '\\\'',
+               "\n" => "\\n",
+               "\r" => "\\r",
+
+               # To avoid closing the element or CDATA section
+               "<" => "\\x3c",
+               ">" => "\\x3e",
+
+               # To avoid any complaints about bad entity refs
+               "&" => "\\x26",
+
+               # Work around https://bugzilla.mozilla.org/show_bug.cgi?id=274152
+               # Encode certain Unicode formatting chars so affected
+               # versions of Gecko don't misinterpret our strings;
+               # this is a common problem with Farsi text.
+               "\xe2\x80\x8c" => "\\u200c", // ZERO WIDTH NON-JOINER
+               "\xe2\x80\x8d" => "\\u200d", // ZERO WIDTH JOINER
+       );
+       return strtr( $string, $pairs );
+}
+?>
diff --git a/js2/mwEmbed/php/noMediaWikiConfig.php b/js2/mwEmbed/php/noMediaWikiConfig.php
new file mode 100644 (file)
index 0000000..5c06618
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+//give us true for mediaWiki
+define( 'MEDIAWIKI', true );
+
+define('MWEMBED_STANDALONE', true);
+
+//setup the globals:   (for documentation see: DefaultSettings.php )
+
+$wgJSAutoloadLocalClasses = array();
+
+$IP = realpath(dirname(__FILE__).'/../');
+
+//$wgMwEmbedDirectory becomes the root $IP
+$wgMwEmbedDirectory = '';
+
+$wgFileCacheDirectory = realpath(dirname(__FILE__)) . '/script-cache';
+
+$wgUseFileCache = true;
+
+$wgEnableScriptLoaderJsFile = false;
+
+
+/*Localization:*/
+$wgEnableScriptLocalization = true;
+$mwLanguageCode = 'en';
+
+$wgContLanguageCode ='';
+
+$wgStyleVersion = '218';
+
+$wgEnableScriptMinify = true;
+
+$wgUseGzip = true;
+
+
+/**
+ * Default value for chmoding of new directories.
+ */
+$wgDirectoryMode = 0777;
+
+$wgJsMimeType = 'text/javascript';
+
+//get the autoLoadClasses
+require_once( realpath( dirname(__FILE__) ) . '/jsAutoloadLocalClasses.php' );
+
+//get the JSmin class:
+require_once( realpath( dirname(__FILE__) ) . '/minify/JSMin.php' );
+
+//some static utility mediaWiki functions that we use:
+function wfClientAcceptsGzip() {
+       global $wgUseGzip;
+       if( $wgUseGzip ) {
+               # FIXME: we may want to blacklist some broken browsers
+               $m = array();
+               if( preg_match(
+                       '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
+                       $_SERVER['HTTP_ACCEPT_ENCODING'],
+                       $m ) ) {
+                       if( isset( $m[2] ) && ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) return false;
+                       wfDebug( " accepts gzip\n" );
+                       return true;
+               }
+       }
+       return false;
+}
+function wfDebug(){
+    return false;
+}
+
+/**
+ * Make directory, and make all parent directories if they don't exist
+ *
+ * @param string $dir Full path to directory to create
+ * @param int $mode Chmod value to use, default is $wgDirectoryMode
+ * @param string $caller Optional caller param for debugging.
+ * @return bool
+ */
+function wfMkdirParents( $dir, $mode = null, $caller = null ) {
+       global $wgDirectoryMode;
+
+       if ( !is_null( $caller ) ) {
+               wfDebug( "$caller: called wfMkdirParents($dir)" );
+       }
+
+       if( strval( $dir ) === '' || file_exists( $dir ) )
+               return true;
+
+       if ( is_null( $mode ) )
+               $mode = $wgDirectoryMode;
+
+       return @mkdir( $dir, $mode, true );  // PHP5 <3
+}
+function wfMsgNoTrans($msgKey){
+    global $messages, $mwLanguageCode;
+    //make sure we have the messages file:
+    require_once( realpath( dirname(__FILE__) ) . '/languages/mwEmbed.i18n.php' );
+
+    if(isset($messages[$mwLanguageCode]) && isset($messages[$mwLanguageCode][$msgKey]) ){
+        return $messages[$mwLanguageCode][$msgKey];
+    }else{
+        return '&lt;' . $msgKey . '&gt;';
+    }
+}
+?>
\ No newline at end of file
diff --git a/js2/mwEmbed/php/script-cache/README b/js2/mwEmbed/php/script-cache/README
new file mode 100755 (executable)
index 0000000..c4e0696
--- /dev/null
@@ -0,0 +1,9 @@
+This folder holds cached versions of grouped script requests.
+Be sure to enable write access by your web-server to this directory. 
+  
+You can specify a different directory by updating the $wgFileCacheDirectory variable in noMediaWikiConfig.php
+
+You can empty this directory at any time and should not be a problem.
+
+You may want to update your include call since the script server sends long expire headers since it ment to work in conjunction with mediaWiki dynamic pages that output fresh request ids as scripts update. 
+
diff --git a/js2/mwEmbed/skins/mvpcf/ie_styles.css b/js2/mwEmbed/skins/mvpcf/ie_styles.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/js2/mwEmbed/skins/mvpcf/images/Button_add_media.png b/js2/mwEmbed/skins/mvpcf/images/Button_add_media.png
new file mode 100644 (file)
index 0000000..c83582e
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/Button_add_media.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/Jcrop.gif b/js2/mwEmbed/skins/mvpcf/images/Jcrop.gif
new file mode 100644 (file)
index 0000000..72ea7cc
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/Jcrop.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/archive_org_bw.png b/js2/mwEmbed/skins/mvpcf/images/archive_org_bw.png
new file mode 100644 (file)
index 0000000..ab36cb9
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/archive_org_bw.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/archive_org_color.png b/js2/mwEmbed/skins/mvpcf/images/archive_org_color.png
new file mode 100644 (file)
index 0000000..503bf74
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/archive_org_color.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/box_layout_icon.png b/js2/mwEmbed/skins/mvpcf/images/box_layout_icon.png
new file mode 100644 (file)
index 0000000..fff1936
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/box_layout_icon.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/box_layout_icon_dark.png b/js2/mwEmbed/skins/mvpcf/images/box_layout_icon_dark.png
new file mode 100644 (file)
index 0000000..c268e78
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/box_layout_icon_dark.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/button_grey_left.png b/js2/mwEmbed/skins/mvpcf/images/button_grey_left.png
new file mode 100644 (file)
index 0000000..4e0b17f
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/button_grey_left.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/button_grey_right.png b/js2/mwEmbed/skins/mvpcf/images/button_grey_right.png
new file mode 100644 (file)
index 0000000..d32a226
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/button_grey_right.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/button_play.png b/js2/mwEmbed/skins/mvpcf/images/button_play.png
new file mode 100644 (file)
index 0000000..bc327b9
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/button_play.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/button_subscribe.png b/js2/mwEmbed/skins/mvpcf/images/button_subscribe.png
new file mode 100644 (file)
index 0000000..525cf0b
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/button_subscribe.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/button_to_clipboard.png b/js2/mwEmbed/skins/mvpcf/images/button_to_clipboard.png
new file mode 100644 (file)
index 0000000..8b4792f
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/button_to_clipboard.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/carousel_left.png b/js2/mwEmbed/skins/mvpcf/images/carousel_left.png
new file mode 100644 (file)
index 0000000..12a860e
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/carousel_left.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/carousel_right.png b/js2/mwEmbed/skins/mvpcf/images/carousel_right.png
new file mode 100644 (file)
index 0000000..626c16a
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/carousel_right.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/carousel_top_left.png b/js2/mwEmbed/skins/mvpcf/images/carousel_top_left.png
new file mode 100644 (file)
index 0000000..f01c460
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/carousel_top_left.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/carousel_top_right.png b/js2/mwEmbed/skins/mvpcf/images/carousel_top_right.png
new file mode 100644 (file)
index 0000000..e999500
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/carousel_top_right.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/clip_thumb_overlay.png b/js2/mwEmbed/skins/mvpcf/images/clip_thumb_overlay.png
new file mode 100644 (file)
index 0000000..340f167
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/clip_thumb_overlay.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/embed_arrow.png b/js2/mwEmbed/skins/mvpcf/images/embed_arrow.png
new file mode 100644 (file)
index 0000000..ce7044e
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/embed_arrow.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_bw.png b/js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_bw.png
new file mode 100644 (file)
index 0000000..08cb5ff
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_bw.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_color.png b/js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_color.png
new file mode 100644 (file)
index 0000000..682f101
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/fish_xiph_org_color.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/flash_carousel.jpg b/js2/mwEmbed/skins/mvpcf/images/flash_carousel.jpg
new file mode 100644 (file)
index 0000000..bf673e4
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/flash_carousel.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/flash_icon_bw.png b/js2/mwEmbed/skins/mvpcf/images/flash_icon_bw.png
new file mode 100644 (file)
index 0000000..b53c903
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/flash_icon_bw.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/flash_icon_color.png b/js2/mwEmbed/skins/mvpcf/images/flash_icon_color.png
new file mode 100644 (file)
index 0000000..bf25877
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/flash_icon_color.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/flash_player.jpg b/js2/mwEmbed/skins/mvpcf/images/flash_player.jpg
new file mode 100644 (file)
index 0000000..3a05d11
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/flash_player.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/font_truetype.png b/js2/mwEmbed/skins/mvpcf/images/font_truetype.png
new file mode 100644 (file)
index 0000000..147c5ff
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/font_truetype.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/html_page_icon.png b/js2/mwEmbed/skins/mvpcf/images/html_page_icon.png
new file mode 100644 (file)
index 0000000..28d7141
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/html_page_icon.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/ico_mail.png b/js2/mwEmbed/skins/mvpcf/images/ico_mail.png
new file mode 100644 (file)
index 0000000..955ac43
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/ico_mail.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/ico_rss.png b/js2/mwEmbed/skins/mvpcf/images/ico_rss.png
new file mode 100644 (file)
index 0000000..9bafee2
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/ico_rss.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/image_layout_left.png b/js2/mwEmbed/skins/mvpcf/images/image_layout_left.png
new file mode 100644 (file)
index 0000000..8110531
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/image_layout_left.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/image_layout_right.png b/js2/mwEmbed/skins/mvpcf/images/image_layout_right.png
new file mode 100644 (file)
index 0000000..1ffa9dc
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/image_layout_right.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/image_thumb_overlay.png b/js2/mwEmbed/skins/mvpcf/images/image_thumb_overlay.png
new file mode 100644 (file)
index 0000000..6229f57
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/image_thumb_overlay.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/img1.jpg b/js2/mwEmbed/skins/mvpcf/images/img1.jpg
new file mode 100644 (file)
index 0000000..a3ec451
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/img1.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/img2.jpg b/js2/mwEmbed/skins/mvpcf/images/img2.jpg
new file mode 100644 (file)
index 0000000..86fd602
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/img2.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/kaltura_logo_sm.png b/js2/mwEmbed/skins/mvpcf/images/kaltura_logo_sm.png
new file mode 100644 (file)
index 0000000..f9f639a
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/kaltura_logo_sm.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/list_layout_icon.png b/js2/mwEmbed/skins/mvpcf/images/list_layout_icon.png
new file mode 100644 (file)
index 0000000..42d28c1
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/list_layout_icon.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/list_layout_icon_dark.png b/js2/mwEmbed/skins/mvpcf/images/list_layout_icon_dark.png
new file mode 100644 (file)
index 0000000..471a97c
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/list_layout_icon_dark.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/loading_ani.gif b/js2/mwEmbed/skins/mvpcf/images/loading_ani.gif
new file mode 100644 (file)
index 0000000..3288d10
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/loading_ani.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/loading_bar_ani.gif b/js2/mwEmbed/skins/mvpcf/images/loading_bar_ani.gif
new file mode 100644 (file)
index 0000000..47adbf0
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/loading_bar_ani.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/logo.png b/js2/mwEmbed/skins/mvpcf/images/logo.png
new file mode 100644 (file)
index 0000000..76cf5ee
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/logo.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/logo2.png b/js2/mwEmbed/skins/mvpcf/images/logo2.png
new file mode 100644 (file)
index 0000000..a949d83
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/logo2.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/metavid_logo_100.png b/js2/mwEmbed/skins/mvpcf/images/metavid_logo_100.png
new file mode 100644 (file)
index 0000000..08d0cc4
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/metavid_logo_100.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/opened.png b/js2/mwEmbed/skins/mvpcf/images/opened.png
new file mode 100644 (file)
index 0000000..97ed9d1
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/opened.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/other_results_bg.png b/js2/mwEmbed/skins/mvpcf/images/other_results_bg.png
new file mode 100644 (file)
index 0000000..fba1bac
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/other_results_bg.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/other_results_top.png b/js2/mwEmbed/skins/mvpcf/images/other_results_top.png
new file mode 100644 (file)
index 0000000..20b4a22
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/other_results_top.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/other_results_top2.png b/js2/mwEmbed/skins/mvpcf/images/other_results_top2.png
new file mode 100644 (file)
index 0000000..bd34bb7
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/other_results_top2.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/pbar-ani.gif b/js2/mwEmbed/skins/mvpcf/images/pbar-ani.gif
new file mode 100644 (file)
index 0000000..0dfd45b
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/pbar-ani.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/pelosi.jpg b/js2/mwEmbed/skins/mvpcf/images/pelosi.jpg
new file mode 100644 (file)
index 0000000..e345cbc
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/pelosi.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/person1.jpg b/js2/mwEmbed/skins/mvpcf/images/person1.jpg
new file mode 100644 (file)
index 0000000..1c25555
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/person1.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_big_play_button.png b/js2/mwEmbed/skins/mvpcf/images/player_big_play_button.png
new file mode 100644 (file)
index 0000000..cdbc279
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_big_play_button.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_bottom_left.png b/js2/mwEmbed/skins/mvpcf/images/player_bottom_left.png
new file mode 100644 (file)
index 0000000..2516405
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_bottom_left.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_bottom_right.png b/js2/mwEmbed/skins/mvpcf/images/player_bottom_right.png
new file mode 100644 (file)
index 0000000..9322c4a
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_bottom_right.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_button_cc.png b/js2/mwEmbed/skins/mvpcf/images/player_button_cc.png
new file mode 100644 (file)
index 0000000..6e788d1
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_button_cc.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_button_fullscreen.png b/js2/mwEmbed/skins/mvpcf/images/player_button_fullscreen.png
new file mode 100644 (file)
index 0000000..540e768
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_button_fullscreen.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_button_options.png b/js2/mwEmbed/skins/mvpcf/images/player_button_options.png
new file mode 100644 (file)
index 0000000..83cd7a2
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_button_options.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_button_pause.png b/js2/mwEmbed/skins/mvpcf/images/player_button_pause.png
new file mode 100644 (file)
index 0000000..6f16062
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_button_pause.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_button_play.png b/js2/mwEmbed/skins/mvpcf/images/player_button_play.png
new file mode 100644 (file)
index 0000000..645e0b7
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_button_play.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_options_bg.png b/js2/mwEmbed/skins/mvpcf/images/player_options_bg.png
new file mode 100644 (file)
index 0000000..e115c99
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_options_bg.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_options_bottom.png b/js2/mwEmbed/skins/mvpcf/images/player_options_bottom.png
new file mode 100644 (file)
index 0000000..f935baf
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_options_bottom.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_options_top.png b/js2/mwEmbed/skins/mvpcf/images/player_options_top.png
new file mode 100644 (file)
index 0000000..6c35193
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_options_top.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_seek_bg_loaded.png b/js2/mwEmbed/skins/mvpcf/images/player_seek_bg_loaded.png
new file mode 100644 (file)
index 0000000..87ac7d7
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_seek_bg_loaded.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_seek_bg_normal.png b/js2/mwEmbed/skins/mvpcf/images/player_seek_bg_normal.png
new file mode 100644 (file)
index 0000000..5458193
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_seek_bg_normal.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_seek_left.png b/js2/mwEmbed/skins/mvpcf/images/player_seek_left.png
new file mode 100644 (file)
index 0000000..b710b59
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_seek_left.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_seek_right.png b/js2/mwEmbed/skins/mvpcf/images/player_seek_right.png
new file mode 100644 (file)
index 0000000..1067cd8
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_seek_right.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_slider.png b/js2/mwEmbed/skins/mvpcf/images/player_slider.png
new file mode 100644 (file)
index 0000000..bef3f55
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_slider.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_video.jpg b/js2/mwEmbed/skins/mvpcf/images/player_video.jpg
new file mode 100644 (file)
index 0000000..9b3b7be
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_video.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_video_options_bg.png b/js2/mwEmbed/skins/mvpcf/images/player_video_options_bg.png
new file mode 100644 (file)
index 0000000..17ca498
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_video_options_bg.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_volume_seek.png b/js2/mwEmbed/skins/mvpcf/images/player_volume_seek.png
new file mode 100644 (file)
index 0000000..2611fd9
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_volume_seek.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_volume_tag.png b/js2/mwEmbed/skins/mvpcf/images/player_volume_tag.png
new file mode 100644 (file)
index 0000000..1198765
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_volume_tag.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/player_volume_tag_off.png b/js2/mwEmbed/skins/mvpcf/images/player_volume_tag_off.png
new file mode 100644 (file)
index 0000000..3b2d699
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/player_volume_tag_off.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/plugin.png b/js2/mwEmbed/skins/mvpcf/images/plugin.png
new file mode 100644 (file)
index 0000000..6187b15
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/plugin.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/plugin_disabled.png b/js2/mwEmbed/skins/mvpcf/images/plugin_disabled.png
new file mode 100644 (file)
index 0000000..f4f6be5
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/plugin_disabled.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/plugin_edit.png b/js2/mwEmbed/skins/mvpcf/images/plugin_edit.png
new file mode 100644 (file)
index 0000000..b6cb0ec
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/plugin_edit.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_17.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_17.png
new file mode 100644 (file)
index 0000000..148ff15
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_17.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_80.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_80.png
new file mode 100644 (file)
index 0000000..6d7701c
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_logo_80.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_tab.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_tab.png
new file mode 100644 (file)
index 0000000..1eb19ed
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/archive_org_tab.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/cc-flickr.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/cc-flickr.png
new file mode 100644 (file)
index 0000000..3b21de4
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/cc-flickr.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/combined_tab.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/combined_tab.png
new file mode 100644 (file)
index 0000000..d49cc70
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/combined_tab.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_logo_17.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_logo_17.png
new file mode 100644 (file)
index 0000000..556d7eb
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_logo_17.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_tab.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_tab.png
new file mode 100644 (file)
index 0000000..c20b8b7
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/metavid_tab.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_logo_17.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_logo_17.png
new file mode 100644 (file)
index 0000000..f10ab33
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_logo_17.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_tab.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_tab.png
new file mode 100644 (file)
index 0000000..a01d776
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/this_wiki_tab.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_17.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_17.png
new file mode 100644 (file)
index 0000000..8fdd575
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_17.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_80.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_80.png
new file mode 100644 (file)
index 0000000..e55aca0
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_logo_80.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_tab.png b/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_tab.png
new file mode 100644 (file)
index 0000000..ae63a7a
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/remote_cp/wiki_commons_tab.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/search_suggest_bg.png b/js2/mwEmbed/skins/mvpcf/images/search_suggest_bg.png
new file mode 100644 (file)
index 0000000..e69748b
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/search_suggest_bg.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/search_suggest_bottom.png b/js2/mwEmbed/skins/mvpcf/images/search_suggest_bottom.png
new file mode 100644 (file)
index 0000000..7231cff
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/search_suggest_bottom.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/search_suggest_top.png b/js2/mwEmbed/skins/mvpcf/images/search_suggest_top.png
new file mode 100644 (file)
index 0000000..60ee2f0
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/search_suggest_top.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/selector.png b/js2/mwEmbed/skins/mvpcf/images/selector.png
new file mode 100644 (file)
index 0000000..8b2e0ad
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/selector.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/slider_handle.gif b/js2/mwEmbed/skins/mvpcf/images/slider_handle.gif
new file mode 100644 (file)
index 0000000..c91a332
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/slider_handle.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/slider_handle_green.gif b/js2/mwEmbed/skins/mvpcf/images/slider_handle_green.gif
new file mode 100644 (file)
index 0000000..84e9449
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/slider_handle_green.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/slider_handle_red.gif b/js2/mwEmbed/skins/mvpcf/images/slider_handle_red.gif
new file mode 100644 (file)
index 0000000..0d5777c
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/slider_handle_red.gif differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/sound_music_icon-60.png b/js2/mwEmbed/skins/mvpcf/images/sound_music_icon-60.png
new file mode 100644 (file)
index 0000000..eec6797
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/sound_music_icon-60.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/sound_music_icon-80.png b/js2/mwEmbed/skins/mvpcf/images/sound_music_icon-80.png
new file mode 100644 (file)
index 0000000..883fac6
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/sound_music_icon-80.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/sound_music_icon.png b/js2/mwEmbed/skins/mvpcf/images/sound_music_icon.png
new file mode 100644 (file)
index 0000000..7291987
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/sound_music_icon.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24.png b/js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24.png
new file mode 100644 (file)
index 0000000..6df91e6
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24_over.png b/js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24_over.png
new file mode 100644 (file)
index 0000000..25d165d
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock-text-layer-24_over.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop.png b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop.png
new file mode 100644 (file)
index 0000000..cf23381
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop_over.png b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop_over.png
new file mode 100644 (file)
index 0000000..d749f0f
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-crop_over.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale.png b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale.png
new file mode 100644 (file)
index 0000000..773603f
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale_over.png b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale_over.png
new file mode 100644 (file)
index 0000000..557874b
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock-tool-button-scale_over.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/stock_icon_over.xcf b/js2/mwEmbed/skins/mvpcf/images/stock_icon_over.xcf
new file mode 100644 (file)
index 0000000..27e958e
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/stock_icon_over.xcf differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/tab-bg.png b/js2/mwEmbed/skins/mvpcf/images/tab-bg.png
new file mode 100644 (file)
index 0000000..a0caaed
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/tab-bg.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/thumb1.jpg b/js2/mwEmbed/skins/mvpcf/images/thumb1.jpg
new file mode 100644 (file)
index 0000000..4341d10
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/thumb1.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/thumb2.jpg b/js2/mwEmbed/skins/mvpcf/images/thumb2.jpg
new file mode 100644 (file)
index 0000000..3004859
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/thumb2.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/thumb3.jpg b/js2/mwEmbed/skins/mvpcf/images/thumb3.jpg
new file mode 100644 (file)
index 0000000..1d6b137
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/thumb3.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/thumb4.jpg b/js2/mwEmbed/skins/mvpcf/images/thumb4.jpg
new file mode 100644 (file)
index 0000000..091a188
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/thumb4.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/tracker.png b/js2/mwEmbed/skins/mvpcf/images/tracker.png
new file mode 100644 (file)
index 0000000..2ba1f54
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/tracker.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/transition_icon.png b/js2/mwEmbed/skins/mvpcf/images/transition_icon.png
new file mode 100644 (file)
index 0000000..e6a8506
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/transition_icon.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/transparent_bg.png b/js2/mwEmbed/skins/mvpcf/images/transparent_bg.png
new file mode 100644 (file)
index 0000000..1bd5357
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/transparent_bg.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/ui-bg_diagonals-thick_20_666666_40x40.png b/js2/mwEmbed/skins/mvpcf/images/ui-bg_diagonals-thick_20_666666_40x40.png
new file mode 100644 (file)
index 0000000..64ece57
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/ui-bg_diagonals-thick_20_666666_40x40.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/uni_edit_bw.png b/js2/mwEmbed/skins/mvpcf/images/uni_edit_bw.png
new file mode 100644 (file)
index 0000000..8ac8487
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/uni_edit_bw.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/uni_edit_color.png b/js2/mwEmbed/skins/mvpcf/images/uni_edit_color.png
new file mode 100644 (file)
index 0000000..875c980
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/uni_edit_color.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/vid_default_thumb.jpg b/js2/mwEmbed/skins/mvpcf/images/vid_default_thumb.jpg
new file mode 100644 (file)
index 0000000..fae4054
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/vid_default_thumb.jpg differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/vid_next_sm.png b/js2/mwEmbed/skins/mvpcf/images/vid_next_sm.png
new file mode 100644 (file)
index 0000000..2eb5f9b
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/vid_next_sm.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/vid_prev_sm.png b/js2/mwEmbed/skins/mvpcf/images/vid_prev_sm.png
new file mode 100644 (file)
index 0000000..6856148
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/vid_prev_sm.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/images/wiki_commons_logo_80.png b/js2/mwEmbed/skins/mvpcf/images/wiki_commons_logo_80.png
new file mode 100644 (file)
index 0000000..e55aca0
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/images/wiki_commons_logo_80.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/mv_sequence.css b/js2/mwEmbed/skins/mvpcf/mv_sequence.css
new file mode 100644 (file)
index 0000000..a170695
--- /dev/null
@@ -0,0 +1,206 @@
+/* the css file for sequence styles */
+.mv_head_jump{
+       font-family:"verdana","helvetica","arial",sans-serif;
+       font-size:11px;
+       background:#CCCCCC;
+       z-index:1;
+}
+.mv_playline{
+       position:absolute;
+       background:gray;
+       top:20px;
+       left:0px;
+       width:2px;
+       bottom:0px;
+       z-index:10;
+       overflow:visible; 
+}
+.mv_playline_top{
+       position:absolute;
+       top:-5px;
+       left:-7px;
+       width:16px;
+       height:16px;    
+       background:url("images/opened.png");
+}
+.mv_story_playline{
+       position:absolute;
+       background:blue;
+       top:0px;
+       left:0px;
+       width:2px;
+       height:100%;
+       bottom:0px;
+       z-index:10;
+       overflow:visible; 
+}
+.mv_seq_tracks{
+       position:absolute;left:90px;top:0px;right:12px;bottom:0px;overflow:auto;
+}
+.mv_tl_left_cnt{
+       position:absolute;
+       top:0px;
+       left:0px;
+       bottom:0px;
+       width:85px;
+}
+.track_name{
+       font-family:"verdana","helvetica","arial",sans-serif;
+       font-size:12px;
+       width:85px;
+       position:absolute;
+       background:#CCCCCC;
+}
+.container_track{
+       position:absolute;
+       border:solid thin gray;
+
+}
+/**************************/
+.clip_img{
+       }
+.clip_edit_button{     
+       width:16px;
+       height:16px;
+       position:absolute;
+       top:0px;
+       right:50px;
+       cursor:pointer;
+}
+.clip_trans_box{
+       border:solid thin black;
+       width:32px;
+       height:32px;
+       position:absolute;
+       top:27px;
+       right:15px;
+}
+
+.clip_edit_base{
+       background: url("images/uni_edit_bw.png");
+}
+.clip_edit_over{
+       background: url('images/uni_edit_color.png');
+}
+.mv_time_clip_text{
+       font-family:"verdana","helvetica","arial",sans-serif;
+       font-size:12px;
+}
+.mv_clip_cnt{
+       position:absolute;
+       width:16px;
+       height:16px;
+}
+
+.ui-drag-e{ cursor: e-resize;}
+.ui-drag-w{ cursor: w-resize;}
+
+.mv_clip_stats{
+       font-family:"verdana","helvetica","arial",sans-serif;
+       font-size:11px;
+       position:absolute;
+       background:#CCCCCC;
+       bottom:0px;
+       right:0px;
+}
+.mv_droppable{
+       position:absolute;
+       top:0px;
+       z-index:-1;
+}
+.mv_storyboard_container{
+       position:absolute;
+       z-index:0;
+       overflow:hidden;
+}
+.mv_clip_thumb{
+       position:absolute;
+       top:7px;        
+       border:solid #CCC;
+       display:block;
+       overflow:hidden;        
+}
+.mv_tl_clip{
+       position:absolute;
+       z-index:0;
+       overflow:hidden;
+       border:solid thin white;
+       white-space: nowrap;    
+}
+.mv_tl_thumb{
+       display:inline; 
+}
+.mv_selected_clip{
+       border:solid #9F9;      
+}
+.mv_selected_transition{
+       border:solid #9F9;
+}
+.mv_adj_text{
+       font-weight: strong;
+       font-size:small;
+       color:#6F6;
+       display:none; /* hide by default */
+       position:absolute;
+       left:20px;
+}
+.mv_adjust_click{
+       cursor:pointer;
+}
+/*
+#seq_menu{
+       list-style-type:none;
+       list-style-position:outside;
+       display:block;
+       padding-left:10px;
+}
+#seq_menu li{
+       display:inline;
+       padding:5px;
+       margin:0px;
+       border: solid thin gray;
+       cursor:pointer; 
+}
+#seq_menu li a{
+       color:#fff;
+}
+*/
+.seq_control_container{
+       position:absolute;
+       top:40px;       
+       overflow:auto; 
+       bottom:0px;
+       left:10px;
+       right:0px;
+}
+.submenu_container{
+/*     top:25px;
+       left:10px;
+       right:0px;
+       overflow:auto;
+       position:absolute;
+       broder: solid thin gray;
+*/
+}
+.mv_submenu{   
+       /*position:absolute;*/
+       /*left:0px;
+       top:0px;
+       margin:2px;
+       list-style-type:none; 
+       bottom:0px;     
+       border:none;
+       padding:0px;*/
+}
+.mv_submenu li{
+       border:solid thin gray;
+       cursor:pointer;
+       display:inline;
+       padding:5px;
+}
+.mv_submenu .mv_sub_selected{
+       border-bottom: none;
+}
+#seq_menu .mv_selected_item{
+       border-bottom:none;
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/skins/mvpcf/styles.css b/js2/mwEmbed/skins/mvpcf/styles.css
new file mode 100644 (file)
index 0000000..c69fd69
--- /dev/null
@@ -0,0 +1,742 @@
+#mv_overlay {
+       background:transparent url(images/transparent_bg.png) repeat scroll 0 0;
+       cursor:wait;
+       height:100%;
+       left:0;
+       position:fixed;
+       top:0;
+       width:100%;
+       z-index:99;
+}
+
+.modal_editor {
+       /*background:#AAA none repeat scroll 0 0;
+       border:3px solid #666666;*/
+       left:10px;
+       top:10px;
+       right:10px;
+       bottom:10px;
+       position:fixed;         
+       z-index:100;
+}
+.mv_track {
+       margin-bottom:20px;
+       position:relative;
+}
+.player_select_list {
+       color:white;
+       font-size:10pt;
+/*     display:none;*/
+}
+
+.player_select_list a:visited {
+       color:white;
+}
+.displayHTML a:visited {
+       color:white;
+}
+.mv_playhead {
+       position:absolute;
+       top:0;
+       left:0;
+       width:17px;
+       height:21px;
+       /*http://art.gnome.org/themes/gtk2*/
+}
+.mv_status {
+       font-family:"Times New Roman", Times, serif;
+       font-size:14px;
+       float:left;
+}
+.set_ogg_player_pref{
+       text-align:left;
+}
+
+.inputTrackerInput {
+               height:20;
+               width:30;
+               font-family : Arial, Helvetica, sans-serif;
+       font-size : 12px;
+}
+.mv_loading_icon {
+       position:absolute;
+       top:0px;
+       right:0px;
+       width:16px;
+       height:16px;
+}
+div.floatleft, table.floatleft {
+       border:0pt none;
+       clear:left;
+       float:left;
+       margin:0pt 0.5em 0.5em 0pt;
+       position:relative;
+}
+
+
+
+
+.videoPlayer
+{
+       color: #474747; 
+}
+
+.videoPlayer a:link {color: #2060c1; text-decoration: underline;}
+.videoPlayer a:visited {color: #2060c1; text-decoration: underline;}
+/*a:visited {color: #75a5e4; text-decoration: underline;}*/ /*Not sure if you want this*/
+.videoPlayer a:hover {color: #75a5e4; text-decoration: underline;}
+.videoPlayer img, .videoPlayer img a, .videoPlayer img a:hover {border: 0;}
+
+.videoPlayer h1, .videoPlayer h2, .videoPlayer h3, .videoPlayer h4, .videoPlayer h5, .videoPlayer h6 {color: #242424; margin: 5px 0; padding: 0;}
+.videoPlayer h1 {font-size: 24px;}
+.videoPlayer h2 {font-size: 18px;}
+.videoPlayer h3 {font-size: 16px;}
+.videoPlayer h4 {font-size: 14px;}
+.videoPlayer h5 {font-size: 13px; text-align: center;}
+.videoPlayer h6 {font-size: 13px; color: #6c6c6c; padding: 10px 20px 0px 20px; text-transform: uppercase;}
+
+
+/*Video player*/
+.videoPlayer {
+/*     width: 100%;*/
+       color: white;
+}
+.videoPlayerSmall {
+/*     width: 439px;*/
+       height: 334px;
+}
+.videoPlayer .video {
+       display: block;
+       position: relative;
+       font-size: 1px;
+       height: 305px;
+}
+.videoPlayer .controls {
+       height: 29px;   
+       border-top-width: 0 !important;
+       /*background: #454545;*/
+       display:block;
+       z-index=-1;
+}
+.videoPlayer .controlInnerSmall {
+/*     width: 430px;*/
+       height: 29px;
+       float: left;
+       display: inline;
+}
+/*
+.videoPlayer .controls span.border_left {background: url(images/player_bottom_left.png) 0 0 no-repeat; width: 4px; height: 29px; float: left; display: inline;}
+.videoPlayer .controls span.border_right {background: url(images/player_bottom_right.png) 0 0 no-repeat; width: 4px; height: 29px; float: right; display: inline;}
+*/
+
+
+.videoPlayer .lButton {
+       cursor:pointer;
+       float:left;
+       list-style:none outside none;
+       margin:2px;
+       padding:4px 0;
+       width: 24px;
+       height:16px;
+       position:relative;
+}
+.videoPlayer .rButton {
+       cursor:pointer;
+       float:right;
+       list-style:none outside none;
+       margin:2px;
+       padding:4px 0;
+       width: 23px;
+       height:16px;
+       position:relative;
+}
+
+.controls a{
+       display: block;
+       height: 100%;
+       width: 100%;
+}
+.videoPlayer .volume_icon {
+       float: right;
+       display: inline;
+       width: 22px;
+       height: 29px;
+       padding: 0 0 0 0;
+       
+}
+.volume_on {   
+       background: url(images/player_volume_tag.png) 0 8px no-repeat;
+}
+.volume_off{
+       background: url(images/player_volume_tag_off.png) 0 8px no-repeat;
+}
+
+.videoPlayer .volume_control {
+       width: 42px;
+       height: 12px;
+       margin: 9px 4px 0 0;
+       float: right;
+       display: inline;
+       background: url(images/player_volume_seek.png) 0 0 no-repeat;
+}
+.videoPlayer .volume_knob {
+       background: url(images/player_slider.png) 0 0 no-repeat;
+       width: 14px;
+       height: 14px;
+       position: absolute;
+       z-index: 2;
+       margin: -1px 0 0 3px;
+       cursor: pointer;
+}
+
+
+.videoPlayer .time {
+       line-height: 32px;
+       height: 29px;
+       overflow: visible;
+       font-size: 10.2px;
+       width: 80px;
+       float: right;
+       display: inline;
+       border:none;
+}
+
+.videoPlayer .play_head{
+       float: left;
+       display: inline;        
+       height: 10px;
+       margin-left:10px;
+       margin-top:10px;        
+}
+
+.play_head .ui-slider-handle{
+       width:10px;
+       height:15px;
+       margin-left:-5px;
+       margin-top:1px;
+}
+
+.inOutSlider .ui-slider-handle{
+       width:8px;      
+       cusror: move;
+}
+
+/*
+.videoPlayer .seeker {
+       float: right;
+       display: inline;
+       width: 55%;
+       margin: 0 5px 0 5px;
+       height: 29px;
+}
+
+.videoPlayer .seeker .seeker_bar {
+       float: left;
+       display: inline;
+       width : 100%;
+       height: 12px;
+       background: url(images/player_seek_bg_loaded.png) 0 1px repeat-x;
+       margin: 9px 0px 0 0px;
+       position:relative;
+}
+
+.videoPlayer .seeker .seeker_bar_outer {
+       width: 100%;
+       height: 12px;
+       position: relative;
+       z-index: 4;
+       background: url(images/player_seek_left.png) 0 0 no-repeat;
+}
+.videoPlayer .seeker .seeker_bar_close {
+       width: 5px;
+       height: 12px;
+       position: relative;
+       z-index: 4;
+       float: right;
+       display: inline;
+       margin: -12px 0 0 0;
+       background: url(images/player_seek_right.png) 0 0 no-repeat;
+}
+
+.videoPlayer .seeker .mv_progress{
+       width: 0%;
+       height: 12px;
+       left:0px;
+       top:0px;
+       position: absolute;
+}
+.videoPlayer .seeker .mv_playback {
+       z-index: 3;
+       background: #CCC;
+}
+.videoPlayer .seeker .mv_buffer {
+       z-index: 2;
+       background: #99C;
+}
+.videoPlayer .seeker .mv_highlight {
+       z-index: 3;
+       background: #558;
+}
+.videoPlayer .seeker .seeker_slider {
+       background: url(images/player_slider.png) 0 0 no-repeat;
+       width: 14px;
+       height: 14px;
+       position: relative;
+       z-index: 6;
+       margin: -13px 0 0 0px;
+       float: left;
+       cursor: pointer;
+}
+*/
+.tt_highlight{
+       border: solid thin blue;
+       background: #CCC;
+}
+.tt_scroll_highlight{
+       border: solid thin red;
+       background: #CCF;
+}
+.mvttseek{
+       cursor:pointer;
+}
+.mvtt{
+       border:solid thin black; 
+}
+.large_play_button {   
+       display:block;
+       width: 130px;
+       height: 96px;
+       margin: auto;
+/*     margin: -202px 0 0 154px;*/
+       position: absolute;
+       z-index: 3;
+       cursor: pointer;
+}
+
+/*Video options*/
+.videoOptions {
+       display: none;
+       width: 183px;
+       overflow: hidden;
+       position: absolute;
+       z-index: 9999;
+/*     margin: 0 0 0 230px;*/
+}
+*:first-child+html .videoOptions {margin-top: -20px;}
+.videoOptionsTop {
+       width: 183px;
+       height: 32px;
+       position: relative;
+       z-index: 3;
+       background: url(images/player_options_top.png) 0 0 no-repeat;
+}
+.videoOptionsBox {
+       width: 170px;
+       padding: 0px 11px 0 4px;
+       position: relative;
+       overflow: hidden;
+       color:#6C6C6C;
+       z-index: 3;
+       background: url(images/player_options_bg.png) 0 0 repeat-y;
+}
+.videoOptionsBot {
+       width: 183px;
+       height: 18px;
+       position: relative;
+       z-index: 3;
+       background: url(images/player_options_bottom.png) 0 0 no-repeat;
+}
+
+.videoOptionsBox div.block {
+       border-top: 1px solid #dadada;
+}
+.videoOptionsBox div.block h6 {
+       padding: 0;
+       margin: 5px 0;
+       text-align: center;
+}
+.videoOptionsBox div.wide_block {
+       padding: 15px 0;
+}
+.videoOptionsBox div.first_block {
+       border: 0;
+}
+.videoOptionsBox div.block p {padding: 10px 20px;margin: 0;}
+.videoOptionsBox div.block p.short_match, .videoOptionsBox div.block p.normal_match {padding: 0; margin: 0;}
+.videoOptionsBox div.block p a {text-decoration: none;}
+.videoOptionsBox div.block p.short_match a {
+       padding: 0;
+       display: block;
+       width: 100%;
+       border-bottom: 1px solid #dadada;
+}
+.videoOptionsBox div.block p.short_match a span {display: block; padding: 5px 20px;}
+.videoOptionsBox div.block p.short_match a:hover {background: #0b68c9 url(images/selector.png) 0 0 repeat-x; color: white;}
+.videoOptionsBox div.block p.short_match a.last_match {border: 0;}
+
+.videoOptionsBox div.block p.normal_match a {
+       padding: 0;
+       margin: 0;
+       display: block;
+       width: 100%;
+       border: 0;
+}
+.videoOptionsBox div.block p.normal_match a span {display: block; padding: 3px 20px;}
+.videoOptionsBox div.block p.normal_match a:hover {background: #0b68c9 url(images/selector.png) 0 0 repeat-x; color: white;}
+.videoOptionsBox div.block p.normal_match a.last_match {border: 0;}
+
+.videoOptionsBox div.block p.bill_match {border-bottom: 1px solid #dadada;}
+
+.videoOptionsBox div.block p.last_match {border-bottom: 0;}
+
+.videoOptionsBox div.block ul {
+       list-style: none;
+       margin: 10px 0;
+       padding: 0 20px;
+}
+.videoOptionsBox div.block ul a { text-decoration: none;}
+.videoOptionsBox div.block ul li { margin: 7px 0;}
+.videoOptionsBox div.block ul li ul {margin: 0;}
+.videoOptionsBox div.block ul li ul li a {color: #df5c01;}
+.videoOptionsBox div.block ul li ul li a:hover {color: #ffa02f;}
+
+.videoOptionsBox div.block ul li span.clips {display: block; text-align: right; margin: 6px 0 18px 0;}
+
+.videoOptionsBox div.advanced a.advanced_options {color: #aaa; text-align: center; display: block; margin: 3px 0; text-decoration: none;}
+
+.videoOptionsBox div.embed_code {text-align: center; border-bottom: 1px solid #dadada; }
+.videoOptionsBox div.embed_code textarea {
+       margin: 10px 0 10px 0;
+       padding: 3px;
+       width: 142px;
+       height: 54px;
+       border: 1px solid #dadada;
+       font-family: Arial;
+       color: #777;
+       font-size: 11px;
+}
+.videoOptionsBox div.embed_code button.copy_to_clipboard {
+       background: #dddddd url(images/button_to_clipboard.png) 0 0 repeat-x;
+       border: 1px solid #a1badf;
+       text-align: center;
+       padding: 2px 4px;
+       margin: 0 0 6px 0;
+}
+
+.videoComplete {
+/*     width: 100%;
+       height: 100%;*/
+       background: url(images/transparent_bg.png) 0 0 repeat;
+       position: absolute;
+       top:0px;
+       left:0px;
+       z-index: 10;
+       font-size:16px;
+       overflow: hidden;
+}
+
+/*     margin: -305px 0 0 0; */
+.videoComplete .videoOptionsComplete {
+       background:transparent url('images/player_video_options_bg.png') no-repeat scroll 0pt;
+       color:#7A7A7A;
+       font-size:10pt;
+       height:158px;
+       left:10%;
+       overflow:auto;
+       padding:19px;
+       position:relative;
+       top:16%;
+       width:283px;
+}
+.videoComplete .videoOptionsComplete p {text-align: center; margin: 3px 0; padding: 0;}
+.videoComplete .videoOptionsComplete a {
+       color: white;
+/*     font-size: 22px;*/
+       font-size:12px;
+       text-decoration: underline;
+}
+
+.videoComplete .videoOptionsComplete a.email {
+       font-size:16px;
+       background: url(images/ico_mail.png) right 0px no-repeat; 
+       padding: 0 50px 0 0;
+}
+
+.videoComplete div.embed_code textarea {
+       margin: 8px 0 8px 0;
+       padding: 3px;
+       width: 258px;
+       height: 54px;
+       border: 1px solid #dadada;
+       font-family: Arial;
+       color: #777;
+       font-size: 11px;
+}
+.videoComplete div.embed_code button.copy_to_clipboard {
+       background: #dddddd url(images/button_to_clipboard.png) 0 0 repeat-x;
+       border: 1px solid #3b4552;
+       text-align: center;
+       padding: 2px 4px;
+       margin: 0 0 6px 0;
+       float: right;
+       display: inline;
+}
+.cl_status{
+       position:absolute; 
+       bottom:0px;
+       top:0px;
+       z-index:3;
+}
+
+.rsd_control_container{        
+       margin:10px;
+}
+
+#SEQUENCER CSS:
+#resizable css:
+/*
+.ui-resizable-handle { position: absolute; background: #ddd; display: none; }
+.ui-resizable .ui-resizable-handle { display: block }
+.ui-resizable-e { z-index:5; position:absolute; cursor: e-resize;
+       width: 15px;height:19px; top: 0px; bottom: 0px; right: 0px;
+       background: transparent url(images/slider_handle_red.gif) no-repeat scroll 0% 0%;
+}
+.ui-resizable-w { z-index:5; position:absolute; cursor: w-resize;
+       width: 15px;height:19px; top: 0px; bottom: 0px; left: 0px;
+       background: transparent url(images/slider_handle_green.gif) no-repeat scroll 0% 0%;
+}
+.ui-dragSpan {
+       filter: alpha(opacity=70); 
+       -moz-opacity: .7;
+       background-color:#AAF; 
+       position:absolute; 
+       left: 10px; 
+       right:10px;
+       height:19px;  
+}
+*/
+/*
+div.rsd_cp_tab_container{
+       display:inline;
+       margin:0;
+       padding:5px 2px 10px 2px;
+       background:#F7F7F7 url(remote_search/tab-bg.png) repeat-x scroll left bottom;
+       border:1px solid #777;  
+       margin-left:7px;
+       cursor:pointer;
+       float:left;
+       width:auto;
+}
+div.rsd_cp_tab {
+       display:inline;
+       margin:0;
+       padding:5px 2px 10px 2px;
+       background:#F7F7F7 url(remote_search/tab-bg.png) repeat-x scroll left bottom;
+       border:1px solid #777;  
+       margin-left:7px;
+       cursor:pointer;
+       float:left;
+       width:auto;
+       position:relative;
+}
+
+div.rsd_selected {
+       background:#FFFFFF none repeat scroll 0 0;      
+       border-bottom:0;
+       padding-top:6px;
+       z-index:2;
+}
+*/
+.rsd_cp_tab img{
+       border:0px;
+}
+.rsd_results_container{
+       left:2px;
+       right:2px;
+       top:2px;
+       bottom:2px;             
+}
+/*#rsd_results {
+       border-top:0;
+       border:1px solid #777;
+       /*position:relative;*/  
+       background:#FFF;        
+       left:2px;
+       right:2px;
+       bottom:2px;     
+       overflow:auto;
+       position:absolute;
+       top:75px;
+}*/
+#rsd_resource_edit{
+       z-index:2;
+}
+.rsd_license{
+       position:absolute;
+       bottom:0px;
+       left:0px;
+}
+.rsd_license img{
+       float:left;
+}
+.rsd_license span{
+       float:left;
+       background:#FFF;
+       color:#200;
+       font-size:x-small;
+       filter:alpha(opacity=70);
+       -moz-opacity:0.7;
+       opacity:0.7;
+}
+.mv_clip_box_result{
+       padding:10px;
+       float:left;
+       border: thin solid #BBB;
+       overflow:hidden;
+}
+.mv_clip_box_result_over{
+       border: thin solid #F99;        
+}
+.mv_clip_list_result{
+       padding:10px;
+       border: thin solid #BBB;
+       clear:both;
+       position:relative;
+}
+.mv_clip_list_result_over{
+       padding:10px;
+       border: thin solid #F99;
+       clear:both;
+}
+.rsd_res_item{
+       cursor:pointer;
+       display:block;
+}
+#rds_results_bar{
+       margin:4px;
+       background:#DEF;
+       height:22px;
+}
+
+/* edit buttons: */
+.mv_edit_button{       
+       width:22px;
+       height:22px;
+       float:left;
+}
+#mv_layout_left_img{
+       width:50px;
+       height:33px;
+       background-image: url('images/image_layout_left.png');
+       float:left;
+}
+#mv_layout_right_img{
+       width:50px;
+       height:33px;
+       background-image: url('images/image_layout_right.png');
+       float:left;
+}
+
+.mv_crop_button_base{
+       background-image: url('images/stock-tool-button-crop.png');
+}
+.mv_crop_button_selected{
+       background-image: url('images/stock-tool-button-crop_over.png');        
+}
+.mv_scale_button_base{
+       background-image: url('images/stock-tool-button-scale.png');
+}
+.mv_scale_button_selected{
+       background-image: url('images/stock-tool-button-scale_over.png');
+}
+.mv_loading_img{
+       width:32px;
+       height:32px;
+       display:inline;
+       padding:0px;
+       position:absolute;
+       background-image: url('images/loading_ani.gif');
+}
+.mv_loading_bar_img{
+       width:220px;
+       height:19px;
+       display:inline;
+       position:absolute;
+       background-image: url('images/loading_bar_ani.gif');
+}
+
+/* jquery.ui overides */
+
+.ui-icon_link {
+       padding: .4em 1em .4em 20px;
+       text-decoration: none;
+       position: relative;     
+}
+.ui-icon_link span.ui-icon {
+       margin: 0 5px 0 0;
+       position: absolute;
+       left: 0.2em;
+       right: auto;
+       top: 50%;
+       margin-top: -8px;
+       zoom: 1;
+}
+.ui-icon_link span.ui-text {   
+       position: absolute;
+       left: 0.2em;
+       right: auto;    
+       margin-top: -3px;
+       zoom: 1;
+}
+
+.ui-progressbar-value{
+       background-image: url('images/pbar-ani.gif');
+}
+
+ui-widget-overlay{
+       background: url("images/ui-bg_diagonals-thick_20_666666_40x40.png") repeat scroll 50% 50% #666666;
+       opacity:0.5;
+}
+
+/* Vertical Tabs
+----------------------------------*/
+.ui-dialog-buttonpane { padding:10px !important; }
+.ui-tabs-vertical { width: 55em; }
+.ui-tabs-vertical .ui-tabs-nav { padding: .2em .1em .2em .2em; float: left; width: 12em; }
+.ui-tabs-vertical .ui-tabs-nav li { clear: left; width: 100%; border-bottom-width: 1px !important; border-right-width: 0 !important; margin: 0 -1px .2em 0; }
+.ui-tabs-vertical .ui-tabs-nav li a { display:block; }
+.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 0; padding-right: .1em; border-right-width: 1px; border-right-width: 1px; }
+.ui-tabs-vertical .ui-tabs-panel { padding: 1em; float: right; width: 40em;}
+
+.ui-dialog .ui-dialog-buttonpane button { float: left !important; }
+
+.ui-widget-content a { text-decoration: underline; }
+
+
+.vol_container{
+       z-index:99;
+       width:23px;
+       height:75px;
+       width:23px;
+       background: #CCC;
+}
+.vol_container_below{
+       top:30px;
+}
+.vol_container_top{
+       top:-77px;
+}
+.vol_container .volume_bar{
+       margin-top:5px; 
+       height:65px;
+       width:10px;
+       margin-left: auto ;
+       margin-right: auto ;    
+}
+.vol_container .ui-slider-handle{
+       cursor : pointer;
+       width:10px;
+       height:10px;    
+       position:absolute;
+       left:-1px;              
+}
\ No newline at end of file
diff --git a/js2/mwEmbed/skins/mvpcf/transition_images/fade_crossfade.png b/js2/mwEmbed/skins/mvpcf/transition_images/fade_crossfade.png
new file mode 100644 (file)
index 0000000..e320e7c
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/transition_images/fade_crossfade.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/transition_images/fade_fadeFromColor.png b/js2/mwEmbed/skins/mvpcf/transition_images/fade_fadeFromColor.png
new file mode 100644 (file)
index 0000000..b4851b6
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/transition_images/fade_fadeFromColor.png differ
diff --git a/js2/mwEmbed/skins/mvpcf/transition_images/transition_wipe.png b/js2/mwEmbed/skins/mvpcf/transition_images/transition_wipe.png
new file mode 100644 (file)
index 0000000..f4350da
Binary files /dev/null and b/js2/mwEmbed/skins/mvpcf/transition_images/transition_wipe.png differ
diff --git a/js2/remoteMwEmbed.js b/js2/remoteMwEmbed.js
new file mode 100644 (file)
index 0000000..d41075e
--- /dev/null
@@ -0,0 +1,82 @@
+/* 
+ * this file exposes some of the functionality of mwEmbed to wikis 
+ * that are not yet running the new-upload branch
+ */
+
+
+var urlparts =  getRemoteEmbedPath();
+var mwEmbedHostPath =urlparts[0];
+var reqAguments =urlparts[1];
+
+//check if mvEmbed is already loaded (ie the js2 branch is active) in which case do nothing
+if( typeof MV_EMBED_VERSION == 'undefined' ){
+       doPageSpecificRewrite();
+}      
+
+function doPageSpecificRewrite(){      
+       //add media wizard:
+       if( wgAction == 'edit' || wgAction == 'submit' ){
+               load_mv_embed( function(){  
+                       importScriptURI(mwEmbedHostPath + '/editPage.js' + reqAguments);
+               });
+       }
+       
+       //firefogg integration:
+       if( wgPageName== "Special:Upload" ){    
+               load_mv_embed( function(){  
+                       importScriptURI(mwEmbedHostPath + '/uploadPage.js' +reqAguments);
+               });
+       }
+               
+       //oggHandler rewrite: 
+       var vidIdList = []; 
+       var divs = document.getElementsByTagName('div');    
+       for(var i = 0; i < divs.length; i++){        
+           if( divs[i].id && divs[i].id.substring(0,11) == 'ogg_player_'){
+               vidIdList.push( divs[i].getAttribute("id") );
+           } 
+       }            
+       if( vidIdList.length > 0){
+           load_mv_embed( function(){
+               mvJsLoader.embedVideoCheck(function(){                                                    
+                   //do utilty rewrite of oggHanlder content: 
+                   rewrite_for_oggHanlder( vidIdList );                    
+               });
+           });
+       }
+}
+function getRemoteEmbedPath(){           
+    for(var i=0; i < document.getElementsByTagName('script').length; i++){     
+        var s = document.getElementsByTagName('script')[i];       
+        if( s.src.indexOf('remoteMwEmbed.js') != -1 ){
+                   var reqStr='';
+                   var scriptPath='';                
+                   if( s.src.indexOf('?') != -1){
+                       reqStr = s.src.substr( s.src.indexOf('?') );
+                       scriptPath = s.src.substr(0,  s.src.indexOf('?')).replace('remoteMwEmbed.js', '');
+                   }else{
+                       scriptPath = s.src.replace('remoteMwEmbed.js', '')
+                   }                       
+            //use the external_media_wizard path: 
+            return [scriptPath, reqStr];
+        }
+    }    
+}
+
+function load_mv_embed( callback ){                    
+    //inject mv_embed if needed:
+    if( typeof mvEmbed == 'undefined'){        
+               importScriptURI(mwEmbedHostPath +'/mwEmbed/mv_embed.js' + reqAguments);
+        check_for_mv_embed( callback ); 
+    }else{        
+        check_for_mv_embed( callback );
+    }          
+}
+function check_for_mv_embed( callback ){
+    if( typeof MV_EMBED_VERSION == 'undefined'){         
+        setTimeout('check_for_mv_embed( ' + callback +');', 25);
+    }else{        
+        callback();
+    }
+}
+
diff --git a/js2/uploadPage.js b/js2/uploadPage.js
new file mode 100644 (file)
index 0000000..46bf061
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * uploadPage.js to be run on specialUpload page.
+ * controls the invocation of the mvUploader class based on local config. 
+ */  
+mwAddOnloadHook( function(){
+       mwUploadHelper.init();          
+});
+//set up the upoload form bindings once all dom manipluation is done
+var mwUploadHelper = {
+       firefogg_installed:false,
+       init:function(){
+               var _this = this;
+               //if not boolean false set to true: 
+               if(typeof wgEnableFirefogg == 'undefined')
+                       wgEnableFirefogg = true;
+                       
+               if( wgEnableFirefogg ){
+                       //setup the upload handler to firefogg  (supports our upload proccess) (should work with the http uploads too) 
+                       $j('#wpUploadFile').firefogg({ 
+                               //an api url (we won't submit directly to action of the form)
+                               'api_url' : wgServer + wgScriptPath + '/api.php',
+                               'form_rewrite': true,                           
+                               'new_source_cb' : function( orgFilename, oggName ){                                             
+                                               $j('#wpDestFile').val( oggName );
+                                               mwUploadHelper.doDestCheck();
+                               },
+                               'detect_cb':function(fogg_installed){
+                                       if(fogg_installed){
+                                               _this.firefogg_installed=true;
+                                       }else{
+                                               _this.firefogg_installed=false;
+                                       }
+                               }
+                       });             
+                       
+               }else{                  
+                       //Add basic upload profile support ( http status monitoring, progress box for browsers that support it etc.) 
+                       if($j('#wpUploadFileURL').length != 0){
+                               $j('#wpUploadFileURL').baseUploadInterface({ 
+                                       'api_url'   : wgServer + wgScriptPath + '/api.php',
+                                       'target_edit_from' : '#mw-upload-form' 
+                               });                             
+                       }
+               }
+               
+               if( wgAjaxUploadDestCheck ){
+                       //do destination check:          
+                       $j('#wpDestFile').change( mwUploadHelper.doDestCheck );
+               }
+               
+               //check if we have http enabled & setup enable/disable toggle:
+               if($j('#wpUploadFileURL').length != 0){                          
+                       //set the initial toggleUpType          
+                       _this.toggleUpType(true);       
+                       
+                       $j("input[name='wpSourceType']").click(function(){                      
+                               _this.toggleUpType( this.id == 'wpSourceTypeFile' );
+                       });                     
+               }         
+               $j('#wpUploadFile,#wpUploadFileURL').focus(function(){          
+                       _this.toggleUpType( this.id == 'wpUploadFile' );        
+               }).change(function(){ //also setup the onChange event binding:                           
+                       if ( wgUploadAutoFill ) {
+                               mwUploadHelper.doDestinationFill( this );               
+                       }               
+               });                        
+       },
+       /**
+        * toggleUpType sets the upload radio buttons
+        * 
+        * boolean set 
+        */                     
+       toggleUpType:function( set ){
+               $j('#wpSourceTypeFile').attr('checked', set);
+               $j('#wpUploadFile').attr('disabled', !set);
+               
+               $j('#wpSourceTypeURL').attr('checked', !set);
+               $j('#wpUploadFileURL').attr('disabled', set);
+               
+               //if firefogg is enbaled: toggle action per form select of http upload vs firefogg upload  
+               if( wgEnableFirefogg ){
+                       $j('#wpUploadFile').firefogg({
+                                       'firefogg_form_action': $j('#wpSourceTypeFile').attr('checked')
+                       });
+               }
+       },   
+       /**
+        * doDestCheck checks the destination
+        * @@todo we should be able to configure its "targets" via parent config
+        */
+       doDestCheck:function(){         
+               var _this = this;
+               $j('#wpDestFile-warning').empty();
+               //show loading
+               $j('#wpDestFile').after('<img id = "mw-spinner-wpDestFile" src ="'+ stylepath + '/common/images/spinner.gif" />');
+               //try and get a thumb of the current file (check its destination)                               
+               do_api_req({
+                       'data':{ 
+                               'titles': 'File:' + $j('#wpDestFile').val(),//@@todo we may need a more clever way to get a the filename
+                               'prop':  'imageinfo',
+                               'iiprop':'url|mime|size',
+                               'iiurlwidth': 150 
+                       },
+                       'url': _this.api_url
+               },function(data){
+                       $j('#mw-spinner-wpDestFile').remove();
+                       if(data && data.query && data.query.pages){
+                               if( data.query.pages[-1] ){
+                                       //all good no file there
+                               }else{
+                                       for(var page_id in data.query.pages){
+                                               if( data.query.normalized){
+                                                       var ntitle = data.query.normalized[0].to;
+                                               }else{
+                                                       var ntitle = data.query.pages[ page_id ].title;
+                                               }       
+                                               var img = data.query.pages[ page_id ].imageinfo[0];                                                             
+                                               $j('#wpDestFile-warning').html(
+                                                       '<ul>' +
+                                                               '<li>'+
+                                                                       gM('fileexists', ntitle) + 
+                                                               '</li>'+
+                                                               '<div class="thumb tright">' +
+                                                                       '<div style="width: ' + ( parseInt(img.thumbwidth)+2 ) + 'px;" class="thumbinner">' +
+                                                                               '<a title="' + ntitle + '" class="image" href="' + img.descriptionurl + '">' +
+                                                                                       '<img width="' + img.thumbwidth + '" height="' + img.thumbheight + '" border="0" class="thumbimage" ' +
+                                                                                       'src="' + img.thumburl + '"' +
+                                                                                       '        alt="' + ntitle + '"/>' +
+                                                                               '</a>' +
+                                                                               '<div class="thumbcaption">' +
+                                                                                       '<div class="magnify">' +
+                                                                                               '<a title="' + gM('thumbnail-more') + '" class="internal" ' +
+                                                                                                       'href="' + img.descriptionurl +'"><img width="15" height="11" alt="" ' +
+                                                                                                       'src="' + stylepath +"/>" +
+                                                                                               '</a>'+
+                                                                                       '</div>'+
+                                                                                       gM('fileexists-thumb') +
+                                                                               '</div>' +
+                                                                       '</div>'+
+                                                               '</div>' +
+                                                       '</ul>'
+                                               );
+                                       }
+                               }
+                       }
+               });                     
+       },
+       /**
+        * doDestinationFill fills in a destination file-name based on a source asset name. 
+        * @@todo we should be able to configure its "targets" via parent config
+        */
+       doDestinationFill:function( targetElm ){
+               js_log("doDestinationFill")
+               //remove any previously flagged errors
+               $j('#mw-upload-permitted,#mw-upload-prohibited').hide();                                        
+               
+               var path = $j(targetElm).val();
+               // Find trailing part
+               var slash = path.lastIndexOf('/');
+               var backslash = path.lastIndexOf('\\');
+               var fname;
+               if (slash == -1 && backslash == -1) {
+                       fname = path;
+               } else if (slash > backslash) {
+                       fname = path.substring(slash+1, 10000);
+               } else {
+                       fname = path.substring(backslash+1, 10000);
+               }               
+               //urls are less likely to have a usefull extension don't include them in the extention check
+               if( wgFileExtensions && $j(targetElm).attr('id') != 'wpUploadFileURL' ){                
+                       var found = false;              
+                       if( fname.lastIndexOf('.')!=-1 ){               
+                               var ext = fname.substr( fname.lastIndexOf('.')+1 );                     
+                               for(var i=0; i < wgFileExtensions.length; i++){                                         
+                                       if(  wgFileExtensions[i].toLowerCase()   ==  ext.toLowerCase() )
+                                               found = true;
+                               }
+                       }
+                       if(!found){
+                               //clear the upload set mw-upload-permitted to error
+                               $j(targetElm).val('');
+                               $j('#mw-upload-permitted,#mw-upload-prohibited').show().addClass('error');                                                                                              
+                               //clear the wpDestFile as well: 
+                               $j('#wpDestFile').val('');                                                              
+                               return false;
+                       }               
+               }                               
+               // Capitalise first letter and replace spaces by underscores
+               fname = fname.charAt(0).toUpperCase().concat(fname.substring(1,10000)).replace(/ /g, '_');      
+               // Output result
+               $j('#wpDestFile').val( fname );
+                               
+               //do a destination check 
+               this.doDestCheck();
+       }
+}
+       
index b2c6350..1cde043 100644 (file)
@@ -889,7 +889,7 @@ See [[Special:Version|version page]].',
 'newmessageslink'              => 'new messages',
 'newmessagesdifflink'          => 'last change',
 'youhavenewmessagesmulti'      => 'You have new messages on $1',
-'newtalkseparator'             => ',&#32;', # do not translate or duplicate this message to other languages
+'newtalkseparator'             => ',_', # do not translate or duplicate this message to other languages
 'editsection'                  => 'edit',
 'editsection-brackets'         => '[$1]', # only translate this message to other languages if you have to change it
 'editold'                      => 'edit',
@@ -970,6 +970,7 @@ Please report this to an [[Special:ListUsers/sysop|administrator]], making note
 'readonly_lag'         => 'The database has been automatically locked while the slave database servers catch up to the master',
 'internalerror'        => 'Internal error',
 'internalerror_info'   => 'Internal error: $1',
+'fileappenderror'      => 'Could not append $1 to $2',
 'filecopyerror'        => 'Could not copy file "$1" to "$2".',
 'filerenameerror'      => 'Could not rename file "$1" to "$2".',
 'filedeleteerror'      => 'Could not delete file "$1".',
@@ -1159,6 +1160,7 @@ You may have already successfully changed your password or requested a new tempo
 'media_tip'       => 'File link',
 'sig_tip'         => 'Your signature with timestamp',
 'hr_tip'          => 'Horizontal line (use sparingly)',
+'add_media_wizard' => 'Add media wizard',
 
 # Edit pages
 'summary'                          => 'Summary:',
@@ -2005,6 +2007,7 @@ To include a file in a page, use a link in one of the following forms:
 'uploadlogpage'               => 'Upload log',
 'uploadlogpagetext'           => 'Below is a list of the most recent file uploads.
 See the [[Special:NewFiles|gallery of new files]] for a more visual overview.',
+
 'filename'                    => 'Filename',
 'filedesc'                    => 'Summary',
 'fileuploadsummary'           => 'Summary:',
@@ -2102,6 +2105,11 @@ Please contact an [[Special:ListUsers/sysop|administrator]].',
 'upload-misc-error-text'  => 'An unknown error occurred during the upload.
 Please verify that the URL is valid and accessible and try again.
 If the problem persists, contact an [[Special:ListUsers/sysop|administrator]].',
+'upload-too-many-redirects' => 'The URL contained too many redirects',
+'upload-unknown-size'       => 'Unknown size',
+
+// Idealy we map out all the http errors and translations else just call this with the http resposne:
+'upload-http-error' => "An HTTP error occured: $1",
 
 # Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
 'upload-curl-error6'       => 'Could not reach URL',
@@ -2380,7 +2388,7 @@ It now redirects to [[$2]].',
 
 # Magic words
 'rfcurl'    => 'http://tools.ietf.org/html/rfc$1', # do not translate or duplicate this message to other languages
-'pubmedurl' => 'http://www.ncbi.nlm.nih.gov/pubmed/$1?dopt=Abstract', # do not translate or duplicate this message to other languages
+'pubmedurl' => 'http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=$1', # do not translate or duplicate this message to other languages
 
 # Special:Log
 'specialloguserlabel'  => 'User:',
index 63efd84..c54852a 100644 (file)
@@ -640,9 +640,9 @@ $2',
 'permissionserrorstext'            => '子權未逮,有{{PLURAL:$1|因|因}}如下:',
 'permissionserrorstext-withaction' => '子權未逮,有{{PLURAL:$1|因|因}}如$2:',
 'recreate-moveddeleted-warn'       => "'''留意:刪文復造,惠慎纂。'''
-誌刪如下:",
+誌刪如下:",
 'moveddeleted-notice'              => '此頁刪矣。
-æ­¤é \81ä¹\8bèª\8cå\88ªé\81·å\8f\83ç\95\99ä¹\8bã\80\82',
+此頁之誌參留之。',
 'log-fulllog'                      => '閱誌全',
 'edit-hook-aborted'                => '鈎纂消矣。
 無解也。',
@@ -897,7 +897,7 @@ $1",
 'searchmenu-prefix'                => '[[Special:PrefixIndex/$1|查此首之頁]]',
 'searchprofile-articles'           => '容',
 'searchprofile-project'            => '助題',
-'searchprofile-images'             => '',
+'searchprofile-images'             => '',
 'searchprofile-everything'         => '全',
 'searchprofile-advanced'           => '進',
 'searchprofile-articles-tooltip'   => '在$1中尋',
@@ -1328,7 +1328,7 @@ $1",
 'nolinkstoimage'            => '無頁連本檔也。',
 'morelinkstoimage'          => '閱檔[[Special:WhatLinksHere/$1|接]]。',
 'redirectstofile'           => '下檔轉到此檔有$1:',
-'duplicatesoffile'          => 'ä¸\8bæª\94é\87\8dæ­¤æª\94æ\9c\89$1ï¼\88[[Special:FileDuplicateSearch/$2|詳]]ï¼\89ï¼\9a',
+'duplicatesoffile'          => '下檔重此檔有$1:',
 'sharedupload'              => '此檔為$1之共傳,可另項用也。',
 'sharedupload-desc-there'   => '此檔為$1之共傳,可另項用也。
 詳閱[$2 檔述]。',
@@ -1520,7 +1520,7 @@ $1",
 
 # Special:Categories
 'categories'                    => '類',
-'categoriespagetext'            => '大典{{PLURAL:$1|類中}}有頁或媒。
+'categoriespagetext'            => '大典有頁或媒。
 [[Special:UnusedCategories|未類]]無示之。
 閱[[Special:WantedCategories|需類]]也。',
 'categoriesfrom'                => '示此項起之類:',
@@ -1728,7 +1728,7 @@ $NEWPAGE
 'protect-locked-dblock'       => "庫鎖,'''$1'''緘昔如下:",
 'protect-locked-access'       => "未准,'''$1'''緘昔如下:",
 'protect-cascadeon'           => '取佐緘焉,迭牽此頁;{{PLURAL:$1|此|此}}頁啟篋,無反累焉。',
-'protect-default'             => '允全簿',
+'protect-default'             => '(慣)',
 'protect-fallback'            => "須''$1''准",
 'protect-level-autoconfirmed' => '禁無簿',
 'protect-level-sysop'         => '惟有秩',
@@ -2284,7 +2284,7 @@ $1已被禁矣。爾是否改此置?',
 
 # Media information
 'mediawarning'         => "'''警'''日:此檔疑惡,行之恐諜也。<hr />",
-'imagemaxsize'         => "述檔頁惟列:<br />''(用於檔)''",
+'imagemaxsize'         => '述檔頁惟列:',
 'thumbsize'            => '縮圖幅',
 'widthheight'          => '$1矩$2',
 'widthheightpage'      => '$1矩$2,共$3頁',
index 08c3d4a..488960c 100644 (file)
@@ -11,8 +11,6 @@
  * @author Hanberke
  * @author Runningfridgesrule
  */
-$linkTrail = '/^([a-zÄäÇçĞğŇňÖöŞşÜüÝýŽž]+)(.*)$/sDu';
 
 $messages = array(
 # User preference toggles
index 9756b9f..b3b8bc9 100644 (file)
@@ -709,7 +709,7 @@ MySQL 嘅錯誤回應 "$3: $4"',
 'clearyourcache'                   => "'''注意 - 喺儲存之後,你可能要先略過你嘅瀏覽器快取去睇到更改。'''
 '''Mozilla / Firefox / Safari:''' 㩒住''Shift''掣再撳''重新載入'',又或者㩒''Ctrl-F5''或者''Ctrl-R''(喺Macintosh㩒''Command-R''掣);
 '''Konqueror:''' 就咁以撳個''重載''掣,又或者㩒''F5'';
-'''Opera:'''å\96º''å·¥å\85·â\86\92å\96\9c好設å®\9a''ä¹\8b中æ¸\85ä½¢å\93\8bå\98\85å¿«å\8f\96ï¼\8cå\8f\88æ\88\96è\80\85ã©\92''Alt-F5''ï¼\9b
+'''Opera:'''喺''工具→喜好設定''之中清佢哋嘅快取;
 '''Internet Explorer:''' 㩒住''Ctrl''掣再撳''重新整理'',又或者㩒''Ctrl-F5''掣。",
 'usercssjsyoucanpreview'           => "'''提示:'''響儲存前,用「顯示預覽」個掣嚟測試你嘅新CSS/JS。",
 'usercsspreview'                   => "'''請注意你而家只係預覽緊你嘅用戶CSS樣式表。'''
@@ -1736,7 +1736,7 @@ Template:搞清楚',
 
 # Special:Categories
 'categories'                    => '類',
-'categoriespagetext'            => '下面嘅{{PLURAL:$1|類}}有版或媒體。
+'categoriespagetext'            => '下面嘅有版或媒體。
 [[Special:UnusedCategories|未用類]]唔會響呢度列示。
 請同時參閱[[Special:WantedCategories|需要嘅分類]]。',
 'categoriesfrom'                => '顯示由呢項起嘅類:',
index f2e5af5..7c91235 100644 (file)
@@ -825,7 +825,7 @@ $2',
 {{GENDER:你|妳|你}}应该要考虑一下继续编辑这一个页面是否合适。
 为方便起见,这一个页面的删除记录已经在下面提供:",
 'moveddeleted-notice'              => '这个页面已经删除。
-这个页面的删除和移动日志已在下面提供以便参考。',
+这个页面的删除日志已在下面提供以便参考。',
 'log-fulllog'                      => '查看完整日志',
 'edit-hook-aborted'                => '编辑被钩取消。
 它并无给出解释。',
@@ -1176,7 +1176,7 @@ $1",
 'stub-threshold'                => '<a href="#" class="stub">短页面链接</a>格式门槛值(字节):',
 'recentchangesdays'             => '最近更改中的显示日数:',
 'recentchangesdays-max'         => '(最大 $1 日)',
-'recentchangescount'            => '默认显示的编辑数:',
+'recentchangescount'            => '最近更改、页面历史及日志页面中的默认编辑数:',
 'prefs-help-recentchangescount' => '这个包括最近更改、页面历史以及日志。',
 'savedprefs'                    => '您的个人参数设置已经保存。',
 'timezonelegend'                => '时区:',
@@ -1782,7 +1782,7 @@ Template:消除歧義',
 
 # Special:Categories
 'categories'                    => '页面分类',
-'categoriespagetext'            => '以下的{{PLURAL:$1|分类}}中包含了页面或媒体。
+'categoriespagetext'            => '以下的分类中包含了页面或媒体。
 [[Special:UnusedCategories|未用分类]]不会在这里列示。
 请同时参阅[[Special:WantedCategories|需要的分类]]。',
 'categoriesfrom'                => '显示由此项起之分类:',
index 6fd0ac4..0b93bd4 100644 (file)
@@ -802,7 +802,7 @@ $2',
 {{GENDER:你|妳|你}}應該要考慮一下繼續編輯這一個頁面是否合適。
 為方便起見,這一個頁面的刪除記錄已經在下面提供:",
 'moveddeleted-notice'              => '這個頁面已經刪除。
-這個頁面的刪除和移動日誌已在下面提供以便參考。',
+這個頁面的刪除日誌已在下面提供以便參考。',
 'log-fulllog'                      => '查看完整日誌',
 'edit-hook-aborted'                => '編輯被鈎取消。
 它並無給出解釋。',
@@ -1153,7 +1153,7 @@ $1",
 'stub-threshold'                => '<a href="#" class="stub">短頁面連結</a>格式門檻值 (位元組):',
 'recentchangesdays'             => '最近更改中的顯示日數:',
 'recentchangesdays-max'         => '(最大 $1 日)',
-'recentchangescount'            => '預設顯示的編輯數:',
+'recentchangescount'            => '最近更改、頁面歷史及日誌頁面中的預設編輯數:',
 'prefs-help-recentchangescount' => '這個包括最近更改、頁面歷史以及日誌。',
 'savedprefs'                    => '您的個人參數設置已經保存。',
 'timezonelegend'                => '時區:',
@@ -1759,7 +1759,7 @@ Template:消除歧義',
 
 # Special:Categories
 'categories'                    => '頁面分類',
-'categoriespagetext'            => '以下的{{PLURAL:$1|分類}}中包含了頁面或媒體。
+'categoriespagetext'            => '以下的分類中包含了頁面或媒體。
 [[Special:UnusedCategories|未用分類]]不會在這裏列示。
 請同時參閱[[Special:WantedCategories|需要的分類]]。',
 'categoriesfrom'                => '顯示由此項起之分類:',
diff --git a/maintenance/http_session_download.php b/maintenance/http_session_download.php
new file mode 100644 (file)
index 0000000..cb56297
--- /dev/null
@@ -0,0 +1,46 @@
+<?php 
+/*
+ * simple entry point to initiate a background download
+ * 
+ * arguments: 
+ * 
+ * -sid {$session_id} -usk {$upload_session_key}
+ */
+
+global $optionsWithArgs;
+$optionsWithArgs = Array('sid', 'usk');
+
+//act like a "normal user"
+$wgUseNormalUser = true;
+
+require_once( 'commandLine.inc' );
+
+if(!isset($options['sid']) || !isset($options['usk'])){
+       print<<<EOT
+       simple entry point to initiate a background download
+       
+       Usage: http_session_download.php [options]
+       Options:
+               --sid the session id (required)
+               --usk the upload session key (also required)  
+EOT;
+
+       exit();
+}
+wfProfileIn('http_session_download.php');
+
+//run the download: 
+Http::doSessionIdDownload( $options['sid'], $options['usk'] );
+
+//close up shop:
+// Execute any deferred updates
+wfDoUpdates();
+                       
+// Log what the user did, for book-keeping purposes.   
+wfLogProfilingData();
+                       
+// Shut down the database before exit
+wfGetLBFactory()->shutdown();
+
+wfProfileOut('http_session_download.php');
+?>
\ No newline at end of file
diff --git a/mwScriptLoader.php b/mwScriptLoader.php
new file mode 100644 (file)
index 0000000..d743b3e
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/*
+ *     mvwScriptLoader.php
+* Script Loading Library for MediaWiki
+*
+* @author Michael Dale mdale@wikimedia.org
+* @date  feb, 2009
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*/
+
+/*
+ * mvwScriptLoader:
+ *
+ * some documentation about script-loader:
+ * http://www.mediawiki.org/wiki/ScriptLoader
+ */
+
+//include WebStart.php
+require_once('includes/WebStart.php');
+
+wfProfileIn('mvwScriptLoader.php');
+
+if( isset( $_SERVER['SCRIPT_URL'] ) ) {
+       $url = $_SERVER['SCRIPT_URL'];
+} else {
+       $url = $_SERVER['PHP_SELF'];
+}
+
+if( strpos($url, "mwScriptLoader$wgScriptExtension") === false){
+       wfHttpError( 403, 'Forbidden',
+               'mvwScriptLoader must be accessed through the primary script entry point.' );
+       return ;
+}
+//Verify the script loader is on:
+if (!$wgEnableScriptLoader) {
+       echo '/*ScriptLoader is not enabled for this site. To enable add the following line to your LocalSettings.php';
+       echo '<pre><b>$wgEnableScriptLoader=true;</b></pre>*/';
+       echo 'alert(\'Script loader is disabled\');';
+       die(1);
+}
+
+//load the mwEmbed language file:
+$wgExtensionMessagesFiles['mwEmbed'] = "{$IP}/js2/mwEmbed/php/languages/mwEmbed.i18n.php";
+//enable the msgs before we go on:
+wfLoadExtensionMessages( 'mwEmbed' );
+
+//run jsScriptLoader action:
+$myScriptLoader = new jsScriptLoader();
+$myScriptLoader->doScriptLoader();
+
+wfProfileOut();
+?>
\ No newline at end of file
index 5c66be4..0bca15c 100644 (file)
@@ -26,8 +26,7 @@ class SkinMonoBook extends SkinTemplate {
                $this->stylename = 'monobook';
                $this->template  = 'MonoBookTemplate';
 
-       }
-
+       }       
        function setupSkinUserCss( OutputPage $out ) {
                global $wgHandheldStyle;
 
@@ -45,7 +44,30 @@ class SkinMonoBook extends SkinTemplate {
                $out->addStyle( 'monobook/IE60Fixes.css', 'screen', 'IE 6' );
                $out->addStyle( 'monobook/IE70Fixes.css', 'screen', 'IE 7' );
 
-               $out->addStyle( 'monobook/rtl.css', 'screen', '', 'rtl' );
+               $out->addStyle( 'monobook/rtl.css', 'screen', '', 'rtl' );              
+               
+               
+               //@@todo we can move this to the parent once we update all skins 
+               if( $this->pagecss )
+                       $out->addInlineStyle( $this->pagecss );         
+               
+               if(  $this->usercss )
+                       $out->addInlineStyle( $this->usercss );
+                               
+       }
+       function setupSkinUserJs( OutputPage $out ) {   
+               parent::setupSkinUserJs( $out );                
+               $out->addScriptFile( 'wikibits.js' );
+               
+               //@@todo can move to parent once we update all skins (to not include things twice               
+               if( $this->jsvarurl )
+                       $out->addScriptFile( $this->jsvarurl );         
+                       
+               if( $this->userjs )             
+                       $out->addScriptFile( $this->userjs );
+               
+               if( $this->userjsprev )
+                       $out->addInlineScript( $this->userjsprev );
        }
 }
 
@@ -72,7 +94,6 @@ class MonoBookTemplate extends QuickTemplate {
                wfSuppressWarnings();
 
                $path = htmlspecialchars( $wgStylePath );
-               # FIXME: What is this?  Should it apply to all skins?
                $wgOut->addScript( <<<HTML
 <!--[if lt IE 7]><script type="$wgJsMimeType" src="$path/common/IEFixes.js?$wgStyleVersion"></script>
        <meta http-equiv="imagetoolbar" content="no" /><![endif]-->
index 5845dcc..57c9864 100644 (file)
@@ -19,18 +19,17 @@ class SkinStandard extends Skin {
         *
         */
        function getHeadScripts( $allowUserJs, $extraHtml = '' ) {
-               global $wgStylePath, $wgJsMimeType, $wgStyleVersion;
+               global $wgStylePath, $wgJsMimeType, $wgStyleVersion, $wgOut;
 
                $s = parent::getHeadScripts( $allowUserJs, $extraHtml );
-               if ( 3 == $this->qbSetting() ) { # Floating left
-                       $s .= "<script language='javascript' type='$wgJsMimeType' " .
-                         "src='{$wgStylePath}/common/sticky.js?$wgStyleVersion'></script>\n";
+               if ( 3 == $this->qbSetting() ) { # Floating left                        
+                       $wgOut->addScriptFile ( "{$wgStylePath}/common/sticky.js" );
                }
                return $s;
        }
 
        /**
-        *
+        * 
         */
        function setupSkinUserCss( OutputPage $out ){
                if ( 3 == $this->qbSetting() ) { # Floating left
index d1cf4b3..d4cff53 100644 (file)
@@ -11,7 +11,17 @@ function licenseSelectorCheck() {
        wgUploadLicenseObj.fetchPreview( selection );
 }
 
-function licenseSelectorFixup() {
+function wgUploadSetup() {
+       //disable source type if not checked: 
+       var e = document.getElementById('wpSourceTypeURL');
+       if(e){
+               if(!e.checked){
+                       var ein = document.getElementById('wpUploadFileURL');
+                       if(ein)
+                               ein.setAttribute('disabled', 'disabled');
+               }
+       }
+       
        // for MSIE/Mac; non-breaking spaces cause the <option> not to render
        // but, for some reason, setting the text to itself works
        var selector = document.getElementById("wpLicense");
@@ -75,9 +85,9 @@ var wgUploadWarningObj = {
                // anonymous callback. fileName is copied so that multiple overlapping 
                // ajax requests can be supported.
                var obj = this;
-               var fileName = this.nameToCheck;
+               var fileName = this.nameToCheck;                
                sajax_do_call( 'UploadForm::ajaxGetExistsWarning', [this.nameToCheck], 
-                       function (result) {
+                       function (result) {                             
                                obj.processResult(result, fileName)
                        }
                );
@@ -102,7 +112,6 @@ var wgUploadWarningObj = {
                        ackElt.value = '1';
                }
        },
-
        'setInnerHTML' : function (element, text) {
                // Check for no change to avoid flicker in IE 7
                if (element.innerHTML != text) {
@@ -118,6 +127,13 @@ function fillDestFilename(id) {
        if (!document.getElementById) {
                return;
        }
+       //remove any previously flagged errors
+       var e = document.getElementById('mw-upload-permitted');
+       if(e) e. className = '';
+       
+       var e = document.getElementById('mw-upload-prohibited');
+       if(e) e.className = '';
+       
        var path = document.getElementById(id).value;
        // Find trailing part
        var slash = path.lastIndexOf('/');
@@ -130,7 +146,36 @@ function fillDestFilename(id) {
        } else {
                fname = path.substring(backslash+1, 10000);
        }
-
+       //check for the wgFileExtensions and clear if not a valid fname extension
+       
+       //urls are less likely to have a usefull extension don't include them in the extention check
+       if( wgFileExtensions && id != 'wpUploadFileURL' ){              
+               var found = false;              
+               if( fname.lastIndexOf('.')!=-1 ){               
+                       var ext = fname.substr( fname.lastIndexOf('.')+1 );                     
+                       for(var i=0; i < wgFileExtensions.length; i++){                                         
+                               if(  wgFileExtensions[i].toLowerCase()   ==  ext.toLowerCase() )
+                                       found = true;
+                       }
+               }
+               if(!found){
+                       //clear the upload set mw-upload-permitted to error
+                       document.getElementById(id).value = '';
+                       var e = document.getElementById('mw-upload-permitted');
+                       if(e) e. className = 'error';
+                       
+                       var e = document.getElementById('mw-upload-prohibited');
+                       if(e) e.className = 'error';
+                       
+                       //clear the wpDestFile as well: 
+                       var e = document.getElementById('wpDestFile')
+                       if(e) e.value = '';
+                       
+                       //return false
+                       return false;
+               }               
+       }       
+               
        // Capitalise first letter and replace spaces by underscores
        fname = fname.charAt(0).toUpperCase().concat(fname.substring(1,10000)).replace(/ /g, '_');
 
@@ -187,4 +232,4 @@ var wgUploadLicenseObj = {
        
 }
 
-addOnloadHook( licenseSelectorFixup );
\ No newline at end of file
+addOnloadHook( wgUploadSetup );
\ No newline at end of file
index 03a7b03..b23ffd1 100644 (file)
@@ -10,9 +10,11 @@ if (webkit_match) {
        var is_safari_win = is_safari && clientPC.indexOf('windows') != -1;
        var webkit_version = parseInt(webkit_match[1]);
 }
+var is_khtml = navigator.vendor == 'KDE' ||
+       ( document.childNodes && !document.all && !navigator.taintEnabled );
 // For accesskeys; note that FF3+ is included here!
 var is_ff2 = /firefox\/[2-9]|minefield\/3/.test( clientPC );
-var ff2_bugs = /firefox\/2/.test( clientPC );
+var is_ff2_ = /firefox\/2/.test( clientPC );
 // These aren't used here, but some custom scripts rely on them
 var is_ff2_win = is_ff2 && clientPC.indexOf('windows') != -1;
 var is_ff2_x11 = is_ff2 && clientPC.indexOf('x11') != -1;
@@ -20,10 +22,7 @@ if (clientPC.indexOf('opera') != -1) {
        var is_opera = true;
        var is_opera_preseven = window.opera && !document.childNodes;
        var is_opera_seven = window.opera && document.childNodes;
-       var is_opera_95 = /opera\/(9\.[5-9]|[1-9][0-9])/.test( clientPC );
-       var opera6_bugs = is_opera_preseven;
-       var opera7_bugs = is_opera_seven && !is_opera_95;
-       var opera95_bugs = /opera\/(9\.5)/.test( clientPC );
+       var is_opera_95 = /opera\/(9.[5-9]|[1-9][0-9])/.test( clientPC );
 }
 
 // Global external objects used by this script.
@@ -34,9 +33,10 @@ var doneOnloadHook;
 
 if (!window.onloadFuncts) {
        var onloadFuncts = [];
-}
-
-function addOnloadHook(hookFunct) {
+}      
+       
+//should use mwAddOnloadHook once js2 is enabled
+function addOnloadHook(hookFunct) {    
        // Allows add-on scripts to add onload functions
        if(!doneOnloadHook) {
                onloadFuncts[onloadFuncts.length] = hookFunct;
@@ -96,15 +96,15 @@ function appendCSS(text) {
 
 // special stylesheet links
 if (typeof stylepath != 'undefined' && typeof skin != 'undefined') {
-       // FIXME: This tries to load the stylesheets even for skins where they
-       // don't exist, i.e., everything but Monobook.
-       if (opera6_bugs) {
+       if (is_opera_preseven) {
                importStylesheetURI(stylepath+'/'+skin+'/Opera6Fixes.css');
-       } else if (opera7_bugs) {
+       } else if (is_opera_seven && !is_opera_95) {
                importStylesheetURI(stylepath+'/'+skin+'/Opera7Fixes.css');
-       } else if (opera95_bugs) {
+       } else if (is_opera_95) {
                importStylesheetURI(stylepath+'/'+skin+'/Opera9Fixes.css');
-       } else if (ff2_bugs) {
+       } else if (is_khtml) {
+               importStylesheetURI(stylepath+'/'+skin+'/KHTMLFixes.css');
+       } else if (is_ff2_) {
                importStylesheetURI(stylepath+'/'+skin+'/FF2Fixes.css');
        }
 }
@@ -452,8 +452,23 @@ function toggle_element_activation(ida,idb) {
        if (!document.getElementById) {
                return;
        }
-       document.getElementById(ida).disabled=true;
-       document.getElementById(idb).disabled=false;
+       //hide and show appropriate upload sizes
+       if(idb == 'wpUploadFileURL'){
+               var e = document.getElementById('mw-upload-maxfilesize');
+               if(e) e.style.display = "none";         
+               
+               var e = document.getElementById('mw-upload-maxfilesize-url');
+               if(e) e.style.display = "block";                
+       }
+       if(idb == 'wpUploadFile'){
+               var e = document.getElementById('mw-upload-maxfilesize-url');
+               if(e) e.style.display =  "none";
+                                       
+               var e = document.getElementById('mw-upload-maxfilesize');
+               if(e) e.style.display =  "block";
+       }
+       document.getElementById(ida).disabled = true;
+       document.getElementById(idb).disabled = false;
 }
 
 function toggle_element_check(ida,idb) {
diff --git a/skins/monobook/KHTMLFixes.css b/skins/monobook/KHTMLFixes.css
new file mode 100644 (file)
index 0000000..afa3568
--- /dev/null
@@ -0,0 +1,4 @@
+/* KHTML fix stylesheet */
+/* work around the horizontal scrollbars */
+#column-content { margin-left: 0; }
+